mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
c++-based patching, almost working
This commit is contained in:
parent
83e6ecc1a4
commit
3771d613ad
@ -48,6 +48,7 @@
|
||||
p3dObject.h p3dObject.I \
|
||||
p3dOsxSplashWindow.h p3dOsxSplashWindow.I \
|
||||
p3dPackage.h p3dPackage.I \
|
||||
p3dPatchfileReader.h p3dPatchfileReader.I \
|
||||
p3dPatchFinder.h p3dPatchFinder.I \
|
||||
p3dPythonObject.h \
|
||||
p3dReferenceCount.h p3dReferenceCount.I \
|
||||
@ -82,6 +83,7 @@
|
||||
p3dObject.cxx \
|
||||
p3dOsxSplashWindow.cxx \
|
||||
p3dPackage.cxx \
|
||||
p3dPatchfileReader.cxx \
|
||||
p3dPatchFinder.cxx \
|
||||
p3dPythonObject.cxx \
|
||||
p3dReferenceCount.cxx \
|
||||
|
@ -288,14 +288,37 @@ read_hash(const string &pathname) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FileSpec::compare_hash
|
||||
// Function: FileSpec::read_hash_stream
|
||||
// Access: Public
|
||||
// Description: Returns true if this hash sorts before the other
|
||||
// hash, false otherwise.
|
||||
// Description: Reads the hash from the next 16 bytes on the
|
||||
// indicated istream, in the same unusual order observed
|
||||
// by Panda's HashVal::read_stream() method.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool FileSpec::
|
||||
read_hash_stream(istream &in) {
|
||||
for (int i = 0; i < hash_size; i += 4) {
|
||||
unsigned int a = in.get();
|
||||
unsigned int b = in.get();
|
||||
unsigned int c = in.get();
|
||||
unsigned int d = in.get();
|
||||
_hash[i + 0] = d;
|
||||
_hash[i + 1] = c;
|
||||
_hash[i + 2] = b;
|
||||
_hash[i + 3] = a;
|
||||
}
|
||||
|
||||
return !in.fail();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FileSpec::compare_hash
|
||||
// Access: Public
|
||||
// Description: Returns < 0 if this hash sorts before the other
|
||||
// hash, > 0 if it sorts after, 0 if they are the same.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int FileSpec::
|
||||
compare_hash(const FileSpec &other) const {
|
||||
return memcmp(_hash, other._hash, hash_size) < 0;
|
||||
return memcmp(_hash, other._hash, hash_size);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -46,7 +46,8 @@ public:
|
||||
|
||||
bool check_hash(const string &pathname) const;
|
||||
bool read_hash(const string &pathname);
|
||||
bool compare_hash(const FileSpec &other) const;
|
||||
bool read_hash_stream(istream &in);
|
||||
int compare_hash(const FileSpec &other) const;
|
||||
|
||||
void write(ostream &out) const;
|
||||
void output_hash(ostream &out) const;
|
||||
|
@ -726,8 +726,8 @@ build_install_plans(TiXmlDocument *doc) {
|
||||
return;
|
||||
}
|
||||
|
||||
_install_plans.push_back(InstallPlan());
|
||||
InstallPlan &plan = _install_plans.back();
|
||||
_install_plans.push_front(InstallPlan());
|
||||
InstallPlan &plan = _install_plans.front();
|
||||
|
||||
bool needs_redownload = false;
|
||||
|
||||
@ -745,7 +745,8 @@ build_install_plans(TiXmlDocument *doc) {
|
||||
|
||||
// Uncompress the compressed archive to generate the uncompressed
|
||||
// archive.
|
||||
step = new InstallStepUncompressFile(this, _compressed_archive, _uncompressed_archive);
|
||||
step = new InstallStepUncompressFile
|
||||
(this, _compressed_archive, _uncompressed_archive, true);
|
||||
plan.push_back(step);
|
||||
}
|
||||
|
||||
@ -775,9 +776,40 @@ build_install_plans(TiXmlDocument *doc) {
|
||||
P3DPatchFinder patch_finder;
|
||||
P3DPatchFinder::Patchfiles chain;
|
||||
if (patch_finder.get_patch_chain_to_current(chain, doc, *on_disk_ptr)) {
|
||||
cerr << "got patch chain of length " << chain.size() << "\n";
|
||||
} else {
|
||||
cerr << "No patch chain possible.\n";
|
||||
nout << "Got patch chain of length " << chain.size() << "\n";
|
||||
|
||||
// OK, we can create a plan to download and apply the patches.
|
||||
_install_plans.push_front(InstallPlan());
|
||||
InstallPlan &plan = _install_plans.front();
|
||||
|
||||
P3DPatchFinder::Patchfiles::iterator pi;
|
||||
for (pi = chain.begin(); pi != chain.end(); ++pi) {
|
||||
P3DPatchFinder::Patchfile *patchfile = (*pi);
|
||||
|
||||
// Download the patchfile
|
||||
step = new InstallStepDownloadFile(this, patchfile->_file);
|
||||
plan.push_back(step);
|
||||
|
||||
// Uncompress it
|
||||
FileSpec new_file = patchfile->_file;
|
||||
string new_filename = new_file.get_filename();
|
||||
size_t dot = new_filename.rfind('.');
|
||||
assert(new_filename.substr(dot) == ".pz");
|
||||
new_filename = new_filename.substr(0, dot);
|
||||
new_file.set_filename(new_filename);
|
||||
step = new InstallStepUncompressFile
|
||||
(this, patchfile->_file, new_file, false);
|
||||
plan.push_back(step);
|
||||
|
||||
// And apply it
|
||||
FileSpec source_file = patchfile->_source_file;
|
||||
FileSpec target_file = patchfile->_target_file;
|
||||
source_file.set_filename(_uncompressed_archive.get_filename());
|
||||
target_file.set_filename(_uncompressed_archive.get_filename());
|
||||
step = new InstallStepApplyPatch
|
||||
(this, new_file, source_file, target_file);
|
||||
plan.push_back(step);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -818,6 +850,9 @@ follow_install_plans(bool download_finished) {
|
||||
_current_step_effort = step->get_effort();
|
||||
|
||||
InstallToken token = step->do_step(download_finished);
|
||||
nout << step << ":";
|
||||
step->output(nout);
|
||||
nout << " returned " << token << "\n";
|
||||
switch (token) {
|
||||
case IT_step_failed:
|
||||
// This plan has failed.
|
||||
@ -845,6 +880,7 @@ follow_install_plans(bool download_finished) {
|
||||
}
|
||||
|
||||
// That plan failed. Go on to the next plan.
|
||||
nout << "Plan failed.\n";
|
||||
_install_plans.pop_front();
|
||||
}
|
||||
|
||||
@ -1252,6 +1288,17 @@ do_step(bool download_finished) {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPackage::InstallStepDownloadFile::output
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DPackage::InstallStepDownloadFile::
|
||||
output(ostream &out) {
|
||||
out << "InstallStepDownloadFile(" << _package->get_package_name()
|
||||
<< ", " << _file.get_filename() << ")";
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPackage::InstallStepUncompressFile::Constructor
|
||||
@ -1260,10 +1307,11 @@ do_step(bool download_finished) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DPackage::InstallStepUncompressFile::
|
||||
InstallStepUncompressFile(P3DPackage *package, const FileSpec &source,
|
||||
const FileSpec &target) :
|
||||
const FileSpec &target, bool verify_target) :
|
||||
InstallStep(package, target.get_size(), _uncompress_factor),
|
||||
_source(source),
|
||||
_target(target)
|
||||
_target(target),
|
||||
_verify_target(verify_target)
|
||||
{
|
||||
}
|
||||
|
||||
@ -1373,7 +1421,7 @@ do_step(bool download_finished) {
|
||||
source.close();
|
||||
target.close();
|
||||
|
||||
if (!_target.full_verify(_package->get_package_dir())) {
|
||||
if (_verify_target && !_target.full_verify(_package->get_package_dir())) {
|
||||
nout << "after uncompressing " << target_pathname
|
||||
<< ", failed hash check\n";
|
||||
return IT_step_failed;
|
||||
@ -1392,6 +1440,17 @@ do_step(bool download_finished) {
|
||||
return IT_step_complete;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPackage::InstallStepUncompressFile::output
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DPackage::InstallStepUncompressFile::
|
||||
output(ostream &out) {
|
||||
out << "InstallStepUncompressFile(" << _package->get_package_name()
|
||||
<< ", " << _source.get_filename() << ", " << _target.get_filename()
|
||||
<< ", " << _verify_target << ")";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPackage::InstallStepUnpackArchive::Constructor
|
||||
@ -1426,3 +1485,65 @@ do_step(bool download_finished) {
|
||||
return IT_step_complete;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPackage::InstallStepUnpackArchive::output
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DPackage::InstallStepUnpackArchive::
|
||||
output(ostream &out) {
|
||||
out << "InstallStepUnpackArchive(" << _package->get_package_name() << ")";
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPackage::InstallStepApplyPatch::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DPackage::InstallStepApplyPatch::
|
||||
InstallStepApplyPatch(P3DPackage *package, const FileSpec &patchfile,
|
||||
const FileSpec &source, const FileSpec &target) :
|
||||
InstallStep(package, target.get_size(), _patch_factor),
|
||||
_reader(package->get_package_dir(), patchfile, source, target)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPackage::InstallStepApplyPatch::do_step
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DPackage::InstallToken P3DPackage::InstallStepApplyPatch::
|
||||
do_step(bool download_finished) {
|
||||
// Open the patchfile
|
||||
if (!_reader.open_read()) {
|
||||
_reader.close();
|
||||
return IT_step_failed;
|
||||
}
|
||||
|
||||
// Apply the patch.
|
||||
while (_reader.step()) {
|
||||
_bytes_done = _reader.get_bytes_written();
|
||||
report_step_progress();
|
||||
}
|
||||
|
||||
// Close and verify.
|
||||
_reader.close();
|
||||
if (!_reader.get_success()) {
|
||||
nout << "Patching failed\n";
|
||||
return IT_step_failed;
|
||||
}
|
||||
|
||||
return IT_step_complete;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPackage::InstallStepApplyPatch::output
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DPackage::InstallStepApplyPatch::
|
||||
output(ostream &out) {
|
||||
out << "InstallStepApplyPatch(" << _package->get_package_name() << ")";
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include "p3d_plugin_common.h"
|
||||
#include "p3dFileDownload.h"
|
||||
#include "p3dPatchfileReader.h"
|
||||
#include "fileSpec.h"
|
||||
#include "get_tinyxml.h"
|
||||
#include <deque>
|
||||
@ -119,6 +120,7 @@ private:
|
||||
virtual ~InstallStep();
|
||||
|
||||
virtual InstallToken do_step(bool download_finished) = 0;
|
||||
virtual void output(ostream &out) = 0;
|
||||
|
||||
inline double get_effort() const;
|
||||
inline double get_progress() const;
|
||||
@ -136,6 +138,7 @@ private:
|
||||
virtual ~InstallStepDownloadFile();
|
||||
|
||||
virtual InstallToken do_step(bool download_finished);
|
||||
virtual void output(ostream &out);
|
||||
|
||||
string _urlbase;
|
||||
string _pathname;
|
||||
@ -146,17 +149,32 @@ private:
|
||||
class InstallStepUncompressFile : public InstallStep {
|
||||
public:
|
||||
InstallStepUncompressFile(P3DPackage *package, const FileSpec &source,
|
||||
const FileSpec &target);
|
||||
const FileSpec &target, bool verify_target);
|
||||
virtual InstallToken do_step(bool download_finished);
|
||||
virtual void output(ostream &out);
|
||||
|
||||
FileSpec _source;
|
||||
FileSpec _target;
|
||||
bool _verify_target;
|
||||
};
|
||||
|
||||
class InstallStepUnpackArchive : public InstallStep {
|
||||
public:
|
||||
InstallStepUnpackArchive(P3DPackage *package, size_t unpack_size);
|
||||
virtual InstallToken do_step(bool download_finished);
|
||||
virtual void output(ostream &out);
|
||||
};
|
||||
|
||||
class InstallStepApplyPatch : public InstallStep {
|
||||
public:
|
||||
InstallStepApplyPatch(P3DPackage *package,
|
||||
const FileSpec &patchfile,
|
||||
const FileSpec &source,
|
||||
const FileSpec &target);
|
||||
virtual InstallToken do_step(bool download_finished);
|
||||
virtual void output(ostream &out);
|
||||
|
||||
P3DPatchfileReader _reader;
|
||||
};
|
||||
|
||||
typedef deque<InstallStep *> InstallPlan;
|
||||
|
@ -108,7 +108,7 @@ operator < (const PackageVersionKey &other) const {
|
||||
if (_host_url != other._host_url) {
|
||||
return _host_url < other._host_url;
|
||||
}
|
||||
return _file.compare_hash(other._file);
|
||||
return _file.compare_hash(other._file) < 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
88
direct/src/plugin/p3dPatchfileReader.I
Normal file
88
direct/src/plugin/p3dPatchfileReader.I
Normal file
@ -0,0 +1,88 @@
|
||||
// Filename: p3dPatchfileReader.I
|
||||
// Created by: drose (28Sep09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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: P3DPatchfileReader::is_open
|
||||
// Access: Public
|
||||
// Description: Returns true if the patchfile is currently open,
|
||||
// false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline bool P3DPatchfileReader::
|
||||
is_open() const {
|
||||
return _is_open;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPatchfileReader::get_bytes_written
|
||||
// Access: Public
|
||||
// Description: Returns the number of bytes written to the output
|
||||
// file so far during the patching process.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline size_t P3DPatchfileReader::
|
||||
get_bytes_written() const {
|
||||
return _bytes_written;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPatchfileReader::get_success
|
||||
// Access: Public
|
||||
// Description: Returns true if the patching process has completed
|
||||
// successfully, false if it has failed or has not yet
|
||||
// completed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline bool P3DPatchfileReader::
|
||||
get_success() const {
|
||||
return _success;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPatchfileReader::read_uint16
|
||||
// Access: Private
|
||||
// Description: Extracts an unsigned short from the patchfile.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline unsigned int P3DPatchfileReader::
|
||||
read_uint16() {
|
||||
unsigned int a = _patch_in.get();
|
||||
unsigned int b = _patch_in.get();
|
||||
return (b << 8) | a;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPatchfileReader::read_uint32
|
||||
// Access: Private
|
||||
// Description: Extracts an unsigned long from the patchfile.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline unsigned int P3DPatchfileReader::
|
||||
read_uint32() {
|
||||
unsigned int a = _patch_in.get();
|
||||
unsigned int b = _patch_in.get();
|
||||
unsigned int c = _patch_in.get();
|
||||
unsigned int d = _patch_in.get();
|
||||
return (d << 24) | (c << 16) | (b << 8) | a;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPatchfileReader::read_int32
|
||||
// Access: Private
|
||||
// Description: Extracts a signed long from the patchfile.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline int P3DPatchfileReader::
|
||||
read_int32() {
|
||||
unsigned int a = _patch_in.get();
|
||||
unsigned int b = _patch_in.get();
|
||||
unsigned int c = _patch_in.get();
|
||||
int d = _patch_in.get();
|
||||
return (d << 24) | (c << 16) | (b << 8) | a;
|
||||
}
|
264
direct/src/plugin/p3dPatchfileReader.cxx
Normal file
264
direct/src/plugin/p3dPatchfileReader.cxx
Normal file
@ -0,0 +1,264 @@
|
||||
// Filename: p3dPatchfileReader.cxx
|
||||
// Created by: drose (28Sep09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "p3dPatchfileReader.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPatchfileReader::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DPatchfileReader::
|
||||
P3DPatchfileReader(const string &package_dir, const FileSpec &patchfile,
|
||||
const FileSpec &source, const FileSpec &target) :
|
||||
_package_dir(package_dir),
|
||||
_patchfile(patchfile),
|
||||
_source(source),
|
||||
_target(target)
|
||||
{
|
||||
_is_open = false;
|
||||
_bytes_written = 0;
|
||||
_success = false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPatchfileReader::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DPatchfileReader::
|
||||
~P3DPatchfileReader() {
|
||||
close();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPatchfileReader::open_read
|
||||
// Access: Public
|
||||
// Description: Opens the named patchfile for reading, reads the
|
||||
// header, and validates the inputs. Returns true on
|
||||
// success, false otherwise. If this returns false, you
|
||||
// should immediately call close(), or let this object
|
||||
// destruct.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DPatchfileReader::
|
||||
open_read() {
|
||||
close();
|
||||
|
||||
// Synthesize an output filename, in case the source and the target
|
||||
// refer to the same filename.
|
||||
_output_pathname = _target.get_pathname(_package_dir);
|
||||
_output_pathname += ".tmp";
|
||||
|
||||
string patch_pathname = _patchfile.get_pathname(_package_dir);
|
||||
_patch_in.clear();
|
||||
_patch_in.open(patch_pathname.c_str(), ios::in | ios::binary);
|
||||
|
||||
string source_pathname = _source.get_pathname(_package_dir);
|
||||
_source_in.clear();
|
||||
_source_in.open(source_pathname.c_str(), ios::in | ios::binary);
|
||||
|
||||
mkfile_complete(_output_pathname, nout);
|
||||
_target_out.clear();
|
||||
_target_out.open(_output_pathname.c_str(), ios::out | ios::binary);
|
||||
|
||||
_is_open = true;
|
||||
|
||||
// If any of those failed to open, we fail.
|
||||
if (_patch_in.fail() || _source_in.fail() || _target_out.fail()) {
|
||||
nout << "Couldn't open patchfile source, input, and/or target.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the patchfile header and validate it against the hashes we
|
||||
// were given.
|
||||
unsigned int magic_number = read_uint32();
|
||||
if (magic_number != 0xfeebfaac) {
|
||||
nout << "Not a valid patchfile: " << patch_pathname << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int version = read_uint16();
|
||||
if (version != 2) {
|
||||
// This code only knows about patchfile version 2. If the
|
||||
// patchfile code is updated, we have to update this code
|
||||
// accordingly.
|
||||
nout << "Unsupported patchfile version: " << version << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t source_length = read_uint32();
|
||||
if (source_length != _source.get_size()) {
|
||||
nout << "Patchfile " << patch_pathname
|
||||
<< " doesn't match source size.\n";
|
||||
return false;
|
||||
}
|
||||
FileSpec validate;
|
||||
validate.read_hash_stream(_patch_in);
|
||||
if (_source.compare_hash(validate) != 0) {
|
||||
nout << "Patchfile " << patch_pathname
|
||||
<< " doesn't match source hash.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
_target_length = read_uint32();
|
||||
if (_target_length != _target.get_size()) {
|
||||
nout << "Patchfile " << patch_pathname
|
||||
<< " doesn't match target size.\n";
|
||||
return false;
|
||||
}
|
||||
validate.read_hash_stream(_patch_in);
|
||||
if (_target.compare_hash(validate) != 0) {
|
||||
nout << "Patchfile " << patch_pathname
|
||||
<< " doesn't match target hash.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPatchfileReader::step
|
||||
// Access: Public
|
||||
// Description: Performs one incremental step of the patching
|
||||
// operation. Returns true if the operation should
|
||||
// continue and step() should be called again, false if
|
||||
// the patching is done (either successfully, or due to
|
||||
// failure).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DPatchfileReader::
|
||||
step() {
|
||||
assert(_is_open);
|
||||
|
||||
size_t add_length = read_uint16();
|
||||
if (add_length != 0) {
|
||||
// Add a number of bytes from the patchfile.
|
||||
if (!copy_bytes(_patch_in, add_length)) {
|
||||
nout << "Truncated patchfile.\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
size_t copy_length = read_uint16();
|
||||
if (copy_length != 0) {
|
||||
// Copy a number of bytes from the original source.
|
||||
ssize_t offset = read_int32();
|
||||
_source_in.seekg(offset, ios::cur);
|
||||
if (!copy_bytes(_source_in, copy_length)) {
|
||||
nout << "Garbage in patchfile.\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
assert(_bytes_written <= _target_length);
|
||||
|
||||
// When both counts reach 0, the patchfile is done.
|
||||
if (add_length != 0 || copy_length != 0) {
|
||||
// So, we've still got more to do.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_bytes_written != _target_length) {
|
||||
nout << "Patchfile wrote truncated file.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the _success flag true, so close() will move the finished
|
||||
// file into place.
|
||||
_success = true;
|
||||
close();
|
||||
|
||||
// Now validate the hash.
|
||||
if (!_target.full_verify(_package_dir)) {
|
||||
nout << "After patching, " << _target.get_filename()
|
||||
<< " is still incorrect.\n";
|
||||
_success = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Successfully patched! Return false to indicate completion.
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPatchfileReader::close
|
||||
// Access: Public
|
||||
// Description: Closes the previously-opened files, and moves the
|
||||
// output file into place.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DPatchfileReader::
|
||||
close() {
|
||||
if (!_is_open) {
|
||||
return;
|
||||
}
|
||||
|
||||
_patch_in.close();
|
||||
_source_in.close();
|
||||
_target_out.close();
|
||||
|
||||
if (_success) {
|
||||
// Move the output file onto the target file.
|
||||
string target_pathname = _target.get_pathname(_package_dir);
|
||||
#ifdef _WIN32
|
||||
// Windows can't delete a file if it's read-only.
|
||||
chmod(target_pathname.c_str(), 0644);
|
||||
#endif
|
||||
unlink(target_pathname.c_str());
|
||||
rename(_output_pathname.c_str(), target_pathname.c_str());
|
||||
|
||||
} else {
|
||||
// Failure; remove the output file.
|
||||
#ifdef _WIN32
|
||||
chmod(_output_pathname.c_str(), 0644);
|
||||
#endif
|
||||
unlink(_output_pathname.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPatchfileReader::copy_bytes
|
||||
// Access: Private
|
||||
// Description: Copies the indicated number of bytes from the
|
||||
// indicated stream onto the output stream. Returns
|
||||
// true on success, false if the input stream didn't
|
||||
// have enough bytes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DPatchfileReader::
|
||||
copy_bytes(istream &in, size_t copy_byte_count) {
|
||||
static const size_t buffer_size = 8192;
|
||||
char buffer[buffer_size];
|
||||
|
||||
size_t read_size = min(copy_byte_count, buffer_size);
|
||||
in.read(buffer, read_size);
|
||||
size_t count = in.gcount();
|
||||
while (count != 0) {
|
||||
_target_out.write(buffer, count);
|
||||
_bytes_written += count;
|
||||
if (_bytes_written > _target_length) {
|
||||
nout << "Runaway patchfile.\n";
|
||||
return false;
|
||||
}
|
||||
if (count != read_size) {
|
||||
return false;
|
||||
}
|
||||
copy_byte_count -= count;
|
||||
count = 0;
|
||||
if (copy_byte_count != 0) {
|
||||
read_size = min(copy_byte_count, buffer_size);
|
||||
in.read(buffer, read_size);
|
||||
count = in.gcount();
|
||||
}
|
||||
}
|
||||
|
||||
return (copy_byte_count == 0);
|
||||
}
|
76
direct/src/plugin/p3dPatchfileReader.h
Normal file
76
direct/src/plugin/p3dPatchfileReader.h
Normal file
@ -0,0 +1,76 @@
|
||||
// Filename: p3dPatchfileReader.h
|
||||
// Created by: drose (27Sep09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 P3DPATCHFILEREADER_H
|
||||
#define P3DPATCHFILEREADER_H
|
||||
|
||||
#include "p3d_plugin_common.h"
|
||||
#include "p3dInstanceManager.h" // for openssl
|
||||
#include "fileSpec.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : P3DPatchfileReader
|
||||
// Description : A read-only implementation of Panda's patchfile
|
||||
// format, for applying patches.
|
||||
//
|
||||
// This object assumes that the sourcefile has been
|
||||
// already validated against its md5 hash, and does not
|
||||
// validate it again. It *does* verify that the md5
|
||||
// hash in source and target match those read in the
|
||||
// patchfile header; and it verifies the md5 hash on the
|
||||
// target after completion.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class P3DPatchfileReader {
|
||||
public:
|
||||
P3DPatchfileReader(const string &package_dir,
|
||||
const FileSpec &patchfile,
|
||||
const FileSpec &source,
|
||||
const FileSpec &target);
|
||||
~P3DPatchfileReader();
|
||||
|
||||
bool open_read();
|
||||
inline bool is_open() const;
|
||||
|
||||
bool step();
|
||||
inline size_t get_bytes_written() const;
|
||||
inline bool get_success() const;
|
||||
|
||||
void close();
|
||||
|
||||
private:
|
||||
bool copy_bytes(istream &in, size_t copy_byte_count);
|
||||
inline unsigned int read_uint16();
|
||||
inline unsigned int read_uint32();
|
||||
inline int read_int32();
|
||||
|
||||
private:
|
||||
string _package_dir;
|
||||
FileSpec _patchfile;
|
||||
FileSpec _source;
|
||||
FileSpec _target;
|
||||
|
||||
string _output_pathname;
|
||||
ifstream _patch_in;
|
||||
ifstream _source_in;
|
||||
ofstream _target_out;
|
||||
|
||||
bool _is_open;
|
||||
size_t _target_length;
|
||||
size_t _bytes_written;
|
||||
bool _success;
|
||||
};
|
||||
|
||||
#include "p3dPatchfileReader.I"
|
||||
|
||||
#endif
|
@ -17,6 +17,7 @@
|
||||
#include "p3dObject.cxx"
|
||||
#include "p3dOsxSplashWindow.cxx"
|
||||
#include "p3dPackage.cxx"
|
||||
#include "p3dPatchfileReader.cxx"
|
||||
#include "p3dPatchFinder.cxx"
|
||||
#include "p3dPythonObject.cxx"
|
||||
#include "p3dReferenceCount.cxx"
|
||||
|
Loading…
x
Reference in New Issue
Block a user