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 */
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 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 */
109 bool DatagramOutputFile::
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 */
142 bool DatagramOutputFile::
143 copy_datagram(SubfileInfo &result, const Filename &filename) {
144 nassertr(_out != nullptr, false);
145 _wrote_first_datagram = true;
146
147 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
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 */
211 bool DatagramOutputFile::
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 */
266 bool DatagramOutputFile::
267 is_error() {
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 */
282 void DatagramOutputFile::
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 */
294 const Filename &DatagramOutputFile::
295 get_filename() {
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 */
303 const FileReference *DatagramOutputFile::
304 get_file() {
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::
317 get_file_pos() {
318 if (_out == nullptr) {
319 return 0;
320 }
321 return _out->tellp();
322 }
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
DatagramOutputFile::flush
virtual void flush()
Ensures that all datagrams previously written will be visible in the output file.
Definition: datagramOutputFile.cxx:283
DatagramOutputFile::open
bool open(const FileReference *file)
Opens the indicated filename for writing.
Definition: datagramOutputFile.cxx:28
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:317
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
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
DatagramOutputFile::put_datagram
virtual bool put_datagram(const Datagram &data)
Writes the given datagram to the file.
Definition: datagramOutputFile.cxx:110
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
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
Filename
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
Filename::open_read
bool open_read(std::ifstream &stream) const
Opens the indicated ifstream for reading the file, if possible.
Definition: filename.cxx:1863
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::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:929
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:530
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:515
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.