From 3771d613ad7c0a848a1481ac45d4a195ed400fb3 Mon Sep 17 00:00:00 2001 From: David Rose Date: Mon, 28 Sep 2009 15:55:37 +0000 Subject: [PATCH] c++-based patching, almost working --- direct/src/plugin/Sources.pp | 2 + direct/src/plugin/fileSpec.cxx | 31 ++- direct/src/plugin/fileSpec.h | 3 +- direct/src/plugin/p3dPackage.cxx | 139 ++++++++++- direct/src/plugin/p3dPackage.h | 20 +- direct/src/plugin/p3dPatchFinder.cxx | 2 +- direct/src/plugin/p3dPatchfileReader.I | 88 +++++++ direct/src/plugin/p3dPatchfileReader.cxx | 264 ++++++++++++++++++++ direct/src/plugin/p3dPatchfileReader.h | 76 ++++++ direct/src/plugin/p3d_plugin_composite1.cxx | 1 + 10 files changed, 610 insertions(+), 16 deletions(-) create mode 100644 direct/src/plugin/p3dPatchfileReader.I create mode 100644 direct/src/plugin/p3dPatchfileReader.cxx create mode 100644 direct/src/plugin/p3dPatchfileReader.h diff --git a/direct/src/plugin/Sources.pp b/direct/src/plugin/Sources.pp index bf96fdb097..a855f66d17 100644 --- a/direct/src/plugin/Sources.pp +++ b/direct/src/plugin/Sources.pp @@ -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 \ diff --git a/direct/src/plugin/fileSpec.cxx b/direct/src/plugin/fileSpec.cxx index 6683f0111c..c9a8ff12fd 100755 --- a/direct/src/plugin/fileSpec.cxx +++ b/direct/src/plugin/fileSpec.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); } //////////////////////////////////////////////////////////////////// diff --git a/direct/src/plugin/fileSpec.h b/direct/src/plugin/fileSpec.h index 45629e9a1b..c02dd1fbc1 100755 --- a/direct/src/plugin/fileSpec.h +++ b/direct/src/plugin/fileSpec.h @@ -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; diff --git a/direct/src/plugin/p3dPackage.cxx b/direct/src/plugin/p3dPackage.cxx index fa7c02aaee..59173b1ffc 100755 --- a/direct/src/plugin/p3dPackage.cxx +++ b/direct/src/plugin/p3dPackage.cxx @@ -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() << ")"; +} diff --git a/direct/src/plugin/p3dPackage.h b/direct/src/plugin/p3dPackage.h index 94f3ce2d10..69335eb460 100755 --- a/direct/src/plugin/p3dPackage.h +++ b/direct/src/plugin/p3dPackage.h @@ -17,6 +17,7 @@ #include "p3d_plugin_common.h" #include "p3dFileDownload.h" +#include "p3dPatchfileReader.h" #include "fileSpec.h" #include "get_tinyxml.h" #include @@ -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 InstallPlan; diff --git a/direct/src/plugin/p3dPatchFinder.cxx b/direct/src/plugin/p3dPatchFinder.cxx index 1dd030fdf2..52b168f126 100644 --- a/direct/src/plugin/p3dPatchFinder.cxx +++ b/direct/src/plugin/p3dPatchFinder.cxx @@ -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; } //////////////////////////////////////////////////////////////////// diff --git a/direct/src/plugin/p3dPatchfileReader.I b/direct/src/plugin/p3dPatchfileReader.I new file mode 100644 index 0000000000..1d884f282c --- /dev/null +++ b/direct/src/plugin/p3dPatchfileReader.I @@ -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; +} diff --git a/direct/src/plugin/p3dPatchfileReader.cxx b/direct/src/plugin/p3dPatchfileReader.cxx new file mode 100644 index 0000000000..62393d3e97 --- /dev/null +++ b/direct/src/plugin/p3dPatchfileReader.cxx @@ -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); +} diff --git a/direct/src/plugin/p3dPatchfileReader.h b/direct/src/plugin/p3dPatchfileReader.h new file mode 100644 index 0000000000..f8d41b4c26 --- /dev/null +++ b/direct/src/plugin/p3dPatchfileReader.h @@ -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 diff --git a/direct/src/plugin/p3d_plugin_composite1.cxx b/direct/src/plugin/p3d_plugin_composite1.cxx index 0aa11a4b21..5ec430f665 100644 --- a/direct/src/plugin/p3d_plugin_composite1.cxx +++ b/direct/src/plugin/p3d_plugin_composite1.cxx @@ -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"