Panda3D
datagramOutputFile.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file datagramOutputFile.cxx
10  * @author drose
11  * @date 2000-10-30
12  */
13 
14 #include "datagramOutputFile.h"
15 #include "streamWriter.h"
16 #include "zStream.h"
17 #include <algorithm>
18 
19 using std::min;
20 using std::streampos;
21 using std::streamsize;
22 
23 /**
24  * Opens the indicated filename for writing. Returns true if successful,
25  * false on failure.
26  */
28 open(const FileReference *file) {
29  close();
30 
31  _file = file;
32  _filename = _file->get_filename();
33 
34  // DatagramOutputFiles are always binary.
35  _filename.set_binary();
36 
38  _vfile = vfs->create_file(_filename);
39  if (_vfile == nullptr) {
40  // No such file.
41  return false;
42  }
43  _out = _vfile->open_write_file(true, true);
44  _owns_out = (_out != nullptr);
45  return _owns_out && !_out->fail();
46 }
47 
48 /**
49  * Starts writing to the indicated stream. Returns true on success, false on
50  * failure. The DatagramOutputFile does not take ownership of the stream; you
51  * are responsible for closing or deleting it when you are done.
52  */
54 open(std::ostream &out, const Filename &filename) {
55  close();
56 
57  _out = &out;
58  _owns_out = false;
59  _filename = filename;
60 
61  if (!filename.empty()) {
62  _file = new FileReference(filename);
63  }
64 
65  return !_out->fail();
66 }
67 
68 /**
69  * Closes the file. This is also implicitly done when the DatagramOutputFile
70  * destructs.
71  */
73 close() {
74  _vfile.clear();
75  if (_owns_out) {
77  vfs->close_write_file(_out);
78  }
79  _out = nullptr;
80  _owns_out = false;
81 
82  _file.clear();
83  _filename = Filename();
84 
85  _wrote_first_datagram = false;
86  _error = false;
87 }
88 
89 /**
90  * Writes a sequence of bytes to the beginning of the datagram file. This may
91  * be called any number of times after the file has been opened and before the
92  * first datagram is written. It may not be called once the first datagram is
93  * written.
94  */
96 write_header(const std::string &header) {
97  nassertr(_out != nullptr, false);
98  nassertr(!_wrote_first_datagram, false);
99 
100  _out->write(header.data(), header.size());
101  thread_consider_yield();
102  return !_out->fail();
103 }
104 
105 /**
106  * Writes the given datagram to the file. Returns true on success, false if
107  * there is an error.
108  */
110 put_datagram(const Datagram &data) {
111  nassertr(_out != nullptr, false);
112  _wrote_first_datagram = true;
113 
114  // First, write the size of the upcoming datagram.
115  StreamWriter writer(_out, false);
116  size_t num_bytes = data.get_length();
117  if (num_bytes == (uint32_t)-1 || num_bytes != (uint32_t)num_bytes) {
118  // Write a large value as a 64-bit size.
119  writer.add_uint32((uint32_t)-1);
120  writer.add_uint64(num_bytes);
121  } else {
122  // Write a value that fits in 32 bits.
123  writer.add_uint32((uint32_t)num_bytes);
124  }
125 
126  // Now, write the datagram itself.
127  _out->write((const char *)data.get_data(), data.get_length());
128  thread_consider_yield();
129 
130  return !_out->fail();
131 }
132 
133 /**
134  * Copies the file data from the entire indicated file (via the vfs) as the
135  * next datagram. This is intended to support potentially very large
136  * datagrams.
137  *
138  * Returns true on success, false on failure or if this method is
139  * unimplemented. On true, fills "result" with the information that
140  * references the copied file, if possible.
141  */
143 copy_datagram(SubfileInfo &result, const Filename &filename) {
144  nassertr(_out != nullptr, false);
145  _wrote_first_datagram = true;
146 
148  PT(VirtualFile) vfile = vfs->get_file(filename);
149  if (vfile == nullptr) {
150  return false;
151  }
152  std::istream *in = vfile->open_read_file(true);
153  if (in == nullptr) {
154  return false;
155  }
156 
157  streamsize size = vfile->get_file_size(in);
158  streamsize num_remaining = size;
159 
160  StreamWriter writer(_out, false);
161  if (num_remaining == (uint32_t)-1 || num_remaining != (uint32_t)num_remaining) {
162  // Write a large value as a 64-bit size.
163  writer.add_uint32((uint32_t)-1);
164  writer.add_uint64(num_remaining);
165  } else {
166  // Write a value that fits in 32 bits.
167  writer.add_uint32((uint32_t)num_remaining);
168  }
169 
170  static const size_t buffer_size = 4096;
171  char buffer[buffer_size];
172 
173  streampos start = _out->tellp();
174  in->read(buffer, min((streamsize)buffer_size, num_remaining));
175  streamsize count = in->gcount();
176  while (count != 0) {
177  _out->write(buffer, count);
178  if (_out->fail()) {
179  vfile->close_read_file(in);
180  return false;
181  }
182  num_remaining -= count;
183  if (num_remaining == 0) {
184  break;
185  }
186  in->read(buffer, min((streamsize)buffer_size, num_remaining));
187  count = in->gcount();
188  }
189 
190  vfile->close_read_file(in);
191 
192  if (num_remaining != 0) {
193  util_cat.error()
194  << "Truncated input stream.\n";
195  return false;
196  }
197 
198  result = SubfileInfo(_file, start, size);
199  return true;
200 }
201 
202 /**
203  * Copies the file data from the range of the indicated file (outside of the
204  * vfs) as the next datagram. This is intended to support potentially very
205  * large datagrams.
206  *
207  * Returns true on success, false on failure or if this method is
208  * unimplemented. On true, fills "result" with the information that
209  * references the copied file, if possible.
210  */
212 copy_datagram(SubfileInfo &result, const SubfileInfo &source) {
213  nassertr(_out != nullptr, false);
214  _wrote_first_datagram = true;
215 
216  pifstream in;
217  if (!source.get_filename().open_read(in)) {
218  return false;
219  }
220 
221  streamsize num_remaining = source.get_size();
222 
223  StreamWriter writer(_out, false);
224  if (num_remaining == (uint32_t)-1 || num_remaining != (uint32_t)num_remaining) {
225  // Write a large value as a 64-bit size.
226  writer.add_uint32((uint32_t)-1);
227  writer.add_uint64(num_remaining);
228  } else {
229  // Write a value that fits in 32 bits.
230  writer.add_uint32((uint32_t)num_remaining);
231  }
232 
233  static const size_t buffer_size = 4096;
234  char buffer[buffer_size];
235 
236  streampos start = _out->tellp();
237  in.seekg(source.get_start());
238  in.read(buffer, min((streamsize)buffer_size, num_remaining));
239  streamsize count = in.gcount();
240  while (count != 0) {
241  _out->write(buffer, count);
242  if (_out->fail()) {
243  return false;
244  }
245  num_remaining -= count;
246  if (num_remaining == 0) {
247  break;
248  }
249  in.read(buffer, min((streamsize)buffer_size, num_remaining));
250  count = in.gcount();
251  }
252 
253  if (num_remaining != 0) {
254  util_cat.error()
255  << "Truncated input stream.\n";
256  return false;
257  }
258 
259  result = SubfileInfo(_file, start, source.get_size());
260  return true;
261 }
262 
263 /**
264  * Returns true if the file has reached an error condition.
265  */
268  if (_out == nullptr) {
269  return true;
270  }
271 
272  if (_out->fail()) {
273  _error = true;
274  }
275  return _error;
276 }
277 
278 /**
279  * Ensures that all datagrams previously written will be visible in the output
280  * file.
281  */
283 flush() {
284  if (_out != nullptr) {
285  _out->flush();
286  }
287 }
288 
289 
290 /**
291  * Returns the filename that provides the target for these datagrams, if any,
292  * or empty string if the datagrams do not get written to a file on disk.
293  */
296  return _filename;
297 }
298 
299 /**
300  * Returns the FileReference that provides the target for these datagrams, if
301  * any, or NULL if the datagrams do not written to a file on disk.
302  */
305  return _file;
306 }
307 
308 /**
309  * Returns the current file position within the data stream, if any, or 0 if
310  * the file position is not meaningful or cannot be determined.
311  *
312  * For DatagramOutputFiles that return a meaningful file position, this will
313  * be pointing to the first byte following the datagram returned after a call
314  * to put_datagram().
315  */
316 streampos DatagramOutputFile::
318  if (_out == nullptr) {
319  return 0;
320  }
321  return _out->tellp();
322 }
SubfileInfo::get_start
std::streampos get_start() const
Returns the offset within the file at which this file data begins.
Definition: subfileInfo.I:100
StreamWriter::add_uint32
void add_uint32(uint32_t value)
Adds an unsigned 32-bit integer to the stream.
Definition: streamWriter.I:147
Filename::open_read
bool open_read(std::ifstream &stream) const
Opens the indicated ifstream for reading the file, if possible.
Definition: filename.cxx:1863
VirtualFileSystem::create_file
PointerTo< VirtualFile > create_file(const Filename &filename)
Attempts to create a file by the indicated name in the filesystem, if possible, and returns it.
Definition: virtualFileSystem.cxx:531
DatagramOutputFile::get_file
virtual const FileReference * get_file()
Returns the FileReference that provides the target for these datagrams, if any, or NULL if the datagr...
Definition: datagramOutputFile.cxx:304
VirtualFileSystem::get_file
PointerTo< VirtualFile > get_file(const Filename &filename, bool status_only=false) const
Looks up the file by the indicated name in the file system.
Definition: virtualFileSystem.cxx:516
DatagramOutputFile::close
void close()
Closes the file.
Definition: datagramOutputFile.cxx:73
DatagramOutputFile::is_error
virtual bool is_error()
Returns true if the file has reached an error condition.
Definition: datagramOutputFile.cxx:267
DatagramOutputFile::get_filename
virtual const Filename & get_filename()
Returns the filename that provides the target for these datagrams, if any, or empty string if the dat...
Definition: datagramOutputFile.cxx:295
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
DatagramOutputFile::get_file_pos
virtual std::streampos get_file_pos()
Returns the current file position within the data stream, if any, or 0 if the file position is not me...
Definition: datagramOutputFile.cxx:317
DatagramOutputFile::flush
virtual void flush()
Ensures that all datagrams previously written will be visible in the output file.
Definition: datagramOutputFile.cxx:283
VirtualFileSystem::close_write_file
static void close_write_file(std::ostream *stream)
Closes a file opened by a previous call to open_write_file().
Definition: virtualFileSystem.cxx:930
VirtualFileSystem
A hierarchy of directories and files that appears to be one continuous file system,...
Definition: virtualFileSystem.h:40
datagramOutputFile.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
DatagramOutputFile::write_header
bool write_header(const std::string &header)
Writes a sequence of bytes to the beginning of the datagram file.
Definition: datagramOutputFile.cxx:96
StreamWriter::add_uint64
void add_uint64(uint64_t value)
Adds an unsigned 64-bit integer to the stream.
Definition: streamWriter.I:156
SubfileInfo::get_filename
const Filename & get_filename() const
A shortcut to the filename.
Definition: subfileInfo.I:88
DatagramOutputFile::copy_datagram
virtual bool copy_datagram(SubfileInfo &result, const Filename &filename)
Copies the file data from the entire indicated file (via the vfs) as the next datagram.
Definition: datagramOutputFile.cxx:143
VirtualFileSystem::get_global_ptr
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
Definition: virtualFileSystem.cxx:742
FileReference
Keeps a reference-counted pointer to a file on disk.
Definition: fileReference.h:26
VirtualFile
The abstract base class for a file or directory within the VirtualFileSystem.
Definition: virtualFile.h:35
zStream.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
StreamWriter
A StreamWriter object is used to write sequential binary data directly to an ostream.
Definition: streamWriter.h:29
SubfileInfo
This class records a particular byte sub-range within an existing file on disk.
Definition: subfileInfo.h:26
DatagramOutputFile::open
bool open(const FileReference *file)
Opens the indicated filename for writing.
Definition: datagramOutputFile.cxx:28
streamWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Filename
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
Filename::set_binary
void set_binary()
Indicates that the filename represents a binary file.
Definition: filename.I:414
DatagramOutputFile::put_datagram
virtual bool put_datagram(const Datagram &data)
Writes the given datagram to the file.
Definition: datagramOutputFile.cxx:110
SubfileInfo::get_size
std::streamsize get_size() const
Returns the number of consecutive bytes, beginning at get_start(), that correspond to this file data.
Definition: subfileInfo.I:109