mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 02:42:49 -04:00
794 lines
24 KiB
C++
Executable File
794 lines
24 KiB
C++
Executable File
// Filename: p3dPackage.cxx
|
|
// Created by: drose (12Jun09)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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 "p3dPackage.h"
|
|
#include "p3dInstanceManager.h"
|
|
#include "p3dInstance.h"
|
|
#include "p3dMultifileReader.h"
|
|
#include "mkdir_complete.h"
|
|
|
|
#include "zlib.h"
|
|
|
|
#include <algorithm>
|
|
#include <fstream>
|
|
|
|
// The relative breakdown of the full install process. Each phase is
|
|
// worth this fraction of the total movement of the progress bar.
|
|
static const double download_portion = 0.9;
|
|
static const double uncompress_portion = 0.05;
|
|
static const double extract_portion = 0.05;
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DPackage::Constructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
P3DPackage::
|
|
P3DPackage(const string &package_name,
|
|
const string &package_platform,
|
|
const string &package_version) :
|
|
_package_name(package_name),
|
|
_package_platform(package_platform),
|
|
_package_version(package_version)
|
|
{
|
|
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
|
|
|
_package_fullname = _package_name;
|
|
_package_dir = inst_mgr->get_root_dir() + string("/packages/") + _package_name;
|
|
if (!_package_platform.empty()) {
|
|
_package_fullname += string("_") + _package_platform;
|
|
_package_dir += string("/") + _package_platform;
|
|
}
|
|
_package_fullname += string("_") + _package_version;
|
|
_package_dir += string("/") + _package_version;
|
|
|
|
_info_ready = false;
|
|
_download_size = 0;
|
|
_allow_data_download = false;
|
|
_ready = false;
|
|
_failed = false;
|
|
_active_download = NULL;
|
|
_partial_download = false;
|
|
|
|
// Ensure the package directory exists; create it if it does not.
|
|
mkdir_complete(_package_dir, nout);
|
|
|
|
_desc_file_basename = _package_fullname + ".xml";
|
|
_desc_file_pathname = _package_dir + "/" + _desc_file_basename;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DPackage::Destructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
P3DPackage::
|
|
~P3DPackage() {
|
|
// Tell any pending callbacks that we're no good any more.
|
|
report_done(false);
|
|
|
|
// Cancel any pending download.
|
|
if (_active_download != NULL) {
|
|
_active_download->cancel();
|
|
delete _active_download;
|
|
_active_download = NULL;
|
|
}
|
|
|
|
assert(_instances.empty());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DPackage::add_instance
|
|
// Access: Public
|
|
// Description: Specifies an instance that may be responsible for
|
|
// downloading this package.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DPackage::
|
|
add_instance(P3DInstance *inst) {
|
|
_instances.push_back(inst);
|
|
|
|
begin_info_download();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DPackage::remove_instance
|
|
// Access: Public
|
|
// Description: Indicates that the given instance will no longer be
|
|
// responsible for downloading this package.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DPackage::
|
|
remove_instance(P3DInstance *inst) {
|
|
assert(!_instances.empty());
|
|
|
|
if (inst == _instances[0]) {
|
|
// This was the primary instance. Cancel any pending download and
|
|
// move to the next instance.
|
|
if (_active_download != NULL) {
|
|
_active_download->cancel();
|
|
delete _active_download;
|
|
_active_download = NULL;
|
|
}
|
|
}
|
|
|
|
Instances::iterator ii = find(_instances.begin(), _instances.end(), inst);
|
|
assert(ii != _instances.end());
|
|
_instances.erase(ii);
|
|
|
|
begin_info_download();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DPackage::begin_info_download
|
|
// Access: Private
|
|
// Description: Begins downloading and installing the information
|
|
// about the package, including its file size and
|
|
// download source and such, if needed. This is
|
|
// generally a very small download.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DPackage::
|
|
begin_info_download() {
|
|
if (_instances.empty()) {
|
|
// Can't download without any instances.
|
|
return;
|
|
}
|
|
|
|
if (_info_ready) {
|
|
// Already downloaded.
|
|
return;
|
|
}
|
|
|
|
if (_active_download != NULL) {
|
|
// In the middle of downloading.
|
|
return;
|
|
}
|
|
|
|
download_contents_file();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DPackage::download_contents_file
|
|
// Access: Private
|
|
// Description: Starts downloading the root-level contents.xml file.
|
|
// This is only done for the first package, and only if
|
|
// the instance manager doesn't have the file already.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DPackage::
|
|
download_contents_file() {
|
|
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
|
|
|
if (inst_mgr->has_contents_file()) {
|
|
// We've already got a contents.xml file; go straight to the
|
|
// package desc file.
|
|
download_desc_file();
|
|
return;
|
|
}
|
|
|
|
string url = inst_mgr->get_download_url();
|
|
url += "contents.xml";
|
|
|
|
// Download contents.xml to a temporary filename first, in case
|
|
// multiple packages are downloading it simultaneously.
|
|
_contents_file_pathname = tempnam(NULL, "p3d_");
|
|
|
|
cerr << "starting contents download\n";
|
|
start_download(DT_contents_file, url, _contents_file_pathname, false);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DPackage::contents_file_download_finished
|
|
// Access: Private
|
|
// Description: Called when the desc file has been fully downloaded.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DPackage::
|
|
contents_file_download_finished(bool success) {
|
|
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
|
cerr << "done contents download: " << success
|
|
<< ", has_contents = " << inst_mgr->has_contents_file()
|
|
<< "\n";
|
|
|
|
if (!inst_mgr->has_contents_file()) {
|
|
if (!success || !inst_mgr->read_contents_file(_contents_file_pathname)) {
|
|
nout << "Couldn't read " << _contents_file_pathname << "\n";
|
|
|
|
// Maybe we can read an already-downloaded contents.xml file.
|
|
string standard_filename = inst_mgr->get_root_dir() + "/contents.xml";
|
|
if (!inst_mgr->read_contents_file(standard_filename)) {
|
|
// Couldn't even read that. Fail.
|
|
report_done(false);
|
|
unlink(_contents_file_pathname.c_str());
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// The file is correctly installed by now; we can remove the
|
|
// temporary file.
|
|
unlink(_contents_file_pathname.c_str());
|
|
|
|
download_desc_file();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DPackage::download_desc_file
|
|
// Access: Private
|
|
// Description: Starts downloading the desc file for the package.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DPackage::
|
|
download_desc_file() {
|
|
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
|
|
|
// Attempt to check the desc file for freshness. If it already
|
|
// exists, and is consistent with the server contents file, we don't
|
|
// need to re-download it.
|
|
string root_dir = inst_mgr->get_root_dir() + "/packages";
|
|
FileSpec desc_file;
|
|
if (!inst_mgr->get_package_desc_file(desc_file, _package_name, _package_version)) {
|
|
nout << "Couldn't find package " << _package_fullname
|
|
<< " in contents file.\n";
|
|
|
|
} else if (desc_file.get_pathname(root_dir) != _desc_file_pathname) {
|
|
nout << "Wrong pathname for desc file: "
|
|
<< desc_file.get_pathname(root_dir)
|
|
<< " instead of " << _desc_file_pathname << "\n";
|
|
|
|
} else if (!desc_file.full_verify(root_dir)) {
|
|
nout << _desc_file_pathname << " is stale.\n";
|
|
|
|
} else {
|
|
// The desc file is current. Attempt to read it.
|
|
TiXmlDocument doc(_desc_file_pathname.c_str());
|
|
if (doc.LoadFile()) {
|
|
got_desc_file(&doc, false);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// The desc file is not current. Go download it.
|
|
string url = inst_mgr->get_download_url();
|
|
url += _package_name;
|
|
if (!_package_platform.empty()) {
|
|
url += "/" + _package_platform;
|
|
}
|
|
url += "/" + _package_version;
|
|
url += "/" + _desc_file_basename;
|
|
|
|
start_download(DT_desc_file, url, _desc_file_pathname, false);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DPackage::desc_file_download_finished
|
|
// Access: Private
|
|
// Description: Called when the desc file has been fully downloaded.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DPackage::
|
|
desc_file_download_finished(bool success) {
|
|
if (!success) {
|
|
report_done(false);
|
|
return;
|
|
}
|
|
|
|
TiXmlDocument doc(_desc_file_pathname.c_str());
|
|
if (!doc.LoadFile()) {
|
|
nout << "Couldn't read " << _desc_file_pathname << "\n";
|
|
report_done(false);
|
|
return;
|
|
}
|
|
|
|
got_desc_file(&doc, true);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DPackage::got_desc_file
|
|
// Access: Private
|
|
// Description: Reads the desc file and begins verifying the files.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DPackage::
|
|
got_desc_file(TiXmlDocument *doc, bool freshly_downloaded) {
|
|
TiXmlElement *xpackage = doc->FirstChildElement("package");
|
|
TiXmlElement *uncompressed_archive = NULL;
|
|
TiXmlElement *compressed_archive = NULL;
|
|
|
|
if (xpackage != NULL) {
|
|
const char *display_name_cstr = xpackage->Attribute("display_name");
|
|
if (display_name_cstr != NULL) {
|
|
_package_display_name = display_name_cstr;
|
|
}
|
|
|
|
uncompressed_archive = xpackage->FirstChildElement("uncompressed_archive");
|
|
compressed_archive = xpackage->FirstChildElement("compressed_archive");
|
|
}
|
|
|
|
if (uncompressed_archive == NULL || compressed_archive == NULL) {
|
|
// The desc file didn't include the archive file itself, weird.
|
|
if (!freshly_downloaded) {
|
|
download_desc_file();
|
|
return;
|
|
}
|
|
report_done(false);
|
|
return;
|
|
}
|
|
|
|
_uncompressed_archive.load_xml(uncompressed_archive);
|
|
_compressed_archive.load_xml(compressed_archive);
|
|
|
|
// Now get all the extractable components.
|
|
_extracts.clear();
|
|
TiXmlElement *extract = xpackage->FirstChildElement("extract");
|
|
while (extract != NULL) {
|
|
FileSpec file;
|
|
file.load_xml(extract);
|
|
_extracts.push_back(file);
|
|
extract = extract->NextSiblingElement("extract");
|
|
}
|
|
|
|
// Verify all of the extracts.
|
|
bool all_extracts_ok = true;
|
|
Extracts::iterator ci;
|
|
for (ci = _extracts.begin(); ci != _extracts.end(); ++ci) {
|
|
if (!(*ci).quick_verify(_package_dir)) {
|
|
nout << "File is incorrect: " << (*ci).get_filename() << "\n";
|
|
all_extracts_ok = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (all_extracts_ok) {
|
|
// Great, we're ready to begin.
|
|
nout << "All " << _extracts.size() << " extracts of " << _package_name
|
|
<< " seem good.\n";
|
|
report_done(true);
|
|
|
|
} else {
|
|
// We need to get the file data still, but at least we know all
|
|
// about it by this point.
|
|
if (!_allow_data_download) {
|
|
// Not authorized to start downloading yet; just report that
|
|
// we're ready.
|
|
report_info_ready();
|
|
} else {
|
|
// We've already been authorized to start downloading, so do it.
|
|
begin_data_download();
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DPackage::begin_data_download
|
|
// Access: Private
|
|
// Description: Begins downloading and installing the package data
|
|
// itself, if needed.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DPackage::
|
|
begin_data_download() {
|
|
if (_instances.empty()) {
|
|
// Can't download without any instances.
|
|
return;
|
|
}
|
|
|
|
if (_ready) {
|
|
// Already downloaded.
|
|
return;
|
|
}
|
|
|
|
if (_active_download != NULL) {
|
|
// In the middle of downloading.
|
|
return;
|
|
}
|
|
|
|
if (!_allow_data_download) {
|
|
// Not authorized yet.
|
|
return;
|
|
}
|
|
|
|
if (_uncompressed_archive.quick_verify(_package_dir)) {
|
|
// We need to re-extract the archive.
|
|
extract_archive();
|
|
|
|
} else if (_compressed_archive.quick_verify(_package_dir)) {
|
|
// We need to uncompress the archive.
|
|
uncompress_archive();
|
|
|
|
} else {
|
|
// Shoot, we need to download the archive.
|
|
download_compressed_archive(true);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DPackage::download_compressed_archive
|
|
// Access: Private
|
|
// Description: Starts downloading the archive file for the package.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DPackage::
|
|
download_compressed_archive(bool allow_partial) {
|
|
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
|
string url = inst_mgr->get_download_url();
|
|
url += _package_name;
|
|
if (!_package_platform.empty()) {
|
|
url += "/" + _package_platform;
|
|
}
|
|
url += "/" + _package_version;
|
|
url += "/" + _compressed_archive.get_filename();
|
|
|
|
string target_pathname = _package_dir + "/" + _compressed_archive.get_filename();
|
|
|
|
start_download(DT_compressed_archive, url, target_pathname, allow_partial);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DPackage::compressed_archive_download_progress
|
|
// Access: Private
|
|
// Description: Called as the file is downloaded.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DPackage::
|
|
compressed_archive_download_progress(double progress) {
|
|
report_progress(download_portion * progress);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DPackage::compressed_archive_download_finished
|
|
// Access: Private
|
|
// Description: Called when the desc file has been fully downloaded.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DPackage::
|
|
compressed_archive_download_finished(bool success) {
|
|
if (!success) {
|
|
report_done(false);
|
|
return;
|
|
}
|
|
|
|
if (_compressed_archive.full_verify(_package_dir)) {
|
|
// Go on to uncompress the archive.
|
|
uncompress_archive();
|
|
return;
|
|
}
|
|
|
|
// Oof, didn't download it correctly.
|
|
if (_partial_download) {
|
|
// Go back and get the whole file this time.
|
|
download_compressed_archive(false);
|
|
}
|
|
|
|
nout << _compressed_archive.get_filename()
|
|
<< " failed hash check after download\n";
|
|
report_done(false);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DPackage::uncompress_archive
|
|
// Access: Private
|
|
// Description: Uncompresses the archive file.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DPackage::
|
|
uncompress_archive() {
|
|
string source_pathname = _package_dir + "/" + _compressed_archive.get_filename();
|
|
string target_pathname = _package_dir + "/" + _uncompressed_archive.get_filename();
|
|
|
|
ifstream source(source_pathname.c_str(), ios::in | ios::binary);
|
|
if (!source) {
|
|
nout << "Couldn't open " << source_pathname << "\n";
|
|
report_done(false);
|
|
return;
|
|
}
|
|
|
|
if (!mkfile_complete(target_pathname, nout)) {
|
|
report_done(false);
|
|
return;
|
|
}
|
|
|
|
ofstream target(target_pathname.c_str(), ios::out | ios::binary);
|
|
if (!target) {
|
|
nout << "Couldn't write to " << target_pathname << "\n";
|
|
report_done(false);
|
|
return;
|
|
}
|
|
|
|
static const int decompress_buffer_size = 81920;
|
|
char decompress_buffer[decompress_buffer_size];
|
|
static const int write_buffer_size = 81920;
|
|
char write_buffer[write_buffer_size];
|
|
|
|
z_stream z;
|
|
z.next_in = Z_NULL;
|
|
z.avail_in = 0;
|
|
z.next_out = Z_NULL;
|
|
z.avail_out = 0;
|
|
z.zalloc = Z_NULL;
|
|
z.zfree = Z_NULL;
|
|
z.opaque = Z_NULL;
|
|
z.msg = (char *)"no error message";
|
|
|
|
bool eof = false;
|
|
int flush = 0;
|
|
|
|
source.read(decompress_buffer, decompress_buffer_size);
|
|
size_t read_count = source.gcount();
|
|
eof = (read_count == 0 || source.eof() || source.fail());
|
|
|
|
z.next_in = (Bytef *)decompress_buffer;
|
|
z.avail_in = read_count;
|
|
|
|
int result = inflateInit(&z);
|
|
if (result < 0) {
|
|
nout << z.msg << "\n";
|
|
report_done(false);
|
|
return;
|
|
}
|
|
|
|
size_t total_out = 0;
|
|
while (true) {
|
|
if (z.avail_in == 0 && !eof) {
|
|
source.read(decompress_buffer, decompress_buffer_size);
|
|
size_t read_count = source.gcount();
|
|
eof = (read_count == 0 || source.eof() || source.fail());
|
|
|
|
z.next_in = (Bytef *)decompress_buffer;
|
|
z.avail_in = read_count;
|
|
}
|
|
|
|
z.next_out = (Bytef *)write_buffer;
|
|
z.avail_out = write_buffer_size;
|
|
int result = inflate(&z, flush);
|
|
if (z.avail_out < write_buffer_size) {
|
|
target.write(write_buffer, write_buffer_size - z.avail_out);
|
|
if (!target) {
|
|
nout << "Couldn't write entire file to " << target_pathname << "\n";
|
|
report_done(false);
|
|
return;
|
|
}
|
|
total_out += (write_buffer_size - z.avail_out);
|
|
if (_uncompressed_archive.get_size() != 0) {
|
|
double progress = (double)total_out / (double)_uncompressed_archive.get_size();
|
|
progress = min(progress, 1.0);
|
|
report_progress(download_portion + uncompress_portion * progress);
|
|
}
|
|
}
|
|
|
|
if (result == Z_STREAM_END) {
|
|
// Here's the end of the file.
|
|
break;
|
|
|
|
} else if (result == Z_BUF_ERROR && flush == 0) {
|
|
// We might get this if no progress is possible, for instance if
|
|
// the input stream is truncated. In this case, tell zlib to
|
|
// dump everything it's got.
|
|
flush = Z_FINISH;
|
|
|
|
} else if (result < 0) {
|
|
nout << z.msg << "\n";
|
|
inflateEnd(&z);
|
|
report_done(false);
|
|
return;
|
|
}
|
|
}
|
|
|
|
result = inflateEnd(&z);
|
|
if (result < 0) {
|
|
nout << z.msg << "\n";
|
|
report_done(false);
|
|
return;
|
|
}
|
|
|
|
source.close();
|
|
target.close();
|
|
|
|
if (!_uncompressed_archive.full_verify(_package_dir)) {
|
|
nout << "after uncompressing " << target_pathname
|
|
<< ", failed hash check\n";
|
|
report_done(false);
|
|
return;
|
|
}
|
|
|
|
unlink(source_pathname.c_str());
|
|
|
|
// All done uncompressing.
|
|
extract_archive();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DPackage::extract_archive
|
|
// Access: Private
|
|
// Description: Extracts the components from the archive file.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DPackage::
|
|
extract_archive() {
|
|
string source_pathname = _package_dir + "/" + _uncompressed_archive.get_filename();
|
|
P3DMultifileReader reader;
|
|
if (!reader.extract_all(source_pathname, _package_dir,
|
|
this, download_portion + uncompress_portion, extract_portion)) {
|
|
nout << "Failure extracting " << _uncompressed_archive.get_filename()
|
|
<< "\n";
|
|
report_done(false);
|
|
return;
|
|
}
|
|
|
|
report_done(true);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DPackage::report_progress
|
|
// Access: Private
|
|
// Description: Reports the indicated install progress to all
|
|
// interested instances.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DPackage::
|
|
report_progress(double progress) {
|
|
Instances::iterator ii;
|
|
for (ii = _instances.begin(); ii != _instances.end(); ++ii) {
|
|
(*ii)->report_package_progress(this, progress);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DPackage::report_info_ready
|
|
// Access: Private
|
|
// Description: Called when the package information has been
|
|
// successfully downloaded but activate_download() has
|
|
// not yet been called, and the package is now idle,
|
|
// waiting for activate_download() to be called.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DPackage::
|
|
report_info_ready() {
|
|
_info_ready = true;
|
|
_download_size = _compressed_archive.get_size();
|
|
|
|
Instances::iterator ii;
|
|
for (ii = _instances.begin(); ii != _instances.end(); ++ii) {
|
|
(*ii)->report_package_info_ready(this);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DPackage::report_done
|
|
// Access: Private
|
|
// Description: Transitions the package to "ready" or "failure"
|
|
// state, and reports this change to all the interested
|
|
// instances.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DPackage::
|
|
report_done(bool success) {
|
|
if (success) {
|
|
_info_ready = true;
|
|
_ready = true;
|
|
_failed = false;
|
|
} else {
|
|
_ready = false;
|
|
_failed = true;
|
|
}
|
|
|
|
if (!_allow_data_download && success) {
|
|
// If we haven't been authorized to start downloading yet, just
|
|
// report that we're ready to start, but that we don't have to
|
|
// download anything.
|
|
_download_size = 0;
|
|
Instances::iterator ii;
|
|
for (ii = _instances.begin(); ii != _instances.end(); ++ii) {
|
|
(*ii)->report_package_info_ready(this);
|
|
}
|
|
|
|
} else {
|
|
// Otherwise, we can report that we're fully downloaded.
|
|
Instances::iterator ii;
|
|
for (ii = _instances.begin(); ii != _instances.end(); ++ii) {
|
|
(*ii)->report_package_done(this, success);
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DPackage::start_download
|
|
// Access: Private
|
|
// Description: Initiates a download of the indicated file.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DPackage::
|
|
start_download(P3DPackage::DownloadType dtype, const string &url,
|
|
const string &pathname, bool allow_partial) {
|
|
// Only one download should be active at a time
|
|
assert(_active_download == NULL);
|
|
|
|
if (!allow_partial) {
|
|
unlink(pathname.c_str());
|
|
}
|
|
|
|
Download *download = new Download(this, dtype);
|
|
download->set_url(url);
|
|
download->set_filename(pathname);
|
|
|
|
// TODO: implement partial file re-download.
|
|
allow_partial = false;
|
|
|
|
_active_download = download;
|
|
_partial_download = false;
|
|
|
|
assert(!_instances.empty());
|
|
|
|
_instances[0]->start_download(download);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DPackage::is_extractable
|
|
// Access: Private
|
|
// Description: Returns true if the name file is on the extract list,
|
|
// false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool P3DPackage::
|
|
is_extractable(const string &filename) const {
|
|
Extracts::const_iterator ci;
|
|
for (ci = _extracts.begin(); ci != _extracts.end(); ++ci) {
|
|
if ((*ci).get_filename() == filename) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DPackage::Download::Constructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
P3DPackage::Download::
|
|
Download(P3DPackage *package, DownloadType dtype) :
|
|
_package(package),
|
|
_dtype(dtype)
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DPackage::Download::download_progress
|
|
// Access: Protected, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DPackage::Download::
|
|
download_progress() {
|
|
P3DFileDownload::download_progress();
|
|
assert(_package->_active_download == this);
|
|
|
|
switch (_dtype) {
|
|
case DT_desc_file:
|
|
break;
|
|
|
|
case DT_compressed_archive:
|
|
_package->compressed_archive_download_progress(get_download_progress());
|
|
break;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DPackage::Download::download_finished
|
|
// Access: Protected, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DPackage::Download::
|
|
download_finished(bool success) {
|
|
P3DFileDownload::download_finished(success);
|
|
assert(_package->_active_download == this);
|
|
_package->_active_download = NULL;
|
|
|
|
switch (_dtype) {
|
|
case DT_contents_file:
|
|
_package->contents_file_download_finished(success);
|
|
break;
|
|
|
|
case DT_desc_file:
|
|
_package->desc_file_download_finished(success);
|
|
break;
|
|
|
|
case DT_compressed_archive:
|
|
_package->compressed_archive_download_finished(success);
|
|
break;
|
|
}
|
|
}
|