new multifile format for upcoming support of direct loading from multifiles

This commit is contained in:
David Rose 2002-08-02 20:59:23 +00:00
parent 2919377449
commit b1dc8b2fa6
25 changed files with 1889 additions and 3043 deletions

View File

@ -1,347 +0,0 @@
// Filename: asyncDecompressor.cxx
// Created by: mike (09Jan97)
//
////////////////////////////////////////////////////////////////////
//
// 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 .
//
////////////////////////////////////////////////////////////////////
// This file is compiled only if we have zlib installed.
////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////
#include "config_downloader.h"
#include <event.h>
#include <pt_Event.h>
#include <throw_event.h>
#include <eventParameter.h>
#include <filename.h>
#include <stdio.h>
#include "asyncDecompressor.h"
////////////////////////////////////////////////////////////////////
// Defines
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Class : DecompressorToken
// Description : Holds a request for the decompressor.
////////////////////////////////////////////////////////////////////
class DecompressorToken : public ReferenceCount {
public:
INLINE DecompressorToken(uint id, const Filename &source_file,
const Filename &dest_file, const string &event_name) {
_id = id;
_source_file = source_file;
_dest_file = dest_file;
_event_name = event_name;
}
int _id;
Filename _source_file;
Filename _dest_file;
string _event_name;
};
////////////////////////////////////////////////////////////////////
// Function: Decompressor::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
Decompressor::
Decompressor(void) : AsyncUtility() {
PT(Buffer) buffer = new Buffer(decompressor_buffer_size);
init(buffer);
}
////////////////////////////////////////////////////////////////////
// Function: Decompressor::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
Decompressor::
Decompressor(PT(Buffer) buffer) : AsyncUtility() {
init(buffer);
}
////////////////////////////////////////////////////////////////////
// Function: Decompressor::Constructor
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
void Decompressor::
init(PT(Buffer) buffer) {
nassertv(!buffer.is_null());
_frequency = decompressor_frequency;
_token_board = new DecompressorTokenBoard;
_half_buffer_length = buffer->get_length()/2;
_buffer = buffer;
char *temp_name = tempnam(NULL, "dc");
_temp_file_name = temp_name;
_temp_file_name.set_binary();
delete temp_name;
}
////////////////////////////////////////////////////////////////////
// Function: Decompressor::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
Decompressor::
~Decompressor(void) {
destroy_thread();
delete _token_board;
_temp_file_name.unlink();
}
////////////////////////////////////////////////////////////////////
// Function: Decompressor::request_decompress
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
int Decompressor::
request_decompress(const Filename &source_file, const string &event_name) {
Filename dest_file = source_file;
string extension = source_file.get_extension();
if (extension == "pz")
dest_file = source_file.get_fullpath_wo_extension();
else {
if (downloader_cat.is_debug())
downloader_cat.debug()
<< "Decompressor::request_decompress() - Unknown file extension: ."
<< extension << endl;
}
return request_decompress(source_file, dest_file, event_name);
}
////////////////////////////////////////////////////////////////////
// Function: Decompressor::request_decompress
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
int Decompressor::
request_decompress(const Filename &source_file, const Filename &dest_file,
const string &event_name) {
PT(DecompressorToken) tok;
if (_threads_enabled) {
// Make sure we actually are threaded
if (!_threaded) {
downloader_cat.info()
<< "Decompressor::request_decompress() - create_thread() was "
<< "never called! Calling it now..." << endl;
create_thread();
}
// We need to grab the lock in order to signal the condition variable
#ifdef HAVE_IPC
_lock.lock();
#endif
if (_token_board->_waiting.is_full()) {
downloader_cat.error()
<< "Downloader::request_download() - Too many pending requests\n";
return 0;
}
if (downloader_cat.is_debug()) {
downloader_cat.debug()
<< "Decompress requested for file: " << source_file << endl;
}
tok = new DecompressorToken(_next_token++, source_file, dest_file,
event_name);
_token_board->_waiting.insert(tok);
#ifdef HAVE_IPC
_request_cond->signal();
_lock.unlock();
#endif
} else {
// If we're not running asynchronously, process the load request
// directly now.
if (_token_board->_waiting.is_full()) {
downloader_cat.error()
<< "Downloader::request_download() - Too many pending requests\n";
return 0;
}
if (downloader_cat.is_debug()) {
downloader_cat.debug()
<< "Decompress requested for file: " << source_file << endl;
}
tok = new DecompressorToken(_next_token++, source_file, dest_file,
event_name);
_token_board->_waiting.insert(tok);
process_request();
}
return tok->_id;
}
////////////////////////////////////////////////////////////////////
// Function: Decompressor::process_request
// Access: Private
// Description: Serves any requests on the token board, moving them
// to the done queue.
////////////////////////////////////////////////////////////////////
bool Decompressor::
process_request() {
if (_shutdown) {
if (downloader_cat.is_debug())
downloader_cat.debug()
<< "Decompressor shutting down...\n";
return false;
}
// If there is actually a request token - process it
while (!_token_board->_waiting.is_empty()) {
PT(DecompressorToken) tok = _token_board->_waiting.extract();
if (decompress(tok->_source_file, tok->_dest_file)) {
_token_board->_done.insert(tok);
// Throw a "done" event now.
if (!tok->_event_name.empty()) {
PT_Event done = new Event(tok->_event_name);
done->add_parameter(EventParameter((int)tok->_id));
throw_event(done);
}
if (downloader_cat.is_debug()) {
downloader_cat.debug()
<< "Decompressor::process_request() - decompress complete for "
<< tok->_source_file << "\n";
}
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: Decompressor::decompress
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
bool Decompressor::
decompress(Filename &source_file) {
Filename dest_file = source_file;
string extension = source_file.get_extension();
if (extension == "pz")
dest_file = source_file.get_fullpath_wo_extension();
else {
if (downloader_cat.is_debug())
downloader_cat.debug()
<< "Decompressor::request_decompress() - Unknown file extension: ."
<< extension << endl;
return false;
}
return decompress(source_file, dest_file);
}
////////////////////////////////////////////////////////////////////
// Function: Decompressor::decompress
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
bool Decompressor::
decompress(Filename &source_file, Filename &dest_file) {
// Open source file
ifstream read_stream;
source_file.set_binary();
if (!source_file.open_read(read_stream)) {
downloader_cat.error()
<< "Decompressor::decompress() - Error opening source file: "
<< source_file << endl;
return false;
}
// Determine source file length
read_stream.seekg(0, ios::end);
int source_file_length = read_stream.tellg();
if (source_file_length == 0) {
downloader_cat.warning()
<< "Decompressor::decompress() - Zero length file: "
<< source_file << endl;
return true;
}
read_stream.seekg(0, ios::beg);
// Open destination file
ofstream write_stream;
dest_file.set_binary();
if (!dest_file.open_write(write_stream)) {
downloader_cat.error()
<< "Decompressor::decompress() - Error opening dest file: "
<< source_file << endl;
return false;
}
// Read from the source file into the first half of the buffer,
// decompress into the second half of the buffer, write the second
// half of the buffer to disk, and repeat.
int total_bytes_read = 0;
bool read_all_input = false;
bool handled_all_input = false;
int source_buffer_length;
ZDecompressor decompressor;
while (handled_all_input == false) {
// See if there is anything left in the source file
if (read_all_input == false) {
read_stream.read(_buffer->_buffer, _half_buffer_length);
source_buffer_length = read_stream.gcount();
total_bytes_read += source_buffer_length;
if (read_stream.eof()) {
nassertr(total_bytes_read == source_file_length, false);
read_all_input = true;
}
}
char *next_in = _buffer->_buffer;
int avail_in = source_buffer_length;
char *dest_buffer = _buffer->_buffer + source_buffer_length;
char *next_out = dest_buffer;
int dest_buffer_length = _buffer->get_length() - source_buffer_length;
int avail_out = dest_buffer_length;
nassertr(avail_out > 0 && avail_in > 0, false);
while (avail_in > 0) {
int ret = decompressor.decompress_to_stream(next_in, avail_in,
next_out, avail_out, dest_buffer,
dest_buffer_length, write_stream);
if (ret == ZCompressorBase::S_error)
return false;
if ((int)decompressor.get_total_in() == source_file_length &&
avail_out == dest_buffer_length)
handled_all_input = true;
}
nap();
}
read_stream.close();
write_stream.close();
source_file.unlink();
return true;
}

View File

@ -1,64 +0,0 @@
// Filename: asyncDecompressor.h
// Created by: mike (09Jan97)
//
////////////////////////////////////////////////////////////////////
//
// 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 ASYNCDECOMPRESSOR_H
#define ASYNCDECOMPRESSOR_H
//
////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////
#include <pandabase.h>
#include <filename.h>
#include <tokenBoard.h>
#include <buffer.h>
#include "zcompressor.h"
#include "asyncUtility.h"
class DecompressorToken;
////////////////////////////////////////////////////////////////////
// Class : Decompressor
// Description :
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS Decompressor : public AsyncUtility {
PUBLISHED:
Decompressor(void);
Decompressor(PT(Buffer) buffer);
virtual ~Decompressor(void);
int request_decompress(const Filename &source_file,
const string &event_name);
int request_decompress(const Filename &source_file,
const Filename &dest_file,
const string &event_name);
bool decompress(Filename &source_file);
bool decompress(Filename &source_file, Filename &dest_file);
private:
void init(PT(Buffer) buffer);
virtual bool process_request(void);
typedef TokenBoard<DecompressorToken> DecompressorTokenBoard;
DecompressorTokenBoard *_token_board;
PT(Buffer) _buffer;
int _half_buffer_length;
Filename _temp_file_name;
};
#endif

View File

@ -1,110 +0,0 @@
// Filename: asyncDownloader.I
// Created by: mike (09Jan97)
//
////////////////////////////////////////////////////////////////////
//
// 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 "config_downloader.h"
////////////////////////////////////////////////////////////////////
// Function: Downloader::set_byte_rate
// Access: Public
// Description: Note: modem speeds are reported in bits, so you
// need to convert!
////////////////////////////////////////////////////////////////////
INLINE void Downloader::
set_byte_rate(float bytes) {
nassertv(bytes > 0.0);
if (bytes == _byte_rate)
return;
#ifdef HAVE_IPC
_buffer_lock.lock();
#endif
_new_byte_rate = bytes;
#ifdef HAVE_IPC
_buffer_lock.unlock();
#endif
}
////////////////////////////////////////////////////////////////////
// Function: Downloader::get_byte_rate
// Access: Public
// Description: Returns byte rate in bytes.
////////////////////////////////////////////////////////////////////
INLINE float Downloader::
get_byte_rate(void) const {
return _byte_rate;
}
////////////////////////////////////////////////////////////////////
// Function: Downloader::enable_download
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void Downloader::
enable_download(bool val) {
_download_enabled = val;
}
////////////////////////////////////////////////////////////////////
// Function: Downloader::is_download_enabled
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool Downloader::
is_download_enabled(void) const {
return _download_enabled;
}
////////////////////////////////////////////////////////////////////
// Function: Downloader::set_disk_write_frequency
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void Downloader::
set_disk_write_frequency(int frequency) {
nassertv(frequency > 0);
#ifdef HAVE_IPC
_buffer_lock.lock();
#endif
_new_disk_write_frequency = frequency;
#ifdef HAVE_IPC
_buffer_lock.unlock();
#endif
}
////////////////////////////////////////////////////////////////////
// Function: Downloader::get_disk_write_frequency
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE int Downloader::
get_disk_write_frequency(void) const {
return _disk_write_frequency;
}
////////////////////////////////////////////////////////////////////
// Function: Downloader::get_last_attempt_stalled
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool Downloader::
get_last_attempt_stalled(void) const {
return _last_attempt_stalled;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,150 +0,0 @@
// Filename: asyncDownloader.h
// Created by: mike (09Jan97)
//
////////////////////////////////////////////////////////////////////
//
// 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 ASYNCDOWNLOADER_H
#define ASYNCDOWNLOADER_H
//
////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////
#include <pandabase.h>
#include <notify.h>
#include <filename.h>
#include <tokenBoard.h>
#include <buffer.h>
#include "asyncUtility.h"
#if defined(WIN32_VC)
#include <winsock.h>
#else
#include <netinet/in.h> // Irix seems to require this one for resolv.h.
#include <sys/types.h>
#include <sys/socket.h>
#include <resolv.h>
#endif
class DownloaderToken;
////////////////////////////////////////////////////////////////////
// Class : Downloader
// Description :
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS Downloader : public AsyncUtility {
PUBLISHED:
enum DownloadCode {
DS_write = 2,
DS_success = 1,
DS_abort = -1,
DS_timeout = -2
};
Downloader(void);
//Downloader(PT(Buffer) buffer);
virtual ~Downloader(void);
bool connect_to_server(const string &name, uint port=80);
void disconnect_from_server(void);
int request_sync_download(const string &file_name, const Filename &file_dest,
const string &event_name);
int request_sync_download(const string &file_name, const Filename &file_dest,
const string &event_name, int first_byte,
int last_byte, int total_bytes,
bool partial_content = true);
int request_download(const string &file_name, const Filename &file_dest,
const string &event_name, bool sync = false);
int request_download(const string &file_name, const Filename &file_dest,
const string &event_name, int first_byte,
int last_byte, int total_bytes,
bool partial_content = true, bool sync = false);
INLINE void set_byte_rate(float bytes);
INLINE float get_byte_rate(void) const;
INLINE void set_disk_write_frequency(int frequency);
INLINE int get_disk_write_frequency(void) const;
INLINE void enable_download(bool val);
INLINE bool is_download_enabled(void) const;
INLINE bool get_last_attempt_stalled(void) const;
private:
class DownloadStatus {
public:
DownloadStatus(char *buffer, const string &event_name, int first_byte,
int last_byte, int total_bytes, bool partial_content,
uint id);
void reset(void);
public:
bool _first_line_complete;
bool _header_is_complete;
bool _header_is_valid;
char *_start;
char *_next_in;
int _bytes_in_buffer;
string _event_name;
int _total_bytes_written;
int _first_byte;
int _last_byte;
int _total_bytes;
bool _partial_content;
uint _id;
char *_buffer;
};
void init();
int download(const string &file_name, Filename file_dest,
const string &event_name, int first_byte,
int last_byte, int total_bytes, bool partial_content,
bool sync, uint id);
virtual bool process_request(void);
bool parse_header(DownloadStatus &status);
bool write_to_disk(DownloadStatus &status);
bool connect_to_server(void);
int safe_send(int socket, const char *data, int length, long timeout);
int safe_receive(int socket, DownloadStatus &status, int length,
long timeout, int &bytes);
bool parse_http_response(const string &resp);
int attempt_read(int length, DownloadStatus &status, int &bytes_read);
typedef TokenBoard<DownloaderToken> DownloaderTokenBoard;
DownloaderTokenBoard *_token_board;
bool _connected;
#ifdef HAVE_IPC
mutex _buffer_lock;
#endif
int _socket;
PT(Buffer) _buffer;
int _disk_write_frequency;
int _new_disk_write_frequency;
float _byte_rate;
float _new_byte_rate;
int _read_size;
bool _download_enabled;
ofstream _dest_stream;
int _disk_buffer_size;
bool _last_attempt_stalled;
bool _current_attempt_stalled;
string _server_name;
struct sockaddr_in _sin;
};
#include "asyncDownloader.I"
#endif

View File

@ -1,262 +0,0 @@
// Filename: asyncExtractor.cxx
// Created by: mike (09Jan97)
//
////////////////////////////////////////////////////////////////////
//
// 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 "config_downloader.h"
#include <event.h>
#include <pt_Event.h>
#include <throw_event.h>
#include <eventParameter.h>
#include <filename.h>
#include "asyncExtractor.h"
////////////////////////////////////////////////////////////////////
// Defines
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Class : ExtractorToken
// Description : Holds a request for the extractor.
////////////////////////////////////////////////////////////////////
class ExtractorToken : public ReferenceCount {
public:
INLINE ExtractorToken(uint id, const Filename &source_file,
const string &event_name,
const Filename &rel_path) {
_id = id;
_source_file = source_file;
_event_name = event_name;
_rel_path = rel_path;
}
int _id;
Filename _source_file;
string _event_name;
Filename _rel_path;
};
////////////////////////////////////////////////////////////////////
// Function: Extractor::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
Extractor::
Extractor(void) : AsyncUtility() {
PT(Buffer) buffer = new Buffer(extractor_buffer_size);
init(buffer);
}
////////////////////////////////////////////////////////////////////
// Function: Extractor::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
Extractor::
Extractor(PT(Buffer) buffer) : AsyncUtility() {
init(buffer);
}
////////////////////////////////////////////////////////////////////
// Function: Extractor::Constructor
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
void Extractor::
init(PT(Buffer) buffer) {
nassertv(!buffer.is_null());
_frequency = extractor_frequency;
_token_board = new ExtractorTokenBoard;
_buffer = buffer;
}
////////////////////////////////////////////////////////////////////
// Function: Extractor::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
Extractor::
~Extractor(void) {
destroy_thread();
delete _token_board;
}
////////////////////////////////////////////////////////////////////
// Function: Extractor::request_extract
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
int Extractor::
request_extract(const Filename &source_file, const string &event_name,
const Filename &rel_path) {
PT(ExtractorToken) tok;
if (_threads_enabled) {
// Make sure we actually are threaded
if (!_threaded) {
downloader_cat.info()
<< "Extractor::request_extract() - create_thread() was "
<< "never called! Calling it now..." << endl;
create_thread();
}
// We need to grab the lock in order to signal the condition variable
#ifdef HAVE_IPC
_lock.lock();
#endif
if (_token_board->_waiting.is_full()) {
downloader_cat.error()
<< "Extractor::request_extract() - Too many pending requests\n";
return 0;
}
if (downloader_cat.is_debug()) {
downloader_cat.debug()
<< "Extract requested for file: " << source_file << endl;
}
tok = new ExtractorToken(_next_token++, source_file, event_name,
rel_path);
_token_board->_waiting.insert(tok);
#ifdef HAVE_IPC
_request_cond->signal();
_lock.unlock();
#endif
} else {
// If we're not running asynchronously, process the load request
// directly now.
if (_token_board->_waiting.is_full()) {
downloader_cat.error()
<< "Extractor::request_extract() - Too many pending requests\n";
return 0;
}
if (downloader_cat.is_debug()) {
downloader_cat.debug()
<< "Extract requested for file: " << source_file << endl;
}
tok = new ExtractorToken(_next_token++, source_file, event_name,
rel_path);
_token_board->_waiting.insert(tok);
process_request();
}
return tok->_id;
}
////////////////////////////////////////////////////////////////////
// Function: Extractor::process_request
// Access: Private
// Description: Serves any requests on the token board, moving them
// to the done queue.
////////////////////////////////////////////////////////////////////
bool Extractor::
process_request() {
if (_shutdown) {
if (downloader_cat.is_debug())
downloader_cat.debug()
<< "Extractor shutting down...\n";
return false;
}
// If there is actually a request token - process it
while (!_token_board->_waiting.is_empty()) {
PT(ExtractorToken) tok = _token_board->_waiting.extract();
if (extract(tok->_source_file, tok->_rel_path)) {
_token_board->_done.insert(tok);
// Throw a "done" event now.
if (!tok->_event_name.empty()) {
PT_Event done = new Event(tok->_event_name);
done->add_parameter(EventParameter((int)tok->_id));
throw_event(done);
}
if (downloader_cat.is_debug()) {
downloader_cat.debug()
<< "Extractor::process_request() - extract complete for "
<< tok->_source_file << "\n";
}
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: Extractor::extract
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
bool Extractor::
extract(Filename &source_file, const Filename &rel_path) {
// Open source file
ifstream read_stream;
source_file.set_binary();
if (!source_file.open_read(read_stream)) {
downloader_cat.error()
<< "Extractor::extract() - Error opening source file: "
<< source_file << endl;
return false;
}
// Determine source file length
read_stream.seekg(0, ios::end);
int source_file_length = read_stream.tellg();
read_stream.seekg(0, ios::beg);
// Read the multifile header
Multifile mfile;
// Read from the source file and write to the appropriate extracted file
int total_bytes_read = 0;
bool read_all_input = false;
bool handled_all_input = false;
int source_buffer_length;
while (handled_all_input == false) {
// See if there is anything left in the source file
if (read_all_input == false) {
read_stream.read(_buffer->_buffer, _buffer->get_length());
source_buffer_length = read_stream.gcount();
total_bytes_read += source_buffer_length;
if (read_stream.eof()) {
nassertr(total_bytes_read == source_file_length, false);
read_all_input = true;
}
}
// Write to the out file
char *start = _buffer->_buffer;
int size = source_buffer_length;
if (mfile.write_extract(start, size, rel_path) == true)
handled_all_input = true;
nap();
}
read_stream.close();
source_file.unlink();
return true;
}

View File

@ -1,58 +0,0 @@
// Filename: asyncExtractor.h
// Created by: mike (09Jan97)
//
////////////////////////////////////////////////////////////////////
//
// 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 ASYNCEXTRACTOR_H
#define ASYNCEXTRACTOR_H
//
////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////
#include <pandabase.h>
#include <filename.h>
#include <tokenBoard.h>
#include <buffer.h>
#include <multifile.h>
#include "asyncUtility.h"
class ExtractorToken;
////////////////////////////////////////////////////////////////////
// Class : Extractor
// Description :
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS Extractor : public AsyncUtility {
PUBLISHED:
Extractor(void);
Extractor(PT(Buffer) buffer);
virtual ~Extractor(void);
int request_extract(const Filename &source_file,
const string &event_name, const Filename &rel_path = "");
bool extract(Filename &source_file, const Filename &rel_path);
private:
void init(PT(Buffer) buffer);
virtual bool process_request(void);
typedef TokenBoard<ExtractorToken> ExtractorTokenBoard;
ExtractorTokenBoard *_token_board;
PT(Buffer) _buffer;
};
#endif

View File

@ -21,16 +21,11 @@
////////////////////////////////////////////////////////////////////
// Function: Extractor::get_progress
// Access: Public
// Description:
// Description: Returns the fraction of the Multifile extracted so
// far.
////////////////////////////////////////////////////////////////////
INLINE float Extractor::
get_progress(void) const {
if (_initiated == false) {
downloader_cat.warning()
<< "Extractor::get_progress() - Extraction has not been initiated"
<< endl;
return 0.0;
}
nassertr(_source_file_length > 0, 0.0);
return ((float)_total_bytes_read / (float)_source_file_length);
get_progress() const {
nassertr(_initiated, 0.0f);
return ((float)_subfile_index / (float)(_multifile.get_num_subfiles() + 1));
}

View File

@ -16,17 +16,12 @@
//
////////////////////////////////////////////////////////////////////
#include "extractor.h"
#include "config_downloader.h"
#include <filename.h>
#include <error_utils.h>
#include "filename.h"
#include "error_utils.h"
#include <errno.h>
#include "extractor.h"
////////////////////////////////////////////////////////////////////
// Defines
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: Extractor::Constructor
@ -34,35 +29,8 @@
// Description:
////////////////////////////////////////////////////////////////////
Extractor::
Extractor(void) {
PT(Buffer) buffer = new Buffer(extractor_buffer_size);
init(buffer);
}
////////////////////////////////////////////////////////////////////
// Function: Extractor::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
Extractor::
Extractor(PT(Buffer) buffer) {
init(buffer);
}
////////////////////////////////////////////////////////////////////
// Function: Extractor::Constructor
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
void Extractor::
init(PT(Buffer) buffer) {
if (downloader_cat.is_debug())
downloader_cat.debug()
<< "Extractor constructor called" << endl;
Extractor() {
_initiated = false;
nassertv(!buffer.is_null());
_buffer = buffer;
_mfile = NULL;
}
////////////////////////////////////////////////////////////////////
@ -71,136 +39,163 @@ init(PT(Buffer) buffer) {
// Description:
////////////////////////////////////////////////////////////////////
Extractor::
~Extractor(void) {
~Extractor() {
if (downloader_cat.is_debug())
downloader_cat.debug()
<< "Extractor destructor called" << endl;
if (_initiated == true)
if (_initiated) {
cleanup();
}
}
////////////////////////////////////////////////////////////////////
// Function: Extractor::initiate
// Access: Public
// Description:
// Description: Begins the extraction process. Returns EU_success if
// successful, EU_error_abort otherwise.
//
// After calling initiate(), you should repeatedly call
// run() as a background task until the file is
// completely extracted.
////////////////////////////////////////////////////////////////////
int Extractor::
initiate(Filename &source_file, const Filename &rel_path) {
if (_initiated == true) {
initiate(const Filename &multifile_name, const Filename &extract_to) {
if (_initiated) {
downloader_cat.error()
<< "Extractor::initiate() - Extraction has already been initiated"
<< endl;
return EU_error_abort;
}
// Open source file
_source_file = source_file;
_source_file.set_binary();
if (!_source_file.open_read(_read_stream)) {
_multifile_name = multifile_name;
_extract_to = extract_to;
if (!_multifile.open_read(_multifile_name)) {
downloader_cat.error()
<< "Extractor::extract() - Error opening source file: "
<< _source_file << " : " << strerror(errno) << endl;
return get_write_error();
<< "Error opening Multifile " << _multifile_name << ".\n";
return EU_error_abort;
}
_rel_path = rel_path;
// Determine source file length
_read_stream.seekg(0, ios::end);
_source_file_length = _read_stream.tellg();
_read_stream.seekg(0, ios::beg);
_total_bytes_read = 0;
_read_all_input = false;
_handled_all_input = false;
_mfile = new Multifile();
_subfile_index = 0;
_subfile_pos = 0;
_subfile_length = 0;
_read = (istream *)NULL;
_initiated = true;
return EU_success;
}
////////////////////////////////////////////////////////////////////
// Function: Extractor::run
// Access: Public
// Description: Extracts the next small unit of data from the
// Multifile. Returns EU_ok if progress is continuing,
// EU_error_abort if there is a problem, or EU_success
// when the last piece has been extracted.
////////////////////////////////////////////////////////////////////
int Extractor::
run() {
if (!_initiated) {
downloader_cat.error()
<< "Extractor::run() - Extraction has not been initiated"
<< endl;
return EU_error_abort;
}
if (_read == (istream *)NULL) {
// Time to open the next subfile.
if (_subfile_index >= _multifile.get_num_subfiles()) {
// All done!
cleanup();
return EU_success;
}
Filename subfile_filename(_extract_to,
_multifile.get_subfile_name(_subfile_index));
subfile_filename.set_binary();
subfile_filename.make_dir();
if (!subfile_filename.open_write(_write)) {
downloader_cat.error()
<< "Unable to write to " << subfile_filename << ".\n";
cleanup();
return EU_error_abort;
}
_subfile_length = _multifile.get_subfile_length(_subfile_index);
_subfile_pos = 0;
_read = &_multifile.open_read_subfile(_subfile_index);
} else if (_subfile_pos >= _subfile_length) {
// Time to close this subfile.
_multifile.close_subfile();
_write.close();
_read = (istream *)NULL;
_subfile_index++;
} else {
// Read a number of bytes from the subfile and write them to the
// output.
size_t max_bytes = min((size_t)extractor_buffer_size,
_subfile_length - _subfile_pos);
for (size_t p = 0; p < max_bytes; p++) {
int byte = _read->get();
if (_read->eof() || _read->fail()) {
downloader_cat.error()
<< "Unexpected EOF on multifile " << _multifile_name << ".\n";
cleanup();
return EU_error_abort;
}
_write.put(byte);
}
_subfile_pos += max_bytes;
}
return EU_ok;
}
////////////////////////////////////////////////////////////////////
// Function: Extractor::extract
// Access: Public
// Description: A convenience function to extract the Multifile all
// at once, when you don't care about doing it in the
// background.
////////////////////////////////////////////////////////////////////
bool Extractor::
extract(const Filename &source_file, const Filename &rel_path) {
int ret = initiate(source_file, rel_path);
if (ret < 0) {
return false;
}
for (;;) {
ret = run();
if (ret == EU_success) {
return true;
}
if (ret < 0) {
return false;
}
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: Extractor::cleanup
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
void Extractor::
cleanup(void) {
cleanup() {
if (downloader_cat.is_debug())
downloader_cat.debug()
<< "Extractor cleanup called" << endl;
if (_initiated == false) {
if (!_initiated) {
downloader_cat.error()
<< "Extractor::cleanup() - Extraction has not been initiated"
<< endl;
return;
}
delete _mfile;
_mfile = NULL;
_read_stream.close();
// _source_file.unlink();
_initiated = false;
}
////////////////////////////////////////////////////////////////////
// Function: Extractor::run
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
int Extractor::
run(void) {
if (_initiated == false) {
downloader_cat.error()
<< "Extractor::run() - Extraction has not been initiated"
<< endl;
return EU_error_abort;
}
// See if there is anything left in the source file
if (_read_all_input == false) {
_read_stream.read(_buffer->_buffer, _buffer->get_length());
_source_buffer_length = _read_stream.gcount();
_total_bytes_read += _source_buffer_length;
if (_read_stream.eof()) {
nassertr(_total_bytes_read == _source_file_length, false);
_read_all_input = true;
}
}
char *buffer_start = _buffer->_buffer;
int buffer_size = _source_buffer_length;
// Write to the out file
int write_ret = _mfile->write(buffer_start, buffer_size, _rel_path);
if (write_ret == EU_success) {
cleanup();
return EU_success;
} else if (write_ret < 0) {
downloader_cat.error()
<< "Extractor::run() - got error from Multifile: " << write_ret
<< endl;
return write_ret;
}
return EU_ok;
}
////////////////////////////////////////////////////////////////////
// Function: Extractor::extract
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
bool Extractor::
extract(Filename &source_file, const Filename &rel_path) {
int ret = initiate(source_file, rel_path);
if (ret < 0)
return false;
for (;;) {
ret = run();
if (ret == EU_success)
return true;
if (ret < 0)
return false;
}
return false;
_multifile.close();
_write.close();
_read = (istream *)NULL;
}

View File

@ -17,49 +17,51 @@
////////////////////////////////////////////////////////////////////
#ifndef EXTRACTOR_H
#define EXTRACTOR_H
//
////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////
#include <pandabase.h>
#include <filename.h>
#include <buffer.h>
#include <multifile.h>
#include <pointerTo.h>
#include "pandabase.h"
#include "filename.h"
#include "buffer.h"
#include "multifile.h"
#include "pointerTo.h"
////////////////////////////////////////////////////////////////////
// Class : Extractor
// Description :
// Description : This class automatically extracts the contents of a
// Multifile to the current directory (or to a specified
// directory) in the background.
//
// It is designed to limit its use of system resources
// and run unobtrusively in the background. After
// initiate(), each call to run() extracts another small
// portion of the Multifile. Call run() repeatedly
// whenever you have spare cycles until run() returns
// EU_success.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS Extractor {
PUBLISHED:
Extractor(void);
Extractor(PT(Buffer) buffer);
virtual ~Extractor(void);
Extractor();
~Extractor();
int initiate(Filename &source_file, const Filename &rel_path = "");
int run(void);
int initiate(const Filename &multifile_name, const Filename &extract_to = "");
int run();
bool extract(Filename &source_file, const Filename &rel_path = "");
bool extract(const Filename &multifile_name, const Filename &extract_to = "");
INLINE float get_progress(void) const;
private:
void init(PT(Buffer) buffer);
void cleanup(void);
void cleanup();
bool _initiated;
PT(Buffer) _buffer;
Filename _multifile_name;
Filename _extract_to;
Multifile _multifile;
ifstream _read_stream;
int _source_file_length;
Multifile *_mfile;
int _total_bytes_read;
bool _read_all_input;
bool _handled_all_input;
int _source_buffer_length;
Filename _source_file;
Filename _rel_path;
int _subfile_index;
size_t _subfile_pos;
size_t _subfile_length;
istream *_read;
ofstream _write;
};
#include "extractor.I"

View File

@ -16,89 +16,354 @@
//
////////////////////////////////////////////////////////////////////
#include <pandabase.h>
#include "pandabase.h"
#ifndef HAVE_GETOPT
#include <gnu_getopt.h>
#include "gnu_getopt.h"
#else
#include <getopt.h>
#endif
#include <multifile.h>
#include <filename.h>
#ifndef OLD_WAY
#include <extractor.h>
#endif
#include "multifile.h"
#include "filename.h"
#include <stdio.h>
bool create = false; // -c
bool append = false; // -r
bool list = false; // -t
bool extract = false; // -x
bool verbose = false; // -v
Filename multifile_name; // -f
bool got_multifile_name = false;
bool to_stdout = false; // -O
Filename chdir_to; // -C
bool got_chdir_to = false;
size_t scale_factor = 0; // -F
void
usage() {
cerr << "Usage: multify -[c|r|t|x] -f <multifile_name> [options] <subfile_name> ...\n";
}
void
help() {
cerr << "multify is used to store and extract files from a Panda Multifile.\n"
<< "This is similar to a tar or zip file in that it is an archive file that\n"
<< "contains a number of subfiles that may later be extracted.\n\n"
<< "The command-line options for multify are designed to be similar to those\n"
<< "for tar, the traditional Unix archiver utility.\n\n";
usage();
}
bool
is_named(const string &subfile_name, int argc, char *argv[]) {
// Returns true if the indicated subfile appears on the list of
// files named on the command line.
if (argc < 2) {
// No named files; everything is listed.
return true;
}
for (int i = 1; i < argc; i++) {
if (subfile_name == argv[i]) {
return true;
}
}
return false;
}
bool
add_directory(Multifile &multifile, const Filename &directory_name) {
vector_string files;
if (!directory_name.scan_directory(files)) {
cerr << "Unable to scan directory " << directory_name << "\n";
return false;
}
bool okflag = true;
vector_string::const_iterator fi;
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);
} else if (!subfile_name.exists()) {
cerr << "Not found: " << subfile_name << "\n";
okflag = false;
} else {
if (verbose) {
cout << subfile_name << "\n";
}
if (!multifile.add_subfile(subfile_name, subfile_name)) {
cerr << "Unable to add " << subfile_name << ".\n";
okflag = false;
}
}
}
return okflag;
}
bool
add_files(int argc, char *argv[]) {
Multifile multifile;
if (append) {
if (!multifile.open_read_write(multifile_name)) {
cerr << "Unable to open " << multifile_name << " for updating.\n";
return false;
}
} else {
if (!multifile.open_write(multifile_name)) {
cerr << "Unable to open " << multifile_name << " for writing.\n";
return false;
}
}
if (scale_factor != 0 && scale_factor != multifile.get_scale_factor()) {
cerr << "Setting scale factor to " << scale_factor << "\n";
multifile.set_scale_factor(scale_factor);
}
bool okflag = true;
for (int i = 1; i < argc; i++) {
Filename subfile_name = Filename::from_os_specific(argv[i]);
if (subfile_name.is_directory()) {
if (!add_directory(multifile, subfile_name)) {
okflag = false;
}
} else if (!subfile_name.exists()) {
cerr << "Not found: " << subfile_name << "\n";
okflag = false;
} else {
if (verbose) {
cout << subfile_name << "\n";
}
if (!multifile.add_subfile(subfile_name, subfile_name)) {
cerr << "Unable to add " << subfile_name << ".\n";
okflag = false;
}
}
}
if (multifile.needs_repack()) {
if (!multifile.repack()) {
cerr << "Failed to write " << multifile_name << ".\n";
okflag = false;
}
} else {
if (!multifile.flush()) {
cerr << "Failed to write " << multifile_name << ".\n";
okflag = false;
}
}
return okflag;
}
bool
extract_files(int argc, char *argv[]) {
if (!multifile_name.exists()) {
cerr << multifile_name << " not found.\n";
return false;
}
Multifile multifile;
if (!multifile.open_read(multifile_name)) {
cerr << "Unable to open " << multifile_name << " for reading.\n";
return false;
}
int num_subfiles = multifile.get_num_subfiles();
for (int i = 0; i < num_subfiles; i++) {
string subfile_name = multifile.get_subfile_name(i);
if (is_named(subfile_name, argc, argv)) {
Filename filename = subfile_name;
if (got_chdir_to) {
filename = Filename(chdir_to, subfile_name);
}
if (to_stdout) {
if (verbose) {
cerr << filename << "\n";
}
multifile.extract_subfile_to(i, cout);
} else {
if (verbose) {
cout << filename << "\n";
}
multifile.extract_subfile(i, filename);
}
}
}
return true;
}
bool
list_files(int argc, char *argv[]) {
if (!multifile_name.exists()) {
cerr << multifile_name << " not found.\n";
return false;
}
Multifile multifile;
if (!multifile.open_read(multifile_name)) {
cerr << "Unable to open " << multifile_name << " for reading.\n";
return false;
}
int num_subfiles = multifile.get_num_subfiles();
if (verbose) {
cout << num_subfiles << " subfiles:\n" << flush;
for (int i = 0; i < num_subfiles; i++) {
string subfile_name = multifile.get_subfile_name(i);
if (is_named(subfile_name, argc, argv)) {
printf("%12d %s\n",
multifile.get_subfile_length(i),
subfile_name.c_str());
}
}
fflush(stdout);
if (multifile.get_scale_factor() != 1) {
cout << "Scale factor is " << multifile.get_scale_factor() << "\n";
}
if (multifile.needs_repack()) {
cout << "Multifile needs to be repacked.\n";
}
} else {
for (int i = 0; i < num_subfiles; i++) {
string subfile_name = multifile.get_subfile_name(i);
if (is_named(subfile_name, argc, argv)) {
cout << subfile_name << "\n";
}
}
}
return true;
}
int
main(int argc, char *argv[]) {
if (argc < 3) {
cerr << "Usage: multify -[x,c|vr] <dest_file> <src_file> ..." << endl;
return 0;
if (argc < 2) {
usage();
return 1;
}
bool verbose = true;
bool extract = false;
// To emulate tar, we assume an implicit hyphen in front of the
// first argument if there is not one already.
if (argc >= 2) {
if (*argv[1] != '-' && *argv[1] != '\0') {
char *new_arg = new char[strlen(argv[1]) + 2];
new_arg[0] = '-';
strcpy(new_arg + 1, argv[1]);
argv[1] = new_arg;
}
}
extern char *optarg;
extern int optind;
int flag = getopt(argc, argv, "xcvr:");
static const char *optflags = "crtxvf:OC:F:h";
int flag = getopt(argc, argv, optflags);
Filename rel_path;
while (flag != EOF) {
switch (flag) {
case 'x':
extract = true;
break;
case 'c':
break;
case 'v':
verbose = true;
break;
case 'r':
rel_path = optarg;
break;
default:
cerr << "Unhandled switch: " << flag << endl;
break;
case 'c':
create = true;
break;
case 'r':
append = true;
break;
case 't':
list = true;
break;
case 'x':
extract = true;
break;
case 'v':
verbose = true;
break;
case 'f':
multifile_name = Filename::from_os_specific(optarg);
got_multifile_name = true;
break;
case 'C':
chdir_to = Filename::from_os_specific(optarg);
got_chdir_to = true;
break;
case 'O':
to_stdout = true;
break;
case 'F':
{
char *endptr;
scale_factor = strtol(optarg, &endptr, 10);
if (*endptr != '\0') {
cerr << "Invalid integer: " << optarg << "\n";
usage();
return 1;
}
if (scale_factor == 0) {
cerr << "Scale factor must be nonzero.\n";
usage();
return 1;
}
}
break;
case 'h':
help();
return 1;
case '?':
usage();
return 1;
default:
cerr << "Unhandled switch: " << flag << endl;
break;
}
flag = getopt(argc, argv, "xcvr:");
flag = getopt(argc, argv, optflags);
}
argc -= (optind - 1);
argv += (optind - 1);
if (argc <= 1) {
cerr << "Usage: multify -[x,c|v] <dest_file> <src_file> ..." << endl;
return 0;
// 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";
usage();
return 1;
}
Filename dest_file = argv[1];
dest_file.set_binary();
if (verbose == true) {
if (extract == true)
cerr << "Extracting from: " << dest_file << endl;
else
cerr << "Appending to: " << dest_file << endl;
}
Multifile mfile;
if (extract == false) {
for (int i = 2; i < argc; i++) {
Filename in_file = argv[i];
in_file.set_binary();
mfile.add(in_file);
if (!got_multifile_name) {
if (argc <= 1) {
usage();
return 1;
}
if (mfile.write(dest_file) == false)
cerr << "Failed to write: " << dest_file << endl;
} else {
#ifdef OLD_WAY
mfile.read(dest_file);
mfile.extract_all(rel_path);
#else
Extractor extor;
extor.extract(dest_file, rel_path);
#endif
// 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++;
}
return 1;
bool okflag = true;
if (create || append) {
okflag = add_files(argc, argv);
} else if (extract) {
okflag = extract_files(argc, argv);
} else { // list
okflag = list_files(argc, argv);
}
if (okflag) {
return 0;
} else {
return 1;
}
}

View File

@ -9,55 +9,61 @@
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
#define SOURCES \
bigEndian.h buffer.I buffer.h \
checksumHashGenerator.I checksumHashGenerator.h circBuffer.I \
circBuffer.h clockObject.I clockObject.h config_express.h \
datagram.I datagram.h datagramGenerator.I \
datagramGenerator.h datagramInputFile.I datagramInputFile.h \
datagramIterator.I datagramIterator.h datagramOutputFile.I \
datagramOutputFile.h datagramSink.I datagramSink.h \
dcast.T dcast.h \
error_utils.h \
get_config_path.h hashGeneratorBase.I hashGeneratorBase.h \
hashVal.I hashVal.h indent.I indent.h littleEndian.h \
memoryInfo.I memoryInfo.h \
memoryUsage.I memoryUsage.h \
memoryUsagePointerCounts.I memoryUsagePointerCounts.h \
memoryUsagePointers.I memoryUsagePointers.h \
multifile.I multifile.h namable.I \
namable.h nativeNumericData.I nativeNumericData.h \
numeric_types.h pointerTo.I pointerTo.h \
pointerToArray.I pointerToArray.h \
profileTimer.I profileTimer.h \
pta_uchar.h referenceCount.I referenceCount.h \
register_type.I register_type.h \
reversedNumericData.I reversedNumericData.h tokenBoard.I \
tokenBoard.h trueClock.I trueClock.h typeHandle.I \
typeHandle.h typedObject.I typedObject.h \
typedReferenceCount.I typedReferenceCount.h typedef.h \
typeRegistry.I typeRegistry.h \
typeRegistryNode.I typeRegistryNode.h \
vector_uchar.h \
$[if $[HAVE_CRYPTO], \
crypto_utils.cxx crypto_utils.h patchfile.I \
patchfile.cxx patchfile.h ]
bigEndian.h buffer.I buffer.h \
checksumHashGenerator.I checksumHashGenerator.h circBuffer.I \
circBuffer.h clockObject.I clockObject.h config_express.h \
datagram.I datagram.h datagramGenerator.I \
datagramGenerator.h datagramInputFile.I datagramInputFile.h \
datagramIterator.I datagramIterator.h datagramOutputFile.I \
datagramOutputFile.h datagramSink.I datagramSink.h \
dcast.T dcast.h \
error_utils.h \
get_config_path.h hashGeneratorBase.I hashGeneratorBase.h \
hashVal.I hashVal.h indent.I indent.h \
indirectLess.I indirectLess.h \
littleEndian.h \
memoryInfo.I memoryInfo.h \
memoryUsage.I memoryUsage.h \
memoryUsagePointerCounts.I memoryUsagePointerCounts.h \
memoryUsagePointers.I memoryUsagePointers.h \
multifile.I multifile.h namable.I \
namable.h nativeNumericData.I nativeNumericData.h \
numeric_types.h \
ordered_vector.h ordered_vector.I ordered_vector.T \
pointerTo.I pointerTo.h \
pointerToArray.I pointerToArray.h \
profileTimer.I profileTimer.h \
pta_uchar.h referenceCount.I referenceCount.h \
register_type.I register_type.h \
reversedNumericData.I reversedNumericData.h tokenBoard.I \
tokenBoard.h trueClock.I trueClock.h typeHandle.I \
typeHandle.h typedObject.I typedObject.h \
typedReferenceCount.I typedReferenceCount.h typedef.h \
typeRegistry.I typeRegistry.h \
typeRegistryNode.I typeRegistryNode.h \
vector_uchar.h \
$[if $[HAVE_CRYPTO], \
crypto_utils.cxx crypto_utils.h patchfile.I \
patchfile.cxx patchfile.h ]
#define INCLUDED_SOURCES \
buffer.cxx checksumHashGenerator.cxx clockObject.cxx \
config_express.cxx datagram.cxx datagramGenerator.cxx \
datagramInputFile.cxx datagramIterator.cxx \
datagramOutputFile.cxx datagramSink.cxx dcast.cxx error_utils.cxx \
get_config_path.cxx \
hashGeneratorBase.cxx hashVal.cxx indent.cxx \
memoryInfo.cxx memoryUsage.cxx memoryUsagePointerCounts.cxx \
memoryUsagePointers.cxx multifile.cxx namable.cxx \
nativeNumericData.cxx profileTimer.cxx \
pta_uchar.cxx referenceCount.cxx register_type.cxx \
reversedNumericData.cxx trueClock.cxx typeHandle.cxx \
typedObject.cxx typedReferenceCount.cxx \
typeRegistry.cxx typeRegistryNode.cxx vector_uchar.cxx
buffer.cxx checksumHashGenerator.cxx clockObject.cxx \
config_express.cxx datagram.cxx datagramGenerator.cxx \
datagramInputFile.cxx datagramIterator.cxx \
datagramOutputFile.cxx datagramSink.cxx dcast.cxx error_utils.cxx \
get_config_path.cxx \
hashGeneratorBase.cxx hashVal.cxx indent.cxx \
memoryInfo.cxx memoryUsage.cxx memoryUsagePointerCounts.cxx \
memoryUsagePointers.cxx multifile.cxx namable.cxx \
nativeNumericData.cxx \
ordered_vector.cxx \
profileTimer.cxx \
pta_uchar.cxx referenceCount.cxx register_type.cxx \
reversedNumericData.cxx trueClock.cxx typeHandle.cxx \
typedObject.cxx typedReferenceCount.cxx \
typeRegistry.cxx typeRegistryNode.cxx vector_uchar.cxx
#define INSTALL_HEADERS \
#define INSTALL_HEADERS \
bigEndian.h buffer.I buffer.h checksumHashGenerator.I \
checksumHashGenerator.h circBuffer.I circBuffer.h clockObject.I \
clockObject.h config_express.h datagram.I datagram.h \
@ -66,12 +72,15 @@
datagramOutputFile.I datagramOutputFile.h datagramSink.I \
datagramSink.h dcast.T dcast.h \
error_utils.h get_config_path.h hashGeneratorBase.I \
hashGeneratorBase.h hashVal.I hashVal.h indent.I indent.h \
hashGeneratorBase.h hashVal.I hashVal.h \
indent.I indent.h \
indirectLess.I indirectLess.h \
littleEndian.h memoryInfo.I memoryInfo.h memoryUsage.I \
memoryUsage.h memoryUsagePointerCounts.I \
memoryUsagePointerCounts.h memoryUsagePointers.I \
memoryUsagePointers.h multifile.I multifile.h namable.I namable.h \
nativeNumericData.I nativeNumericData.h numeric_types.h \
ordered_vector.h ordered_vector.I ordered_vector.T \
patchfile.I patchfile.h pointerTo.I pointerTo.h \
pointerToArray.I pointerToArray.h profileTimer.I \
profileTimer.h pta_uchar.h referenceCount.I referenceCount.h \
@ -98,3 +107,14 @@
#end test_bin_target
#begin test_bin_target
#define TARGET test_ordered_vector
#define SOURCES \
test_ordered_vector.cxx
#define LOCAL_LIBS $[LOCAL_LIBS] putil
#define OTHER_LIBS $[OTHER_LIBS] pystub
#end test_bin_target

View File

@ -2,6 +2,7 @@
#include "multifile.cxx"
#include "namable.cxx"
#include "nativeNumericData.cxx"
#include "ordered_vector.cxx"
#include "profileTimer.cxx"
#include "pta_uchar.cxx"
#include "referenceCount.cxx"

View File

@ -19,7 +19,7 @@
#ifndef INDIRECTLESS_H
#define INDIRECTLESS_H
#include <pandabase.h>
#include "pandabase.h"
////////////////////////////////////////////////////////////////////
// Class : IndirectLess

View File

@ -16,27 +16,180 @@
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: Multifile::write_header
// Access: Private
// Description: Writes the header uncompressed with platform-
// independent byte ordering
// Function: Multifile::is_read_valid
// Access: Published
// Description: Returns true if the Multifile has been opened for
// read mode and there have been no errors, and
// individual Subfile contents may be extracted.
////////////////////////////////////////////////////////////////////
INLINE void Multifile::
write_header(ofstream &write_stream) {
_datagram.clear();
_datagram.add_uint32(_magic_number);
_datagram.add_int32(_num_mfiles);
string msg = _datagram.get_message();
write_stream.write((char *)msg.data(), msg.length());
INLINE bool Multifile::
is_read_valid() const {
return (_read != (istream *)NULL && !_read->fail() &&
_open_subfile == (Subfile *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::get_header_length
// Access: Public
// Description:
// Function: Multifile::is_write_valid
// Access: Published
// Description: Returns true if the Multifile has been opened for
// write mode and there have been no errors, and
// Subfiles may be added or removed from the Multifile.
////////////////////////////////////////////////////////////////////
INLINE int Multifile::
get_header_length(void) const {
return _header_length;
INLINE bool Multifile::
is_write_valid() const {
return (_write != (ostream *)NULL && !_write->fail() &&
_open_subfile == (Subfile *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::needs_repack
// Access: Published
// Description: Returns true if the Multifile index is suboptimal and
// should be repacked. Call repack() to achieve this.
////////////////////////////////////////////////////////////////////
INLINE bool Multifile::
needs_repack() const {
return _needs_repack;
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::set_scale_factor
// Access: Published
// Description: Changes the internal scale factor for this Multifile.
//
// This is normally 1, but it may be set to any
// arbitrary value (greater than zero) to support
// Multifile archives that exceed 4GB, if necessary.
// (Individual subfiles may still not exceed 4GB.)
//
// All addresses within the file are rounded up to the
// next multiple of _scale_factor, and zeros are written
// to the file to fill the resulting gaps. Then the
// address is divided by _scale_factor and written out
// as a 32-bit integer. Thus, setting a scale factor of
// 2 supports up to 8GB files, 3 supports 12GB files,
// etc.
//
// Calling this function on an already-existing
// Multifile forces an immediate repack() operation.
////////////////////////////////////////////////////////////////////
INLINE void Multifile::
set_scale_factor(size_t scale_factor) {
nassertv(scale_factor != 0);
if (_scale_factor != scale_factor) {
_scale_factor = scale_factor;
if (_next_index != 0) {
repack();
}
}
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::get_scale_factor
// Access: Published
// Description: Returns the internal scale factor for this Multifile.
// See set_scale_factor().
////////////////////////////////////////////////////////////////////
INLINE size_t Multifile::
get_scale_factor() const {
return _scale_factor;
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::word_to_streampos
// Access: Private
// Description: Converts a size_t address read from the file to
// a streampos byte address within the file.
////////////////////////////////////////////////////////////////////
INLINE streampos Multifile::
word_to_streampos(size_t word) const {
return (streampos)word * (streampos)_scale_factor;
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::streampos_to_word
// Access: Private
// Description: Converts a streampos byte address within the file to
// a size_t value suitable for writing to the file.
////////////////////////////////////////////////////////////////////
INLINE size_t Multifile::
streampos_to_word(streampos fpos) const {
return (size_t)((fpos + _scale_factor - 1) / _scale_factor);
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::normalize_streampos
// Access: Private
// Description: Rounds the streampos byte address up to the next
// multiple of _scale_factor. Only multiples of
// _scale_factor may be written to the file.
////////////////////////////////////////////////////////////////////
INLINE streampos Multifile::
normalize_streampos(streampos fpos) const {
return word_to_streampos(streampos_to_word(fpos));
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::Subfile::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE Multifile::Subfile::
Subfile(const string &name) :
_name(name)
{
_index_start = 0;
_data_start = 0;
_data_length = 0;
_source = (istream *)NULL;
_flags = 0;
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::Subfile::operator <
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool Multifile::Subfile::
operator < (const Multifile::Subfile &other) const {
return _name < other._name;
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::Subfile::is_deleted
// Access: Public
// Description: Returns true if the Subfile indicates it has been
// deleted (removed from the index), false otherwise.
// This should never be true of Subfiles that currently
// appear in either the _subfiles or _new_subfiles
// lists.
////////////////////////////////////////////////////////////////////
INLINE bool Multifile::Subfile::
is_deleted() const {
return (_flags & SF_deleted) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::Subfile::is_index_invalid
// Access: Public
// Description: Returns true if there was some problem reading the
// index record for this Subfile from the Multifile.
////////////////////////////////////////////////////////////////////
INLINE bool Multifile::Subfile::
is_index_invalid() const {
return (_flags & SF_index_invalid) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::Subfile::is_data_invalid
// Access: Public
// Description: Returns true if there was some problem reading the
// data contents of this Subfile, particularly when
// copying into the Multifile.
////////////////////////////////////////////////////////////////////
INLINE bool Multifile::Subfile::
is_data_invalid() const {
return (_flags & SF_data_invalid) != 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -15,21 +15,19 @@
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef MULTIFILE_H
#define MULTIFILE_H
//
////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////
#include <pandabase.h>
#include "typedef.h"
#include "pandabase.h"
#include "datagram.h"
#include "datagramIterator.h"
#include <notify.h>
#include <filename.h>
#include "plist.h"
#include "filename.h"
#include "ordered_vector.h"
#include "indirectLess.h"
#include "pvector.h"
////////////////////////////////////////////////////////////////////
// Class : Multifile
@ -37,95 +35,120 @@
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS Multifile {
PUBLISHED:
enum Type {
T_unknown,
T_valid,
T_invalid,
};
Multifile();
~Multifile();
Multifile(void);
~Multifile(void);
bool open_read(const Filename &multifile_name);
bool open_write(const Filename &multifile_name);
bool open_read_write(const Filename &multifile_name);
void close();
INLINE int get_header_length(void) const;
INLINE bool is_read_valid() const;
INLINE bool is_write_valid() const;
INLINE bool needs_repack() const;
static int evaluate(const char *start, int size);
INLINE void set_scale_factor(size_t scale_factor);
INLINE size_t get_scale_factor() const;
bool add(const Filename &name);
bool remove(const Filename &name);
bool has_file(const Filename &name);
bool add_subfile(const string &subfile_name, const Filename &filename);
bool flush();
bool repack();
bool read(Filename &name);
bool write(Filename name);
int write(char *&start, int &size, const Filename &rel_path = "");
bool write_extract(char *&start, int &size, const Filename &rel_path = "");
bool extract(const Filename &name, const Filename &rel_path = "");
void extract_all(const Filename &rel_path = "");
int get_num_subfiles() const;
int find_subfile(const string &subfile_name) const;
void remove_subfile(int index);
const string &get_subfile_name(int index) const;
size_t get_subfile_length(int index) const;
void reset(void);
int parse_header(char *&start, int &size);
private:
INLINE void write_header(ofstream &write_stream);
void read_subfile(int index, Datagram &datagram);
bool extract_subfile(int index, const Filename &filename);
public:
// This nested class must be public so we can make a list of its
// pointers. Weird.
class Memfile {
public:
Memfile(void);
~Memfile(void);
bool parse_header_length(char *&start, int &size);
bool parse_header(char *&start, int &size);
// Special interfaces to work with iostreams, not necessarily files.
bool open_read(istream *multifile_stream);
bool open_write(ostream *multifile_stream);
bool open_read_write(iostream *multifile_stream);
bool add_subfile(const string &subfile_name, istream *subfile_data);
bool read(const Filename &name);
bool read_from_multifile(ifstream &read_stream);
bool write(const Filename &rel_path);
void write_to_multifile(ofstream &write_stream);
int write(char *&start, int &size, const Filename &rel_path = "");
void reset(void);
public:
bool _header_length_parsed;
bool _header_parsed;
Datagram _datagram;
char *_header_length_buf;
int _header_length_buf_length;
PN_int32 _header_length;
Filename _name;
PN_int32 _buffer_length;
char* _buffer;
bool _file_open;
ofstream _write_stream;
int _bytes_written;
};
bool extract_subfile_to(int index, ostream &out);
istream &open_read_subfile(int index);
void close_subfile();
private:
typedef plist<Memfile *> MemfileList;
class MemfileMatch {
public:
MemfileMatch(const Filename &name) {
_want_name = name;
}
bool operator()(Memfile *mfile) const {
return mfile->_name == _want_name;
}
Filename _want_name;
enum SubfileFlags {
SF_deleted = 0x0001,
SF_index_invalid = 0x0002,
SF_data_invalid = 0x0004,
};
private:
MemfileList _files;
PN_int32 _num_mfiles;
bool _header_parsed;
Memfile *_current_mfile;
Datagram _datagram;
int _header_length;
int _mfiles_written;
class Subfile {
public:
INLINE Subfile(const string &name);
INLINE bool operator < (const Subfile &other) const;
streampos read_index(istream &read, streampos fpos,
Multifile *multfile);
streampos write_index(ostream &write, streampos fpos,
Multifile *multifile);
streampos write_data(ostream &write, istream *read, streampos fpos);
void rewrite_index_data_start(ostream &write, Multifile *multifile);
void rewrite_index_flags(ostream &write);
INLINE bool is_deleted() const;
INLINE bool is_index_invalid() const;
INLINE bool is_data_invalid() const;
static PN_uint32 _magic_number;
string _name;
streampos _index_start;
streampos _data_start;
size_t _data_length;
istream *_source;
Filename _source_filename;
int _flags;
};
INLINE streampos word_to_streampos(size_t word) const;
INLINE size_t streampos_to_word(streampos fpos) const;
INLINE streampos normalize_streampos(streampos fpos) const;
streampos pad_to_streampos(streampos fpos);
bool add_new_subfile(Subfile *subfile);
void clear_subfiles();
bool read_index();
bool write_header();
typedef ov_set<Subfile *, IndirectLess<Subfile> > Subfiles;
Subfiles _subfiles;
typedef pvector<Subfile *> PendingSubfiles;
PendingSubfiles _new_subfiles;
PendingSubfiles _removed_subfiles;
istream *_read;
ostream *_write;
streampos _next_index;
streampos _last_index;
bool _needs_repack;
size_t _scale_factor;
ifstream _read_file;
ofstream _write_file;
fstream _read_write_file;
Filename _multifile_name;
int _file_major_ver;
int _file_minor_ver;
Subfile *_open_subfile;
// This is just to support open_read_subfile() for those subfiles
// that have recently been added but not flushed.
ifstream _subfile_read;
static const char _header[];
static const size_t _header_size;
static const int _current_major_ver;
static const int _current_minor_ver;
friend class Subfile;
};
#include "multifile.I"

View File

@ -20,7 +20,6 @@
#define ORDERED_VECTOR_H
#include "pandabase.h"
#include "config_util.h"
#include "pvector.h"
#include "pset.h"

View File

@ -30,13 +30,11 @@
globalPointerRegistry.I globalPointerRegistry.h \
indirectCompareNames.I indirectCompareNames.h \
indirectCompareTo.I indirectCompareTo.h \
indirectLess.I indirectLess.h \
ioPtaDatagramFloat.h ioPtaDatagramInt.h \
ioPtaDatagramShort.h keyboardButton.h lineStream.I \
lineStream.h lineStreamBuf.I lineStreamBuf.h \
modifierButtons.I modifierButtons.h mouseButton.h \
mouseData.I mouseData.h nameUniquifier.I nameUniquifier.h \
ordered_vector.h ordered_vector.I ordered_vector.T \
pipeline.h pipeline.I \
pipelineCycler.h pipelineCycler.I \
pipelineCyclerBase.h pipelineCyclerBase.I \
@ -67,7 +65,6 @@
keyboardButton.cxx lineStream.cxx lineStreamBuf.cxx \
modifierButtons.cxx mouseButton.cxx mouseData.cxx \
nameUniquifier.cxx \
ordered_vector.cxx \
pipeline.cxx \
pipelineCycler.cxx \
pipelineCyclerBase.cxx \
@ -100,13 +97,12 @@
globPattern.I globPattern.h \
globalPointerRegistry.I globalPointerRegistry.h \
indirectCompareNames.I indirectCompareNames.h indirectCompareTo.I \
indirectCompareTo.h indirectLess.I indirectLess.h \
indirectCompareTo.h \
ioPtaDatagramFloat.h ioPtaDatagramInt.h \
ioPtaDatagramShort.h iterator_types.h keyboardButton.h lineStream.I \
lineStream.h lineStreamBuf.I lineStreamBuf.h modifierButtons.I \
modifierButtons.h mouseButton.h mouseData.I mouseData.h \
nameUniquifier.I nameUniquifier.h \
ordered_vector.h ordered_vector.I ordered_vector.T \
pipeline.h pipeline.I \
pipelineCycler.h pipelineCycler.I \
pipelineCyclerBase.h pipelineCyclerBase.I \
@ -170,14 +166,3 @@
test_linestream.cxx
#end test_bin_target
#begin test_bin_target
#define TARGET test_ordered_vector
#define SOURCES \
test_ordered_vector.cxx
#define LOCAL_LIBS $[LOCAL_LIBS] putil
#define OTHER_LIBS $[OTHER_LIBS] pystub
#end test_bin_target

View File

@ -1,5 +1,4 @@
#include "nameUniquifier.cxx"
#include "ordered_vector.cxx"
#include "pipeline.cxx"
#include "pipelineCycler.cxx"
#include "pipelineCyclerBase.cxx"