Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/downloader/decompressor.cxx

Go to the documentation of this file.
00001 // Filename: decompressor.cxx
00002 // Created by:  mike (09Jan97)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 // This file is compiled only if we have zlib installed.
00020 
00021 #include "config_downloader.h"
00022 
00023 #include "error_utils.h"
00024 #include "filename.h"
00025 #include "buffer.h"
00026 #include "zStream.h"
00027 #include "config_express.h"
00028 
00029 #include "decompressor.h"
00030 
00031 #include <stdio.h>
00032 #include <errno.h>
00033 
00034 ////////////////////////////////////////////////////////////////////
00035 //     Function: Decompressor::Constructor
00036 //       Access: Public
00037 //  Description:
00038 ////////////////////////////////////////////////////////////////////
00039 Decompressor::
00040 Decompressor() {
00041   _source = NULL;
00042   _decompress = NULL;
00043   _dest = NULL;
00044 }
00045 
00046 ////////////////////////////////////////////////////////////////////
00047 //     Function: Decompressor::Destructor
00048 //       Access: Public
00049 //  Description:
00050 ////////////////////////////////////////////////////////////////////
00051 Decompressor::
00052 ~Decompressor() {
00053   cleanup();
00054 }
00055 
00056 ////////////////////////////////////////////////////////////////////
00057 //     Function: Decompressor::initiate
00058 //       Access: Public
00059 //  Description: Begins a background decompression of the named file
00060 //               (whose filename must end in ".pz") to a new file
00061 //               without the .pz extension.  The source file is
00062 //               removed after successful completion.
00063 ////////////////////////////////////////////////////////////////////
00064 int Decompressor::
00065 initiate(const Filename &source_file) {
00066   string extension = source_file.get_extension();
00067   if (extension == "pz") {
00068     Filename dest_file = source_file;
00069     dest_file = source_file.get_fullpath_wo_extension();
00070     return initiate(source_file, dest_file);
00071   }
00072 
00073   if (downloader_cat.is_debug()) {
00074     downloader_cat.debug()
00075       << "Unknown file extension for decompressor: ."
00076       << extension << endl;
00077   }
00078   return EU_error_abort;
00079 }
00080 
00081 ////////////////////////////////////////////////////////////////////
00082 //     Function: Decompressor::initiate
00083 //       Access: Public
00084 //  Description: Begins a background decompression from the named
00085 //               source file to the named destination file.  The
00086 //               source file is removed after successful completion.
00087 ////////////////////////////////////////////////////////////////////
00088 int Decompressor::
00089 initiate(const Filename &source_file, const Filename &dest_file) {
00090   cleanup();
00091 
00092   // Open source file
00093   _source_filename = Filename(source_file);
00094   _source_filename.set_binary();
00095 
00096   ifstream *source_fstream = new ifstream;
00097   _source = source_fstream;
00098   if (!_source_filename.open_read(*source_fstream)) {
00099     downloader_cat.error()
00100       << "Unable to read " << _source_filename << "\n";
00101     return get_write_error();
00102   }
00103 
00104   // Determine source file length
00105   source_fstream->seekg(0, ios::end);
00106   _source_length = source_fstream->tellg();
00107   if (_source_length == 0) {
00108     downloader_cat.warning()
00109       << "Zero length file: " << source_file << "\n";
00110     return EU_error_file_empty;
00111   }
00112   source_fstream->seekg(0, ios::beg);
00113 
00114   // Open destination file
00115   Filename dest_filename(dest_file);
00116   dest_filename.set_binary();
00117 
00118   ofstream *dest_fstream = new ofstream;
00119   _dest = dest_fstream;
00120   if (dest_filename.exists()) {
00121     downloader_cat.info()
00122       << dest_filename << " already exists, removing.\n";
00123     if (!dest_filename.unlink()) {
00124       downloader_cat.error()
00125         << "Unable to remove old " << dest_filename << "\n";
00126       return get_write_error();
00127     }
00128   } else {
00129     if (downloader_cat.is_debug()) {
00130       downloader_cat.debug()
00131         << dest_filename << " does not already exist.\n";
00132     }
00133   }
00134   if (!dest_filename.open_write(*dest_fstream, true)) {
00135     downloader_cat.error()
00136       << "Unable to write to " << dest_filename << "\n";
00137     return get_write_error();
00138   }
00139 
00140   // Now create the decompressor stream.
00141   _decompress = new IDecompressStream(_source, false);
00142   return EU_success;
00143 }
00144 
00145 ////////////////////////////////////////////////////////////////////
00146 //     Function: Decompressor::run
00147 //       Access: Public
00148 //  Description: Called each frame to do the next bit of work in the
00149 //               background task.  Returns EU_ok if a chunk is
00150 //               completed but there is more to go, or EU_success when
00151 //               we're all done.  Any other return value indicates an
00152 //               error.
00153 ////////////////////////////////////////////////////////////////////
00154 int Decompressor::
00155 run() {
00156   if (_decompress == (istream *)NULL) {
00157     // Hmm, we were already done.
00158     return EU_success;
00159   }
00160   
00161   // Read a bunch of characters from the decompress stream, but no
00162   // more than decompressor_buffer_size.
00163   int count = 0;
00164   int ch = _decompress->get();
00165   while (!_decompress->eof() && !_decompress->fail()) {
00166     _dest->put(ch);
00167     if (++count >= decompressor_buffer_size) {
00168       // That's enough for now.
00169       return EU_ok;
00170     }
00171 
00172     ch = _decompress->get();
00173   }
00174 
00175   // All done!
00176   cleanup();
00177   if (!keep_temporary_files) {
00178     _source_filename.unlink();
00179   }
00180   return EU_success;
00181 }
00182 
00183 ////////////////////////////////////////////////////////////////////
00184 //     Function: Decompressor::decompress
00185 //       Access: Public
00186 //  Description: Performs a foreground decompression of the named
00187 //               file; does not return until the decompression is
00188 //               complete.
00189 ////////////////////////////////////////////////////////////////////
00190 bool Decompressor::
00191 decompress(const Filename &source_file) {
00192   int ret = initiate(source_file);
00193   if (ret < 0)
00194     return false;
00195 
00196   int ch = _decompress->get();
00197   while (!_decompress->eof() && !_decompress->fail()) {
00198     _dest->put(ch);
00199     ch = _decompress->get();
00200   }
00201 
00202   cleanup();
00203   if (!keep_temporary_files) {
00204     _source_filename.unlink();
00205   }
00206   return true;
00207 }
00208 
00209 ////////////////////////////////////////////////////////////////////
00210 //     Function: Decompressor::decompress
00211 //       Access: Public
00212 //  Description: Does an in-memory decompression of the indicated
00213 //               Ramfile.  The decompressed contents are written back
00214 //               into the same Ramfile on completion.
00215 ////////////////////////////////////////////////////////////////////
00216 bool Decompressor::
00217 decompress(Ramfile &source_and_dest_file) {
00218   istringstream source(source_and_dest_file._data);
00219   ostringstream dest;
00220 
00221   IDecompressStream decompress(&source, false);
00222 
00223   int ch = decompress.get();
00224   while (!decompress.eof() && !decompress.fail()) {
00225     dest.put(ch);
00226     ch = decompress.get();
00227   }
00228 
00229   source_and_dest_file._pos = 0;
00230   source_and_dest_file._data = dest.str();
00231   return true;
00232 }
00233 
00234 ////////////////////////////////////////////////////////////////////
00235 //     Function: Decompressor::get_progress
00236 //       Access: Public
00237 //  Description: Returns the ratio through the decompression step
00238 //               in the background.
00239 ////////////////////////////////////////////////////////////////////
00240 float Decompressor::
00241 get_progress() const {
00242   if (_decompress == (istream *)NULL) {
00243     // Hmm, we were already done.
00244     return 1.0f;
00245   }
00246 
00247   nassertr(_source_length > 0, 0.0);
00248   size_t source_pos = _source->tellg();
00249 
00250   // We stop the scale at 0.99 because there may be a little bit more
00251   // to do even after the decompressor has read all of the source.
00252   return (0.99f * (float)source_pos / (float)_source_length);
00253 }
00254 
00255 ////////////////////////////////////////////////////////////////////
00256 //     Function: Decompressor::cleanup
00257 //       Access: Private
00258 //  Description: Called to reset a previous decompressor state and
00259 //               clean up properly.
00260 ////////////////////////////////////////////////////////////////////
00261 void Decompressor::
00262 cleanup() {
00263   if (_source != (istream *)NULL) {
00264     delete _source;
00265     _source = NULL;
00266   }
00267   if (_dest != (ostream *)NULL) {
00268     delete _dest;
00269     _dest = NULL;
00270   }
00271   if (_decompress != (istream *)NULL) {
00272     delete _decompress;
00273     _decompress = NULL;
00274   }
00275 }

Generated on Fri May 2 00:36:44 2003 for Panda by doxygen1.3