Panda3D
|
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 }