Panda3D

datagramOutputFile.cxx

00001 // Filename: datagramOutputFile.cxx
00002 // Created by:  drose (30Oct00)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "datagramOutputFile.h"
00016 #include "streamWriter.h"
00017 #include "zStream.h"
00018 
00019 ////////////////////////////////////////////////////////////////////
00020 //     Function: DatagramOutputFile::open
00021 //       Access: Public
00022 //  Description: Opens the indicated filename for writing.  Returns
00023 //               true if successful, false on failure.
00024 ////////////////////////////////////////////////////////////////////
00025 bool DatagramOutputFile::
00026 open(const FileReference *file) {
00027   close();
00028 
00029   _file = file;
00030   _filename = _file->get_filename();
00031 
00032   // DatagramOutputFiles are always binary.
00033   _filename.set_binary();
00034 
00035   VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00036   _vfile = vfs->create_file(_filename);
00037   if (_vfile == (VirtualFile *)NULL) {
00038     // No such file.
00039     return false;
00040   }
00041   _out = _vfile->open_write_file(true, true);
00042   _owns_out = (_out != (ostream *)NULL);
00043   return _owns_out && !_out->fail();
00044 }
00045 
00046 ////////////////////////////////////////////////////////////////////
00047 //     Function: DatagramOutputFile::open
00048 //       Access: Public
00049 //  Description: Starts writing to the indicated stream.  Returns
00050 //               true on success, false on failure.  The
00051 //               DatagramOutputFile does not take ownership of the
00052 //               stream; you are responsible for closing or deleting
00053 //               it when you are done.
00054 ////////////////////////////////////////////////////////////////////
00055 bool DatagramOutputFile::
00056 open(ostream &out, const Filename &filename) {
00057   close();
00058 
00059   _out = &out;
00060   _owns_out = false;
00061   _filename = filename;
00062 
00063   if (!filename.empty()) {
00064     _file = new FileReference(filename);
00065   }
00066 
00067   return !_out->fail();
00068 }
00069 
00070 ////////////////////////////////////////////////////////////////////
00071 //     Function: DatagramOutputFile::close
00072 //       Access: Public
00073 //  Description: Closes the file.  This is also implicitly done when
00074 //               the DatagramOutputFile destructs.
00075 ////////////////////////////////////////////////////////////////////
00076 void DatagramOutputFile::
00077 close() {
00078   _vfile.clear();
00079   if (_owns_out) {
00080     VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00081     vfs->close_write_file(_out);
00082   }
00083   _out = (ostream *)NULL;
00084   _owns_out = false;
00085 
00086   _file.clear();
00087   _filename = Filename();
00088 
00089   _wrote_first_datagram = false;
00090   _error = false;
00091 }
00092 
00093 ////////////////////////////////////////////////////////////////////
00094 //     Function: DatagramOutputFile::write_header
00095 //       Access: Public
00096 //  Description: Writes a sequence of bytes to the beginning of the
00097 //               datagram file.  This may be called any number of
00098 //               times after the file has been opened and before the
00099 //               first datagram is written.  It may not be called once
00100 //               the first datagram is written.
00101 ////////////////////////////////////////////////////////////////////
00102 bool DatagramOutputFile::
00103 write_header(const string &header) {
00104   nassertr(_out != (ostream *)NULL, false);
00105   nassertr(!_wrote_first_datagram, false);
00106 
00107   _out->write(header.data(), header.size());
00108   thread_consider_yield();
00109   return !_out->fail();
00110 }
00111 
00112 ////////////////////////////////////////////////////////////////////
00113 //     Function: DatagramOutputFile::put_datagram
00114 //       Access: Public, Virtual
00115 //  Description: Writes the given datagram to the file.  Returns true
00116 //               on success, false if there is an error.
00117 ////////////////////////////////////////////////////////////////////
00118 bool DatagramOutputFile::
00119 put_datagram(const Datagram &data) {
00120   nassertr(_out != (ostream *)NULL, false);
00121   _wrote_first_datagram = true;
00122 
00123   // First, write the size of the upcoming datagram.
00124   StreamWriter writer(_out, false);
00125   writer.add_uint32(data.get_length());
00126 
00127   // Now, write the datagram itself.
00128   _out->write((const char *)data.get_data(), data.get_length());
00129   thread_consider_yield();
00130 
00131   return !_out->fail();
00132 }
00133 
00134 ////////////////////////////////////////////////////////////////////
00135 //     Function: DatagramOutputFile::copy_datagram
00136 //       Access: Published, Virtual
00137 //  Description: Copies the file data from the entire indicated
00138 //               file (via the vfs) as the next datagram.  This is
00139 //               intended to support potentially very large datagrams.
00140 //
00141 //               Returns true on success, false on failure or if this
00142 //               method is unimplemented.  On true, fills "result"
00143 //               with the information that references the copied file,
00144 //               if possible.
00145 ////////////////////////////////////////////////////////////////////
00146 bool DatagramOutputFile::
00147 copy_datagram(SubfileInfo &result, const Filename &filename) {
00148   nassertr(_out != (ostream *)NULL, false);
00149   _wrote_first_datagram = true;
00150 
00151   VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00152   PT(VirtualFile) vfile = vfs->get_file(filename);
00153   if (vfile == NULL) {
00154     return false;
00155   }
00156   istream *in = vfile->open_read_file(true);
00157   if (in == NULL) {
00158     return false;
00159   }
00160 
00161   off_t size = vfile->get_file_size(in);
00162   size_t num_remaining = (size_t)size;
00163   nassertr(num_remaining == size, false);
00164 
00165   StreamWriter writer(_out, false);
00166   writer.add_uint32(num_remaining);
00167 
00168   static const size_t buffer_size = 4096;
00169   char buffer[buffer_size];
00170 
00171   streampos start = _out->tellp();
00172   in->read(buffer, min(buffer_size, num_remaining));
00173   size_t count = in->gcount();
00174   while (count != 0) {
00175     _out->write(buffer, count);
00176     if (_out->fail()) {
00177       vfile->close_read_file(in);
00178       return false;
00179     }
00180     num_remaining -= count;
00181     if (num_remaining == 0) {
00182       break;
00183     }
00184     in->read(buffer, min(buffer_size, num_remaining));
00185     count = in->gcount();
00186   }
00187 
00188   vfile->close_read_file(in);
00189 
00190   if (num_remaining != 0) {
00191     util_cat.error()
00192       << "Truncated input stream.\n";
00193     return false;
00194   }
00195   
00196   result = SubfileInfo(_file, start, size);
00197   return true;
00198 }
00199 
00200 ////////////////////////////////////////////////////////////////////
00201 //     Function: DatagramOutputFile::copy_datagram
00202 //       Access: Published, Virtual
00203 //  Description: Copies the file data from the range of the indicated
00204 //               file (outside of the vfs) as the next datagram.  This
00205 //               is intended to support potentially very large
00206 //               datagrams.
00207 //
00208 //               Returns true on success, false on failure or if this
00209 //               method is unimplemented.  On true, fills "result"
00210 //               with the information that references the copied file,
00211 //               if possible.
00212 ////////////////////////////////////////////////////////////////////
00213 bool DatagramOutputFile::
00214 copy_datagram(SubfileInfo &result, const SubfileInfo &source) {
00215   nassertr(_out != (ostream *)NULL, false);
00216   _wrote_first_datagram = true;
00217 
00218   pifstream in;
00219   if (!source.get_filename().open_read(in)) {
00220     return false;
00221   }
00222 
00223   size_t num_remaining = source.get_size();
00224 
00225   StreamWriter writer(_out, false);
00226   writer.add_uint32(num_remaining);
00227 
00228   static const size_t buffer_size = 4096;
00229   char buffer[buffer_size];
00230   
00231   streampos start = _out->tellp();
00232   in.seekg(source.get_start());
00233   in.read(buffer, min(buffer_size, num_remaining));
00234   size_t count = in.gcount();
00235   while (count != 0) {
00236     _out->write(buffer, count);
00237     if (_out->fail()) {
00238       return false;
00239     }
00240     num_remaining -= count;
00241     if (num_remaining == 0) {
00242       break;
00243     }
00244     in.read(buffer, min(buffer_size, num_remaining));
00245     count = in.gcount();
00246   }
00247 
00248   if (num_remaining != 0) {
00249     util_cat.error()
00250       << "Truncated input stream.\n";
00251     return false;
00252   }
00253 
00254   result = SubfileInfo(_file, start, source.get_size());
00255   return true;
00256 }
00257 
00258 ////////////////////////////////////////////////////////////////////
00259 //     Function: DatagramOutputFile::is_error
00260 //       Access: Public, Virtual
00261 //  Description: Returns true if the file has reached an error
00262 //               condition.
00263 ////////////////////////////////////////////////////////////////////
00264 bool DatagramOutputFile::
00265 is_error() {
00266   if (_out == (ostream *)NULL) {
00267     return true;
00268   }
00269 
00270   if (_out->fail()) {
00271     _error = true;
00272   }
00273   return _error;
00274 }
00275 
00276 ////////////////////////////////////////////////////////////////////
00277 //     Function: DatagramOutputFile::flush
00278 //       Access: Public, Virtual
00279 //  Description: Ensures that all datagrams previously written will be
00280 //               visible in the output file.
00281 ////////////////////////////////////////////////////////////////////
00282 void DatagramOutputFile::
00283 flush() {
00284   if (_out != (ostream *)NULL) {
00285     _out->flush();
00286   }
00287 }
00288 
00289 
00290 ////////////////////////////////////////////////////////////////////
00291 //     Function: DatagramOutputFile::get_filename
00292 //       Access: Published, Virtual
00293 //  Description: Returns the filename that provides the target for
00294 //               these datagrams, if any, or empty string if the
00295 //               datagrams do not get written to a file on disk.
00296 ////////////////////////////////////////////////////////////////////
00297 const Filename &DatagramOutputFile::
00298 get_filename() {
00299   return _filename;
00300 }
00301 
00302 ////////////////////////////////////////////////////////////////////
00303 //     Function: DatagramOutputFile::get_file
00304 //       Access: Published, Virtual
00305 //  Description: Returns the FileReference that provides the target for
00306 //               these datagrams, if any, or NULL if the datagrams do
00307 //               not written to a file on disk.
00308 ////////////////////////////////////////////////////////////////////
00309 const FileReference *DatagramOutputFile::
00310 get_file() {
00311   return _file;
00312 }
00313 
00314 ////////////////////////////////////////////////////////////////////
00315 //     Function: DatagramOutputFile::get_file_pos
00316 //       Access: Published, Virtual
00317 //  Description: Returns the current file position within the data
00318 //               stream, if any, or 0 if the file position is not
00319 //               meaningful or cannot be determined.
00320 //
00321 //               For DatagramOutputFiles that return a meaningful file
00322 //               position, this will be pointing to the first byte
00323 //               following the datagram returned after a call to
00324 //               put_datagram().
00325 ////////////////////////////////////////////////////////////////////
00326 streampos DatagramOutputFile::
00327 get_file_pos() {
00328   if (_out == (ostream *)NULL) {
00329     return 0;
00330   }
00331   return _out->tellp();
00332 }
 All Classes Functions Variables Enumerations