Panda3D

Loading...
Searching...
No Matches
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 */
27 bool DatagramOutputFile::
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
37 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
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 */
53 bool DatagramOutputFile::
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 */
72 void DatagramOutputFile::
73 close() {
74 _vfile.clear();
75 if (_owns_out) {
76 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
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 */
95 bool DatagramOutputFile::
96 write_header(const vector_uchar &header) {
97 nassertr(_out != nullptr, false);
98 nassertr(!_wrote_first_datagram, false);
99
100 _out->write((const char *)&header[0], header.size());
101 thread_consider_yield();
102 return !_out->fail();
103}
104
105/**
106 * Writes a sequence of bytes to the beginning of the datagram file. This may
107 * be called any number of times after the file has been opened and before the
108 * first datagram is written. It may not be called once the first datagram is
109 * written.
110 */
111 bool DatagramOutputFile::
112 write_header(const std::string &header) {
113 nassertr(_out != nullptr, false);
114 nassertr(!_wrote_first_datagram, false);
115
116 _out->write(header.data(), header.size());
117 thread_consider_yield();
118 return !_out->fail();
119}
120
121/**
122 * Writes the given datagram to the file. Returns true on success, false if
123 * there is an error.
124 */
125 bool DatagramOutputFile::
126 put_datagram(const Datagram &data) {
127 nassertr(_out != nullptr, false);
128 _wrote_first_datagram = true;
129
130 // First, write the size of the upcoming datagram.
131 StreamWriter writer(_out, false);
132 size_t num_bytes = data.get_length();
133 if (num_bytes == (uint32_t)-1 || num_bytes != (uint32_t)num_bytes) {
134 // Write a large value as a 64-bit size.
135 writer.add_uint32((uint32_t)-1);
136 writer.add_uint64(num_bytes);
137 } else {
138 // Write a value that fits in 32 bits.
139 writer.add_uint32((uint32_t)num_bytes);
140 }
141
142 // Now, write the datagram itself.
143 _out->write((const char *)data.get_data(), data.get_length());
144 thread_consider_yield();
145
146 return !_out->fail();
147}
148
149/**
150 * Copies the file data from the entire indicated file (via the vfs) as the
151 * next datagram. This is intended to support potentially very large
152 * datagrams.
153 *
154 * Returns true on success, false on failure or if this method is
155 * unimplemented. On true, fills "result" with the information that
156 * references the copied file, if possible.
157 */
158 bool DatagramOutputFile::
159 copy_datagram(SubfileInfo &result, const Filename &filename) {
160 nassertr(_out != nullptr, false);
161 _wrote_first_datagram = true;
162
163 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
164 PT(VirtualFile) vfile = vfs->get_file(filename);
165 if (vfile == nullptr) {
166 return false;
167 }
168 std::istream *in = vfile->open_read_file(true);
169 if (in == nullptr) {
170 return false;
171 }
172
173 streamsize size = vfile->get_file_size(in);
174 streamsize num_remaining = size;
175
176 StreamWriter writer(_out, false);
177 if (num_remaining == (uint32_t)-1 || num_remaining != (uint32_t)num_remaining) {
178 // Write a large value as a 64-bit size.
179 writer.add_uint32((uint32_t)-1);
180 writer.add_uint64(num_remaining);
181 } else {
182 // Write a value that fits in 32 bits.
183 writer.add_uint32((uint32_t)num_remaining);
184 }
185
186 static const size_t buffer_size = 4096;
187 char buffer[buffer_size];
188
189 streampos start = _out->tellp();
190 in->read(buffer, min((streamsize)buffer_size, num_remaining));
191 streamsize count = in->gcount();
192 while (count != 0) {
193 _out->write(buffer, count);
194 if (_out->fail()) {
195 vfile->close_read_file(in);
196 return false;
197 }
198 num_remaining -= count;
199 if (num_remaining == 0) {
200 break;
201 }
202 in->read(buffer, min((streamsize)buffer_size, num_remaining));
203 count = in->gcount();
204 }
205
206 vfile->close_read_file(in);
207
208 if (num_remaining != 0) {
209 util_cat.error()
210 << "Truncated input stream.\n";
211 return false;
212 }
213
214 result = SubfileInfo(_file, start, size);
215 return true;
216}
217
218/**
219 * Copies the file data from the range of the indicated file (outside of the
220 * vfs) as the next datagram. This is intended to support potentially very
221 * large datagrams.
222 *
223 * Returns true on success, false on failure or if this method is
224 * unimplemented. On true, fills "result" with the information that
225 * references the copied file, if possible.
226 */
227 bool DatagramOutputFile::
228 copy_datagram(SubfileInfo &result, const SubfileInfo &source) {
229 nassertr(_out != nullptr, false);
230 _wrote_first_datagram = true;
231
232 pifstream in;
233 if (!source.get_filename().open_read(in)) {
234 return false;
235 }
236
237 streamsize num_remaining = source.get_size();
238
239 StreamWriter writer(_out, false);
240 if (num_remaining == (uint32_t)-1 || num_remaining != (uint32_t)num_remaining) {
241 // Write a large value as a 64-bit size.
242 writer.add_uint32((uint32_t)-1);
243 writer.add_uint64(num_remaining);
244 } else {
245 // Write a value that fits in 32 bits.
246 writer.add_uint32((uint32_t)num_remaining);
247 }
248
249 static const size_t buffer_size = 4096;
250 char buffer[buffer_size];
251
252 streampos start = _out->tellp();
253 in.seekg(source.get_start());
254 in.read(buffer, min((streamsize)buffer_size, num_remaining));
255 streamsize count = in.gcount();
256 while (count != 0) {
257 _out->write(buffer, count);
258 if (_out->fail()) {
259 return false;
260 }
261 num_remaining -= count;
262 if (num_remaining == 0) {
263 break;
264 }
265 in.read(buffer, min((streamsize)buffer_size, num_remaining));
266 count = in.gcount();
267 }
268
269 if (num_remaining != 0) {
270 util_cat.error()
271 << "Truncated input stream.\n";
272 return false;
273 }
274
275 result = SubfileInfo(_file, start, source.get_size());
276 return true;
277}
278
279/**
280 * Returns true if the file has reached an error condition.
281 */
282 bool DatagramOutputFile::
283 is_error() {
284 if (_out == nullptr) {
285 return true;
286 }
287
288 if (_out->fail()) {
289 _error = true;
290 }
291 return _error;
292}
293
294/**
295 * Ensures that all datagrams previously written will be visible in the output
296 * file.
297 */
298 void DatagramOutputFile::
299 flush() {
300 if (_out != nullptr) {
301 _out->flush();
302 }
303}
304
305
306/**
307 * Returns the filename that provides the target for these datagrams, if any,
308 * or empty string if the datagrams do not get written to a file on disk.
309 */
310 const Filename &DatagramOutputFile::
311 get_filename() {
312 return _filename;
313}
314
315/**
316 * Returns the FileReference that provides the target for these datagrams, if
317 * any, or NULL if the datagrams do not written to a file on disk.
318 */
319 const FileReference *DatagramOutputFile::
320 get_file() {
321 return _file;
322}
323
324/**
325 * Returns the current file position within the data stream, if any, or 0 if
326 * the file position is not meaningful or cannot be determined.
327 *
328 * For DatagramOutputFiles that return a meaningful file position, this will
329 * be pointing to the first byte following the datagram returned after a call
330 * to put_datagram().
331 */
332streampos DatagramOutputFile::
333 get_file_pos() {
334 if (_out == nullptr) {
335 return 0;
336 }
337 return _out->tellp();
338}
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:159
DatagramOutputFile::flush
virtual void flush()
Ensures that all datagrams previously written will be visible in the output file.
Definition datagramOutputFile.cxx:299
DatagramOutputFile::open
bool open(const FileReference *file)
Opens the indicated filename for writing.
Definition datagramOutputFile.cxx:28
DatagramOutputFile::write_header
bool write_header(const vector_uchar &header)
Writes a sequence of bytes to the beginning of the datagram file.
Definition datagramOutputFile.cxx:96
DatagramOutputFile::close
void close()
Closes the file.
Definition datagramOutputFile.cxx:73
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:333
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:320
DatagramOutputFile::is_error
virtual bool is_error()
Returns true if the file has reached an error condition.
Definition datagramOutputFile.cxx:283
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:311
DatagramOutputFile::put_datagram
virtual bool put_datagram(const Datagram &data)
Writes the given datagram to the file.
Definition datagramOutputFile.cxx:126
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition datagram.h:38
FileReference
Keeps a reference-counted pointer to a file on disk.
Definition fileReference.h:26
FileReference::get_filename
const Filename & get_filename() const
Returns the filename of the reference.
Definition fileReference.I:25
Filename
The name of a file, such as a texture file or an Egg file.
Definition filename.h:44
Filename::open_read
bool open_read(std::ifstream &stream) const
Opens the indicated ifstream for reading the file, if possible.
Definition filename.cxx:1872
Filename::set_binary
void set_binary()
Indicates that the filename represents a binary file.
Definition filename.I:414
StreamWriter
A StreamWriter object is used to write sequential binary data directly to an ostream.
Definition streamWriter.h:29
StreamWriter::add_uint32
void add_uint32(uint32_t value)
Adds an unsigned 32-bit integer to the stream.
Definition streamWriter.I:147
StreamWriter::add_uint64
void add_uint64(uint64_t value)
Adds an unsigned 64-bit integer to the stream.
Definition streamWriter.I:156
SubfileInfo
This class records a particular byte sub-range within an existing file on disk.
Definition subfileInfo.h:26
SubfileInfo::get_filename
const Filename & get_filename() const
A shortcut to the filename.
Definition subfileInfo.I:88
SubfileInfo::get_start
std::streampos get_start() const
Returns the offset within the file at which this file data begins.
Definition subfileInfo.I:100
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
VirtualFileSystem
A hierarchy of directories and files that appears to be one continuous file system,...
Definition virtualFileSystem.h:40
VirtualFileSystem::get_global_ptr
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
Definition virtualFileSystem.cxx:741
VirtualFile
The abstract base class for a file or directory within the VirtualFileSystem.
Definition virtualFile.h:35
datagramOutputFile.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
streamWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
zStream.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.