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
19using std::min;
20using std::streampos;
21using std::streamsize;
22
23/**
24 * Opens the indicated filename for writing. Returns true if successful,
25 * false on failure.
26 */
28open(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 */
54open(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 */
73close() {
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 */
96write_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 */
112write_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 */
126put_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 */
159copy_datagram(SubfileInfo &result, const Filename &filename) {
160 nassertr(_out != nullptr, false);
161 _wrote_first_datagram = true;
162
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 */
228copy_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 */
283is_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 */
299flush() {
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 */
311get_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 */
320get_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 */
333get_file_pos() {
334 if (_out == nullptr) {
335 return 0;
336 }
337 return _out->tellp();
338}
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.
virtual void flush()
Ensures that all datagrams previously written will be visible in the output file.
bool open(const FileReference *file)
Opens the indicated filename for writing.
bool write_header(const vector_uchar &header)
Writes a sequence of bytes to the beginning of the datagram file.
void close()
Closes the file.
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...
virtual const FileReference * get_file()
Returns the FileReference that provides the target for these datagrams, if any, or NULL if the datagr...
virtual bool is_error()
Returns true if the file has reached an error condition.
virtual const Filename & get_filename()
Returns the filename that provides the target for these datagrams, if any, or empty string if the dat...
virtual bool put_datagram(const Datagram &data)
Writes the given datagram to the file.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition datagram.h:38
Keeps a reference-counted pointer to a file on disk.
The name of a file, such as a texture file or an Egg file.
Definition filename.h:44
bool open_read(std::ifstream &stream) const
Opens the indicated ifstream for reading the file, if possible.
void set_binary()
Indicates that the filename represents a binary file.
Definition filename.I:414
A StreamWriter object is used to write sequential binary data directly to an ostream.
void add_uint32(uint32_t value)
Adds an unsigned 32-bit integer to the stream.
void add_uint64(uint64_t value)
Adds an unsigned 64-bit integer to the stream.
This class records a particular byte sub-range within an existing file on disk.
Definition subfileInfo.h:26
const Filename & get_filename() const
A shortcut to the filename.
Definition subfileInfo.I:88
std::streampos get_start() const
Returns the offset within the file at which this file data begins.
std::streamsize get_size() const
Returns the number of consecutive bytes, beginning at get_start(), that correspond to this file data.
A hierarchy of directories and files that appears to be one continuous file system,...
static void close_write_file(std::ostream *stream)
Closes a file opened by a previous call to open_write_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.
PointerTo< VirtualFile > get_file(const Filename &filename, bool status_only=false) const
Looks up the file by the indicated name in the file system.
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
The abstract base class for a file or directory within the VirtualFileSystem.
Definition virtualFile.h:35
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.