fix fmod threading issues

This commit is contained in:
David Rose 2011-06-21 17:10:51 +00:00
parent 8fd5dff01c
commit 5b2c80e5f3
22 changed files with 557 additions and 169 deletions

View File

@ -29,6 +29,14 @@ ConfigureFn(config_fmodAudio) {
init_libFmodAudio();
}
ConfigVariableInt fmod_audio_preload_threshold
("fmod-audio-preload-threshold", 1048576,
PRC_DESC("Files that are smaller "
"than this number of bytes will be preloaded and kept "
"resident in memory, while files that are this size or larger "
"will be streamed from disk. Set this to -1 to preload "
"every file."));
////////////////////////////////////////////////////////////////////
// Function: init_libFmodAudio
// Description: Initializes the library. This must be called at

View File

@ -46,9 +46,8 @@ ConfigVariableInt miles_audio_expand_mp3_threshold
ConfigVariableInt miles_audio_preload_threshold
("miles-audio-preload-threshold", -1,
PRC_DESC("This is the last Miles fallback size, and should be no smaller "
"than both miles-audio-expand-mp3-threshold and "
"miles-audio-calc-mp3-threshold. Files that are smaller "
PRC_DESC("This should be no smaller "
"than miles-audio-expand-mp3-threshold. Files that are smaller "
"than this number of bytes will be preloaded and kept "
"resident in memory, while files that are this size or larger "
"will be streamed from disk. Set this to -1 to preload "

View File

@ -142,13 +142,6 @@ FmodAudioManager() {
if (_system_is_valid) {
result = _system->set3DSettings( _doppler_factor, _distance_factor, _drop_off_factor);
fmod_audio_errcheck("_system->set3DSettings()", result);
#if (FMOD_VERSION >= 0x00043100) // FMod 4.31.00 changed this API
result = _system->setFileSystem(open_callback, close_callback, read_callback, seek_callback, 0, 0, -1);
#else
result = _system->setFileSystem(open_callback, close_callback, read_callback, seek_callback, -1);
#endif
fmod_audio_errcheck("_system->setFileSystem()", result);
}
}
@ -833,97 +826,4 @@ get_cache_limit() const {
return 0;
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioManager::open_callback
// Access: Private, Static
// Description: A hook into Panda's virtual file system.
////////////////////////////////////////////////////////////////////
FMOD_RESULT F_CALLBACK FmodAudioManager::
open_callback(const char *name, int, unsigned int *file_size,
void **handle, void **user_data) {
if (name == (const char *)NULL || name[0] == '\0') {
// An invalid attempt to open an unnamed file.
return FMOD_ERR_FILE_NOTFOUND;
}
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
PT(VirtualFile) file = vfs->get_file(Filename(name));
if (file == (VirtualFile *)NULL) {
return FMOD_ERR_FILE_NOTFOUND;
}
istream *str = file->open_read_file(true);
(*file_size) = file->get_file_size(str);
(*handle) = (void *)str;
(*user_data) = NULL;
return FMOD_OK;
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioManager::close_callback
// Access: Private, Static
// Description: A hook into Panda's virtual file system.
////////////////////////////////////////////////////////////////////
FMOD_RESULT F_CALLBACK FmodAudioManager::
close_callback(void *handle, void *user_data) {
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
istream *str = (istream *)handle;
vfs->close_read_file(str);
return FMOD_OK;
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioManager::read_callback
// Access: Private, Static
// Description: A hook into Panda's virtual file system.
////////////////////////////////////////////////////////////////////
FMOD_RESULT F_CALLBACK FmodAudioManager::
read_callback(void *handle, void *buffer, unsigned int size_bytes,
unsigned int *bytes_read, void *user_data) {
istream *str = (istream *)handle;
str->read((char *)buffer, size_bytes);
(*bytes_read) = str->gcount();
// We can't yield here, since this callback is made within a
// sub-thread--an OS-level sub-thread spawned by FMod, not a Panda
// thread.
//thread_consider_yield();
if (str->eof()) {
if ((*bytes_read) == 0) {
return FMOD_ERR_FILE_EOF;
} else {
// Report the EOF next time.
return FMOD_OK;
}
} if (str->fail()) {
return FMOD_ERR_FILE_BAD;
} else {
return FMOD_OK;
}
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioManager::seek_callback
// Access: Private, Static
// Description: A hook into Panda's virtual file system.
////////////////////////////////////////////////////////////////////
FMOD_RESULT F_CALLBACK FmodAudioManager::
seek_callback(void *handle, unsigned int pos, void *user_data) {
istream *str = (istream *)handle;
str->clear();
str->seekg(pos);
if (str->fail() && !str->eof()) {
return FMOD_ERR_FILE_COULDNOTSEEK;
} else {
return FMOD_OK;
}
}
#endif //]

View File

@ -164,20 +164,6 @@ class EXPCL_FMOD_AUDIO FmodAudioManager : public AudioManager {
////////////////////////////////////////////////////////////////////
private:
static FMOD_RESULT F_CALLBACK
open_callback(const char *name, int unicode, unsigned int *file_size,
void **handle, void **user_data);
static FMOD_RESULT F_CALLBACK
close_callback(void *handle, void *user_data);
static FMOD_RESULT F_CALLBACK
read_callback(void *handle, void *buffer, unsigned int size_bytes,
unsigned int *bytes_read, void *user_data);
static FMOD_RESULT F_CALLBACK
seek_callback(void *handle, unsigned int pos, void *user_data);
FMOD::DSP *make_dsp(const FilterProperties::FilterConfig &conf);
void update_dsp_chain(FMOD::DSP *head, FilterProperties *config);
virtual bool configure_filters(FilterProperties *config);

View File

@ -25,6 +25,7 @@
#include "config_audio.h"
#include "fmodAudioSound.h"
#include "string_utils.h"
#include "fileSystemInfo.h"
TypeHandle FmodAudioSound::_type_handle;
@ -71,46 +72,119 @@ FmodAudioSound(AudioManager *manager, Filename file_name, bool positional) {
_channel = 0;
_file_name = file_name;
FMOD_CREATESOUNDEXINFO *sound_info = NULL;
_file_name.set_binary();
//Get the Speaker Mode [Important for later on.]
result = _manager->_system->getSpeakerMode( &_speakermode );
fmod_audio_errcheck("_system->getSpeakerMode()", result);
// Calculate the approximate uncompressed size of the sound.
int size = file_name.get_file_size();
string ext = downcase(file_name.get_extension());
if (ext != "wav") size *= 10;
int flag = positional ? FMOD_3D : FMOD_2D;
int streamflag = (size > 250000) ? FMOD_CREATESTREAM : FMOD_CREATESAMPLE;
if (ext == "mid") {
streamflag = FMOD_CREATESTREAM;
sound_info = &_manager->_midi_info;
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
PT(VirtualFile) file = vfs->get_file(_file_name);
if (file == (VirtualFile *)NULL) {
// File not found. We will display the appropriate error message
// below.
result = FMOD_ERR_FILE_NOTFOUND;
} else {
bool preload = (fmod_audio_preload_threshold < 0) || (file->get_file_size() < fmod_audio_preload_threshold);
int flags = FMOD_SOFTWARE;
flags |= positional ? FMOD_3D : FMOD_2D;
if (sound_info->dlsname != NULL) {
audio_debug("Using DLS file " << sound_info->dlsname);
FMOD_CREATESOUNDEXINFO sound_info;
memset(&sound_info, 0, sizeof(sound_info));
sound_info.cbsize = sizeof(sound_info);
string ext = downcase(_file_name.get_extension());
if (ext == "mid") {
// Get the MIDI parameters.
memcpy(&sound_info, &_manager->_midi_info, sizeof(sound_info));
if (sound_info.dlsname != NULL) {
audio_debug("Using DLS file " << sound_info.dlsname);
}
}
const char *name_or_data = _file_name.c_str();
pvector<unsigned char> mem_buffer;
FileSystemInfo info;
if (preload) {
// Pre-read the file right now, and pass it in as a memory
// buffer. This avoids threading issues completely, because all
// of the reading happens right here.
file->read_file(mem_buffer, true);
sound_info.length = mem_buffer.size();
if (mem_buffer.size() != 0) {
name_or_data = (const char *)&mem_buffer[0];
}
flags |= FMOD_OPENMEMORY;
if (fmodAudio_cat.is_debug()) {
fmodAudio_cat.debug()
<< "Reading " << _file_name << " into memory (" << sound_info.length
<< " bytes)\n";
}
} else if (file->get_system_info(info)) {
// The file exists on disk (or it's part of a multifile that
// exists on disk), so we can have FMod read the file directly.
// This is also safe, because FMod uses its own I/O operations
// that don't involve Panda, so this can safely happen in an
// FMod thread.
name_or_data = info.get_os_file_name().c_str();
sound_info.fileoffset = (unsigned int)info.get_file_start();
sound_info.length = (unsigned int)info.get_file_size();
flags |= FMOD_CREATESTREAM;
if (fmodAudio_cat.is_debug()) {
fmodAudio_cat.debug()
<< "Streaming " << _file_name << " from disk (" << name_or_data
<< ", " << sound_info.fileoffset << ", " << sound_info.length << ")\n";
}
} else {
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
// Otherwise, if the Panda threading system is compiled in, we
// can assign callbacks to read the file through the VFS.
name_or_data = (const char *)file.p();
sound_info.length = (unsigned int)info.get_file_size();
sound_info.useropen = open_callback;
sound_info.userclose = close_callback;
sound_info.userread = read_callback;
sound_info.userseek = seek_callback;
flags |= FMOD_CREATESTREAM;
if (fmodAudio_cat.is_debug()) {
fmodAudio_cat.debug()
<< "Streaming " << _file_name << " from disk using callbacks\n";
}
#else // HAVE_THREADS && !SIMPLE_THREADS
// Without threads, we can't safely read this file.
name_or_data = "";
fmodAudio_cat.warning()
<< "Cannot stream " << _file_name << "; file is not literally on disk.\n";
#endif
}
result =
_manager->_system->createSound(name_or_data, flags, &sound_info, &_sound);
}
result = _manager->_system->createSound( file_name.c_str(), FMOD_SOFTWARE | streamflag | flag ,
sound_info, &_sound);
if (result != FMOD_OK) {
audio_error("createSound(" << file_name << "): " << FMOD_ErrorString(result));
audio_error("createSound(" << _file_name << "): " << FMOD_ErrorString(result));
// We couldn't load the sound file. Create a blank sound record
// instead.
FMOD_CREATESOUNDEXINFO sound_info;
memset(&sound_info, 0, sizeof(sound_info));
char blank_data[100];
FMOD_CREATESOUNDEXINFO exinfo;
memset(&exinfo, 0, sizeof(exinfo));
memset(blank_data, 0, sizeof(blank_data));
exinfo.cbsize = sizeof(exinfo);
exinfo.length = sizeof(blank_data);
exinfo.numchannels = 1;
exinfo.defaultfrequency = 8000;
exinfo.format = FMOD_SOUND_FORMAT_PCM16;
result = _manager->_system->createSound( blank_data, FMOD_SOFTWARE | flag | FMOD_OPENMEMORY | FMOD_OPENRAW, &exinfo, &_sound);
sound_info.cbsize = sizeof(sound_info);
sound_info.length = sizeof(blank_data);
sound_info.numchannels = 1;
sound_info.defaultfrequency = 8000;
sound_info.format = FMOD_SOUND_FORMAT_PCM16;
int flags = FMOD_SOFTWARE | FMOD_OPENMEMORY | FMOD_OPENRAW;
result = _manager->_system->createSound( blank_data, flags, &sound_info, &_sound);
fmod_audio_errcheck("createSound (blank)", result);
}
@ -157,27 +231,6 @@ play() {
start_playing();
}
////////////////////////////////////////////////////////////////////
// Function: sound_end_callback
// Access: Static
// Description: When fmod finishes playing a sound, decrements the
// reference count of the associated FmodAudioSound.
////////////////////////////////////////////////////////////////////
FMOD_RESULT F_CALLBACK sound_end_callback(FMOD_CHANNEL * channel,
FMOD_CHANNEL_CALLBACKTYPE type,
void *commanddata1,
void *commanddata2) {
if (type == FMOD_CHANNEL_CALLBACKTYPE_END) {
FMOD::Channel *fc = (FMOD::Channel *)channel;
void *userdata = NULL;
FMOD_RESULT result = fc->getUserData(&userdata);
fmod_audio_errcheck("channel->getUserData()", result);
FmodAudioSound *fsound = (FmodAudioSound*)userdata;
fsound->_self_ref = fsound;
}
return FMOD_OK;
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioSound::stop
// Access: public
@ -884,4 +937,147 @@ get_finished_event() const {
return _finished_event;
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioSound::sound_end_callback
// Access: Private, Static
// Description: When fmod finishes playing a sound, decrements the
// reference count of the associated FmodAudioSound.
////////////////////////////////////////////////////////////////////
FMOD_RESULT F_CALLBACK FmodAudioSound::
sound_end_callback(FMOD_CHANNEL * channel,
FMOD_CHANNEL_CALLBACKTYPE type,
void *commanddata1,
void *commanddata2) {
// Fortunately, this callback is made synchronously rather than
// asynchronously (it is triggered during System::update()), so we
// don't have to worry about thread-related issues here.
if (type == FMOD_CHANNEL_CALLBACKTYPE_END) {
FMOD::Channel *fc = (FMOD::Channel *)channel;
void *userdata = NULL;
FMOD_RESULT result = fc->getUserData(&userdata);
fmod_audio_errcheck("channel->getUserData()", result);
FmodAudioSound *fsound = (FmodAudioSound*)userdata;
fsound->_self_ref = fsound;
}
return FMOD_OK;
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioSound::open_callback
// Access: Private, Static
// Description: A hook into Panda's virtual file system.
////////////////////////////////////////////////////////////////////
FMOD_RESULT F_CALLBACK FmodAudioSound::
open_callback(const char *name, int, unsigned int *file_size,
void **handle, void **user_data) {
// We actually pass in the VirtualFile pointer as the "name".
VirtualFile *file = (VirtualFile *)name;
if (file == (VirtualFile *)NULL) {
return FMOD_ERR_FILE_NOTFOUND;
}
if (fmodAudio_cat.is_spam()) {
fmodAudio_cat.spam()
<< "open_callback(" << *file << ")\n";
}
istream *str = file->open_read_file(true);
(*file_size) = file->get_file_size(str);
(*handle) = (void *)str;
(*user_data) = (void *)file;
// Explicitly ref the VirtualFile since we're storing it in a void
// pointer instead of a PT(VirtualFile).
file->ref();
return FMOD_OK;
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioSound::close_callback
// Access: Private, Static
// Description: A hook into Panda's virtual file system.
////////////////////////////////////////////////////////////////////
FMOD_RESULT F_CALLBACK FmodAudioSound::
close_callback(void *handle, void *user_data) {
VirtualFile *file = (VirtualFile *)user_data;
if (fmodAudio_cat.is_spam()) {
fmodAudio_cat.spam()
<< "close_callback(" << *file << ")\n";
}
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
istream *str = (istream *)handle;
vfs->close_read_file(str);
// Explicitly unref the VirtualFile pointer.
unref_delete(file);
return FMOD_OK;
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioSound::read_callback
// Access: Private, Static
// Description: A hook into Panda's virtual file system.
////////////////////////////////////////////////////////////////////
FMOD_RESULT F_CALLBACK FmodAudioSound::
read_callback(void *handle, void *buffer, unsigned int size_bytes,
unsigned int *bytes_read, void *user_data) {
VirtualFile *file = (VirtualFile *)user_data;
if (fmodAudio_cat.is_spam()) {
fmodAudio_cat.spam()
<< "read_callback(" << *file << ", " << size_bytes << ")\n";
}
istream *str = (istream *)handle;
str->read((char *)buffer, size_bytes);
(*bytes_read) = str->gcount();
// We can't yield here, since this callback is made within a
// sub-thread--an OS-level sub-thread spawned by FMod, not a Panda
// thread. But we will only execute this code in the true-threads
// case anyway.
//thread_consider_yield();
if (str->eof()) {
if ((*bytes_read) == 0) {
return FMOD_ERR_FILE_EOF;
} else {
// Report the EOF next time.
return FMOD_OK;
}
} if (str->fail()) {
return FMOD_ERR_FILE_BAD;
} else {
return FMOD_OK;
}
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioSound::seek_callback
// Access: Private, Static
// Description: A hook into Panda's virtual file system.
////////////////////////////////////////////////////////////////////
FMOD_RESULT F_CALLBACK FmodAudioSound::
seek_callback(void *handle, unsigned int pos, void *user_data) {
VirtualFile *file = (VirtualFile *)user_data;
if (fmodAudio_cat.is_spam()) {
fmodAudio_cat.spam()
<< "seek_callback(" << *file << ", " << pos << ")\n";
}
istream *str = (istream *)handle;
str->clear();
str->seekg(pos);
if (str->fail() && !str->eof()) {
return FMOD_ERR_FILE_COULDNOTSEEK;
} else {
return FMOD_OK;
}
}
#endif //]

View File

@ -204,10 +204,26 @@ class EXPCL_FMOD_AUDIO FmodAudioSound : public AudioSound {
// other mismanagement.
PT(FmodAudioSound) _self_ref;
friend FMOD_RESULT F_CALLBACK sound_end_callback(FMOD_CHANNEL * channel,
FMOD_CHANNEL_CALLBACKTYPE type,
void *commanddata1,
void *commanddata2);
static FMOD_RESULT F_CALLBACK
sound_end_callback(FMOD_CHANNEL * channel,
FMOD_CHANNEL_CALLBACKTYPE type,
void *commanddata1,
void *commanddata2);
static FMOD_RESULT F_CALLBACK
open_callback(const char *name, int unicode, unsigned int *file_size,
void **handle, void **user_data);
static FMOD_RESULT F_CALLBACK
close_callback(void *handle, void *user_data);
static FMOD_RESULT F_CALLBACK
read_callback(void *handle, void *buffer, unsigned int size_bytes,
unsigned int *bytes_read, void *user_data);
static FMOD_RESULT F_CALLBACK
seek_callback(void *handle, unsigned int pos, void *user_data);
////////////////////////////////////////////////////////////
//These are needed for Panda's Pointer System. DO NOT ERASE!

View File

@ -23,6 +23,7 @@
encrypt_string.h \
error_utils.h \
export_dtool.h \
fileSystemInfo.h fileSystemInfo.I \
hashGeneratorBase.I hashGeneratorBase.h \
hashVal.I hashVal.h \
indirectLess.I indirectLess.h \
@ -84,6 +85,7 @@
datagramSink.cxx dcast.cxx \
encrypt_string.cxx \
error_utils.cxx \
fileSystemInfo.cxx \
hashGeneratorBase.cxx hashVal.cxx \
memoryInfo.cxx memoryUsage.cxx memoryUsagePointerCounts.cxx \
memoryUsagePointers.cxx multifile.cxx \
@ -140,6 +142,7 @@
dcast.T dcast.h \
encrypt_string.h \
error_utils.h \
fileSystemInfo.h fileSystemInfo.I \
hashGeneratorBase.I hashGeneratorBase.h \
hashVal.I hashVal.h \
indirectLess.I indirectLess.h \

View File

@ -10,6 +10,7 @@
#include "dcast.cxx"
#include "encrypt_string.cxx"
#include "error_utils.cxx"
#include "fileSystemInfo.cxx"
#include "hashGeneratorBase.cxx"
#include "hashVal.cxx"
#include "memoryInfo.cxx"

View File

@ -0,0 +1,103 @@
// Filename: fileSystemInfo.I
// Created by: drose (20Jun11)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: FileSystemInfo::Default Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE FileSystemInfo::
FileSystemInfo() :
_file_start(0),
_file_size(0)
{
}
////////////////////////////////////////////////////////////////////
// Function: FileSystemInfo::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE FileSystemInfo::
FileSystemInfo(const string &os_file_name, streampos file_start, streamsize file_size) :
_os_file_name(os_file_name),
_file_start(file_start),
_file_size(file_size)
{
}
////////////////////////////////////////////////////////////////////
// Function: FileSystemInfo::Copy Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE FileSystemInfo::
FileSystemInfo(const FileSystemInfo &copy) :
_os_file_name(copy._os_file_name),
_file_start(copy._file_start),
_file_size(copy._file_size)
{
}
////////////////////////////////////////////////////////////////////
// Function: FileSystemInfo::Copy Assignment Operator
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void FileSystemInfo::
operator = (const FileSystemInfo &copy) {
_os_file_name = copy._os_file_name;
_file_start = copy._file_start;
_file_size = copy._file_size;
}
////////////////////////////////////////////////////////////////////
// Function: FileSystemInfo::get_os_file_name
// Access: Published
// Description: Returns the os-specific filename that may be used to
// open this file.
////////////////////////////////////////////////////////////////////
INLINE const string &FileSystemInfo::
get_os_file_name() const {
return _os_file_name;
}
////////////////////////////////////////////////////////////////////
// Function: FileSystemInfo::get_file_start
// Access: Published
// Description: Returns the offset within the file at which this file
// data begins.
////////////////////////////////////////////////////////////////////
INLINE streampos FileSystemInfo::
get_file_start() const {
return _file_start;
}
////////////////////////////////////////////////////////////////////
// Function: FileSystemInfo::get_file_size
// Access: Published
// Description: Returns the number of consecutive bytes, beginning at
// get_file_start(), that correspond to this file data.
////////////////////////////////////////////////////////////////////
INLINE streamsize FileSystemInfo::
get_file_size() const {
return _file_size;
}
INLINE ostream &
operator << (ostream &out, const FileSystemInfo &info) {
info.output(out);
return out;
}

View File

@ -0,0 +1,26 @@
// Filename: fileSystemInfo.cxx
// Created by: drose (20Jun11)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "fileSystemInfo.h"
////////////////////////////////////////////////////////////////////
// Function: FileSystemInfo::output
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
void FileSystemInfo::
output(ostream &out) const {
out << "FileSystemInfo(" << _os_file_name << ", " << _file_start
<< ", " << _file_size << ")";
}

View File

@ -0,0 +1,48 @@
// Filename: fileSystemInfo.h
// Created by: drose (20Jun11)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef FILESYSTEMINFO_H
#define FILESYSTEMINFO_H
#include "pandabase.h"
////////////////////////////////////////////////////////////////////
// Class : FileSystemInfo
// Description : This class is used to return data about an actual
// file on disk by VirtualFile::get_system_info().
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS FileSystemInfo {
PUBLISHED:
INLINE FileSystemInfo();
INLINE FileSystemInfo(const string &os_file_name, streampos file_start, streamsize file_size);
INLINE FileSystemInfo(const FileSystemInfo &copy);
INLINE void operator = (const FileSystemInfo &copy);
INLINE const string &get_os_file_name() const;
INLINE streampos get_file_start() const;
INLINE streamsize get_file_size() const;
void output(ostream &out) const;
private:
string _os_file_name;
streampos _file_start;
streamsize _file_size;
};
INLINE ostream &operator << (ostream &out, const FileSystemInfo &info);
#include "fileSystemInfo.I"
#endif

View File

@ -26,6 +26,7 @@
#include "referenceCount.h"
#include "pvector.h"
#include "openSSLWrapper.h"
#include "fileSystemInfo.h"
////////////////////////////////////////////////////////////////////
// Class : Multifile

View File

@ -213,6 +213,21 @@ get_timestamp() const {
return 0;
}
////////////////////////////////////////////////////////////////////
// Function: VirtualFile::get_system_info
// Access: Published, Virtual
// Description: Populates the FileSystemInfo structure with the data
// representing where the file actually resides on disk,
// if this is knowable. Returns true if the file might
// reside on disk, and the info is populated, or false
// if it does not (or it is not known where the file
// resides), in which case the info is meaningless.
////////////////////////////////////////////////////////////////////
bool VirtualFile::
get_system_info(FileSystemInfo &info) {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: VirtualFile::close_read_file
// Access: Public

View File

@ -18,6 +18,7 @@
#include "pandabase.h"
#include "filename.h"
#include "fileSystemInfo.h"
#include "pointerTo.h"
#include "typedReferenceCount.h"
#include "ordered_vector.h"
@ -60,6 +61,8 @@ PUBLISHED:
BLOCKING virtual off_t get_file_size() const;
BLOCKING virtual time_t get_timestamp() const;
virtual bool get_system_info(FileSystemInfo &info);
public:
INLINE void set_original_filename(const Filename &filename);
bool read_file(string &result, bool auto_unwrap) const;

View File

@ -140,6 +140,21 @@ close_read_file(istream *stream) const {
}
}
////////////////////////////////////////////////////////////////////
// Function: VirtualFileMount::get_system_info
// Access: Public, Virtual
// Description: Populates the FileSystemInfo structure with the data
// representing where the file actually resides on disk,
// if this is knowable. Returns true if the file might
// reside on disk, and the info is populated, or false
// if it does not (or it is not known where the file
// resides), in which case the info is meaningless.
////////////////////////////////////////////////////////////////////
bool VirtualFileMount::
get_system_info(const Filename &file, FileSystemInfo &info) {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: VirtualFileMount::output
// Access: Public, Virtual

View File

@ -58,6 +58,7 @@ public:
virtual off_t get_file_size(const Filename &file, istream *stream) const=0;
virtual off_t get_file_size(const Filename &file) const=0;
virtual time_t get_timestamp(const Filename &file) const=0;
virtual bool get_system_info(const Filename &file, FileSystemInfo &info);
virtual bool scan_directory(vector_string &contents,
const Filename &dir) const=0;

View File

@ -171,6 +171,38 @@ get_timestamp(const Filename &file) const {
return _multifile->get_subfile_timestamp(subfile_index);
}
////////////////////////////////////////////////////////////////////
// Function: VirtualFileMountMultifile::get_system_info
// Access: Public, Virtual
// Description: Populates the FileSystemInfo structure with the data
// representing where the file actually resides on disk,
// if this is knowable. Returns true if the file might
// reside on disk, and the info is populated, or false
// if it might not (or it is not known where the file
// resides), in which case the info is meaningless.
////////////////////////////////////////////////////////////////////
bool VirtualFileMountMultifile::
get_system_info(const Filename &file, FileSystemInfo &info) {
Filename multifile_name = _multifile->get_multifile_name();
if (multifile_name.empty()) {
return false;
}
int subfile_index = _multifile->find_subfile(file);
if (subfile_index < 0) {
return false;
}
if (_multifile->is_subfile_compressed(subfile_index) ||
_multifile->is_subfile_encrypted(subfile_index)) {
return false;
}
streampos start = _multifile->get_subfile_internal_start(subfile_index);
size_t length = _multifile->get_subfile_internal_length(subfile_index);
info = FileSystemInfo(multifile_name.to_os_specific(), start, length);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: VirtualFileMountMultifile::scan_directory
// Access: Public, Virtual

View File

@ -45,6 +45,7 @@ public:
virtual off_t get_file_size(const Filename &file, istream *stream) const;
virtual off_t get_file_size(const Filename &file) const;
virtual time_t get_timestamp(const Filename &file) const;
virtual bool get_system_info(const Filename &file, FileSystemInfo &info);
virtual bool scan_directory(vector_string &contents,
const Filename &dir) const;

View File

@ -181,6 +181,23 @@ get_timestamp(const Filename &file) const {
return pathname.get_timestamp();
}
////////////////////////////////////////////////////////////////////
// Function: VirtualFileMountSystem::get_system_info
// Access: Public, Virtual
// Description: Populates the FileSystemInfo structure with the data
// representing where the file actually resides on disk,
// if this is knowable. Returns true if the file might
// reside on disk, and the info is populated, or false
// if it does not (or it is not known where the file
// resides), in which case the info is meaningless.
////////////////////////////////////////////////////////////////////
bool VirtualFileMountSystem::
get_system_info(const Filename &file, FileSystemInfo &info) {
Filename pathname(_physical_filename, file);
info = FileSystemInfo(pathname.to_os_specific(), 0, pathname.get_file_size());
return true;
}
////////////////////////////////////////////////////////////////////
// Function: VirtualFileMountSystem::scan_directory
// Access: Public, Virtual

View File

@ -39,6 +39,7 @@ public:
virtual off_t get_file_size(const Filename &file, istream *stream) const;
virtual off_t get_file_size(const Filename &file) const;
virtual time_t get_timestamp(const Filename &file) const;
virtual bool get_system_info(const Filename &file, FileSystemInfo &info);
virtual bool scan_directory(vector_string &contents,
const Filename &dir) const;

View File

@ -160,6 +160,21 @@ get_timestamp() const {
return _mount->get_timestamp(_local_filename);
}
////////////////////////////////////////////////////////////////////
// Function: VirtualFileSimple::get_system_info
// Access: Published, Virtual
// Description: Populates the FileSystemInfo structure with the data
// representing where the file actually resides on disk,
// if this is knowable. Returns true if the file might
// reside on disk, and the info is populated, or false
// if it does not (or it is not known where the file
// resides), in which case the info is meaningless.
////////////////////////////////////////////////////////////////////
bool VirtualFileSimple::
get_system_info(FileSystemInfo &info) {
return _mount->get_system_info(_local_filename, info);
}
////////////////////////////////////////////////////////////////////
// Function: VirtualFileSimple::read_file
// Access: Public, Virtual

View File

@ -46,6 +46,7 @@ PUBLISHED:
virtual off_t get_file_size(istream *stream) const;
virtual off_t get_file_size() const;
virtual time_t get_timestamp() const;
virtual bool get_system_info(FileSystemInfo &info);
public:
virtual bool read_file(pvector<unsigned char> &result, bool auto_unwrap) const;