Panda3D
virtualFileSimple.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 virtualFileSimple.cxx
10  * @author drose
11  * @date 2002-08-03
12  */
13 
14 #include "virtualFileSimple.h"
15 #include "virtualFileMount.h"
16 #include "virtualFileList.h"
17 #include "dcast.h"
18 
19 using std::iostream;
20 using std::istream;
21 using std::ostream;
22 using std::string;
23 
24 TypeHandle VirtualFileSimple::_type_handle;
25 
26 
27 /**
28  * Returns the VirtualFileSystem this file is associated with.
29  */
31 get_file_system() const {
32  return _mount->get_file_system();
33 }
34 
35 /**
36  * Returns the full pathname to this file within the virtual file system.
37  */
39 get_filename() const {
40  string mount_point = _mount->get_mount_point();
41  if (_local_filename.empty()) {
42  if (mount_point.empty()) {
43  return "/";
44  } else {
45  return string("/") + mount_point;
46  }
47 
48  } else {
49  if (mount_point.empty()) {
50  return string("/") + _local_filename.get_fullpath();
51  } else {
52  return string("/") + mount_point + string("/") + _local_filename.get_fullpath();
53  }
54  }
55 }
56 
57 /**
58  * Returns true if this file exists, false otherwise.
59  */
61 has_file() const {
62  return _mount->has_file(_local_filename);
63 }
64 
65 /**
66  * Returns true if this file represents a directory (and scan_directory() may
67  * be called), false otherwise.
68  */
70 is_directory() const {
71  return _mount->is_directory(_local_filename);
72 }
73 
74 /**
75  * Returns true if this file represents a regular file (and read_file() may be
76  * called), false otherwise.
77  */
79 is_regular_file() const {
80  return _mount->is_regular_file(_local_filename);
81 }
82 
83 /**
84  * Returns true if this file represents a writable regular file (and
85  * write_file() may be called), false otherwise.
86  */
88 is_writable() const {
89  return _mount->is_writable(_local_filename);
90 }
91 
92 /**
93  * Attempts to delete this file or directory. This can remove a single file
94  * or an empty directory. It will not remove a nonempty directory. Returns
95  * true on success, false on failure.
96  */
98 delete_file() {
99  return _mount->delete_file(_local_filename);
100 }
101 
102 /**
103  * Attempts to move or rename this file or directory. If the original file is
104  * an ordinary file, it will quietly replace any already-existing file in the
105  * new filename (but not a directory). If the original file is a directory,
106  * the new filename must not already exist.
107  *
108  * If the file is a directory, the new filename must be within the same mount
109  * point. If the file is an ordinary file, the new filename may be anywhere;
110  * but if it is not within the same mount point then the rename operation is
111  * automatically performed as a two-step copy-and-delete operation.
112  */
114 rename_file(VirtualFile *new_file) {
115  if (new_file->is_of_type(VirtualFileSimple::get_class_type())) {
116  VirtualFileSimple *new_file_simple = DCAST(VirtualFileSimple, new_file);
117  if (new_file_simple->_mount == _mount) {
118  // Same mount pount.
119  if (_mount->rename_file(_local_filename, new_file_simple->_local_filename)) {
120  return true;
121  }
122  }
123  }
124 
125  // Different mount point, or the mount doesn't support renaming. Do it by
126  // hand.
127  if (is_regular_file() && !new_file->is_directory()) {
128  // copy-and-delete.
129  new_file->delete_file();
130  if (copy_file(new_file)) {
131  delete_file();
132  return true;
133  }
134  }
135 
136  return false;
137 }
138 
139 /**
140  * Attempts to copy the contents of this file to the indicated file. Returns
141  * true on success, false on failure.
142  */
144 copy_file(VirtualFile *new_file) {
145  if (new_file->is_of_type(VirtualFileSimple::get_class_type())) {
146  VirtualFileSimple *new_file_simple = DCAST(VirtualFileSimple, new_file);
147  if (new_file_simple->_mount == _mount) {
148  // Same mount pount.
149  if (_mount->copy_file(_local_filename, new_file_simple->_local_filename)) {
150  return true;
151  }
152  }
153  }
154 
155  // Different mount point, or the mount doesn't support copying. Do it by
156  // hand.
157  ostream *out = new_file->open_write_file(false, true);
158  if (out == nullptr) {
159  return false;
160  }
161 
162  istream *in = open_read_file(false);
163  if (in == nullptr) {
164  new_file->close_write_file(out);
165  new_file->delete_file();
166  return false;
167  }
168 
169  static const size_t buffer_size = 4096;
170  char buffer[buffer_size];
171 
172  in->read(buffer, buffer_size);
173  size_t count = in->gcount();
174  while (count != 0) {
175  out->write(buffer, count);
176  if (out->fail()) {
177  new_file->close_write_file(out);
178  close_read_file(in);
179  new_file->delete_file();
180  return false;
181  }
182  in->read(buffer, buffer_size);
183  count = in->gcount();
184  }
185 
186  if (!in->eof()) {
187  new_file->close_write_file(out);
188  close_read_file(in);
189  new_file->delete_file();
190  return false;
191  }
192 
193  new_file->close_write_file(out);
194  close_read_file(in);
195  return true;
196 }
197 
198 /**
199  * Opens the file for reading. Returns a newly allocated istream on success
200  * (which you should eventually delete when you are done reading). Returns
201  * NULL on failure.
202  *
203  * If auto_unwrap is true, an explicitly-named .pz/.gz file is automatically
204  * decompressed and the decompressed contents are returned. This is different
205  * than vfs-implicit-pz, which will automatically decompress a file if the
206  * extension .pz is *not* given.
207  */
209 open_read_file(bool auto_unwrap) const {
210 
211  // Will we be automatically unwrapping a .pz file?
212  bool do_uncompress = (_implicit_pz_file ||
213  (auto_unwrap && (_local_filename.get_extension() == "pz" ||
214  _local_filename.get_extension() == "gz")));
215 
216  Filename local_filename(_local_filename);
217  if (do_uncompress) {
218  // .pz files are always binary, of course.
219  local_filename.set_binary();
220  }
221 
222  return _mount->open_read_file(local_filename, do_uncompress);
223 }
224 
225 /**
226  * Closes a file opened by a previous call to open_read_file(). This really
227  * just deletes the istream pointer, but it is recommended to use this
228  * interface instead of deleting it explicitly, to help work around compiler
229  * issues.
230  */
232 close_read_file(istream *stream) const {
233  _mount->close_read_file(stream);
234 }
235 
236 /**
237  * Opens the file for writing. Returns a newly allocated ostream on success
238  * (which you should eventually delete when you are done writing). Returns
239  * NULL on failure.
240  *
241  * If auto_wrap is true, an explicitly-named .pz file is automatically
242  * compressed while writing. If truncate is true, the file is truncated to
243  * zero length before writing.
244  */
246 open_write_file(bool auto_wrap, bool truncate) {
247  // Will we be automatically wrapping a .pz file?
248  bool do_compress = (_implicit_pz_file || (auto_wrap && _local_filename.get_extension() == "pz"));
249 
250  Filename local_filename(_local_filename);
251  if (do_compress) {
252  // .pz files are always binary, of course.
253  local_filename.set_binary();
254  }
255 
256  return _mount->open_write_file(local_filename, do_compress, truncate);
257 }
258 
259 /**
260  * Works like open_write_file(), but the file is opened in append mode. Like
261  * open_write_file, the returned pointer should eventually be passed to
262  * close_write_file().
263  */
266  return _mount->open_append_file(_local_filename);
267 }
268 
269 /**
270  * Closes a file opened by a previous call to open_write_file(). This really
271  * just deletes the ostream pointer, but it is recommended to use this
272  * interface instead of deleting it explicitly, to help work around compiler
273  * issues.
274  */
276 close_write_file(ostream *stream) {
277  _mount->close_write_file(stream);
278 }
279 
280 /**
281  * Opens the file for writing. Returns a newly allocated iostream on success
282  * (which you should eventually delete when you are done writing). Returns
283  * NULL on failure.
284  */
286 open_read_write_file(bool truncate) {
287  return _mount->open_read_write_file(_local_filename, truncate);
288 }
289 
290 /**
291  * Works like open_read_write_file(), but the file is opened in append mode.
292  * Like open_read_write_file, the returned pointer should eventually be passed
293  * to close_read_write_file().
294  */
297  return _mount->open_read_append_file(_local_filename);
298 }
299 
300 /**
301  * Closes a file opened by a previous call to open_read_write_file(). This
302  * really just deletes the iostream pointer, but it is recommended to use this
303  * interface instead of deleting it explicitly, to help work around compiler
304  * issues.
305  */
307 close_read_write_file(iostream *stream) {
308  _mount->close_read_write_file(stream);
309 }
310 
311 /**
312  * Returns the current size on disk (or wherever it is) of the already-open
313  * file. Pass in the stream that was returned by open_read_file(); some
314  * implementations may require this stream to determine the size.
315  */
316 std::streamsize VirtualFileSimple::
317 get_file_size(istream *stream) const {
318  return _mount->get_file_size(_local_filename, stream);
319 }
320 
321 /**
322  * Returns the current size on disk (or wherever it is) of the file before it
323  * has been opened.
324  */
325 std::streamsize VirtualFileSimple::
326 get_file_size() const {
327  return _mount->get_file_size(_local_filename);
328 }
329 
330 /**
331  * Returns a time_t value that represents the time the file was last modified,
332  * to within whatever precision the operating system records this information
333  * (on a Windows95 system, for instance, this may only be accurate to within 2
334  * seconds).
335  *
336  * If the timestamp cannot be determined, either because it is not supported
337  * by the operating system or because there is some error (such as file not
338  * found), returns 0.
339  */
341 get_timestamp() const {
342  return _mount->get_timestamp(_local_filename);
343 }
344 
345 /**
346  * Populates the SubfileInfo structure with the data representing where the
347  * file actually resides on disk, if this is knowable. Returns true if the
348  * file might reside on disk, and the info is populated, or false if it does
349  * not (or it is not known where the file resides), in which case the info is
350  * meaningless.
351  */
354  return _mount->get_system_info(_local_filename, info);
355 }
356 
357 /**
358  * See Filename::atomic_compare_and_exchange_contents().
359  */
361 atomic_compare_and_exchange_contents(string &orig_contents,
362  const string &old_contents,
363  const string &new_contents) {
364  return _mount->atomic_compare_and_exchange_contents(_local_filename, orig_contents, old_contents, new_contents);
365 }
366 
367 /**
368  * See Filename::atomic_read_contents().
369  */
371 atomic_read_contents(string &contents) const {
372  return _mount->atomic_read_contents(_local_filename, contents);
373 }
374 
375 /**
376  * Fills up the indicated pvector with the contents of the file, if it is a
377  * regular file. Returns true on success, false otherwise.
378  */
380 read_file(vector_uchar &result, bool auto_unwrap) const {
381 
382  // Will we be automatically unwrapping a .pz file?
383  bool do_uncompress = (_implicit_pz_file ||
384  (auto_unwrap && (_local_filename.get_extension() == "pz" ||
385  _local_filename.get_extension() == "gz")));
386 
387  Filename local_filename(_local_filename);
388  if (do_uncompress) {
389  // .pz files are always binary, of course.
390  local_filename.set_binary();
391  }
392 
393  return _mount->read_file(local_filename, do_uncompress, result);
394 }
395 
396 /**
397  * Writes the indicated data to the file, if it is writable. Returns true on
398  * success, false otherwise.
399  */
401 write_file(const unsigned char *data, size_t data_size, bool auto_wrap) {
402  // Will we be automatically wrapping a .pz file?
403  bool do_compress = (_implicit_pz_file || (auto_wrap && _local_filename.get_extension() == "pz"));
404 
405  Filename local_filename(_local_filename);
406  if (do_compress) {
407  // .pz files are always binary, of course.
408  local_filename.set_binary();
409  }
410 
411  return _mount->write_file(local_filename, do_compress, data, data_size);
412 }
413 
414 /**
415  * Fills file_list up with the list of files that are within this directory,
416  * excluding those whose basenames are listed in mount_points. Returns true
417  * if successful, false if the file is not a directory or the directory cannot
418  * be read.
419  */
420 bool VirtualFileSimple::
421 scan_local_directory(VirtualFileList *file_list,
422  const ov_set<string> &mount_points) const {
423  vector_string names;
424  if (!_mount->scan_directory(names, _local_filename)) {
425  return false;
426  }
427 
428  // Now the scan above gave us a list of basenames. Turn these back into
429  // VirtualFile pointers.
430 
431  // Each of the files returned by the mount will be just a simple file within
432  // the same mount tree, unless it is shadowed by a mount point listed in
433  // mount_points.
434 
435  vector_string::const_iterator ni;
436  for (ni = names.begin(); ni != names.end(); ++ni) {
437  const string &basename = (*ni);
438  if (mount_points.find(basename) == mount_points.end()) {
439  Filename filename(_local_filename, basename);
440  VirtualFileSimple *file = new VirtualFileSimple(_mount, filename, false, 0);
441  file_list->add_file(file);
442  }
443  }
444 
445  return true;
446 }
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
void set_binary()
Indicates that the filename represents a binary file.
Definition: filename.I:414
std::string get_fullpath() const
Returns the entire filename: directory, basename, extension.
Definition: filename.I:338
std::string get_extension() const
Returns the file extension.
Definition: filename.I:400
This class records a particular byte sub-range within an existing file on disk.
Definition: subfileInfo.h:26
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
A list of VirtualFiles, as returned by VirtualFile::scan_directory().
void add_file(VirtualFile *file)
Adds a new file to the list.
virtual std::iostream * open_read_write_file(const Filename &file, bool truncate)
Opens the file for writing.
virtual bool atomic_read_contents(const Filename &file, std::string &contents) const
See Filename::atomic_read_contents().
virtual bool is_writable(const Filename &file) const
Returns true if the named file or directory may be written to, false otherwise.
const Filename & get_mount_point() const
Returns the name of the directory within the virtual file system that this mount object is attached t...
virtual bool delete_file(const Filename &file)
Attempts to delete the indicated file or directory within the mount.
virtual bool read_file(const Filename &file, bool do_uncompress, vector_uchar &result) const
Fills up the indicated pvector with the contents of the file, if it is a regular file.
virtual void close_write_file(std::ostream *stream)
Closes a file opened by a previous call to open_write_file().
virtual void close_read_write_file(std::iostream *stream)
Closes a file opened by a previous call to open_read_write_file().
virtual bool copy_file(const Filename &orig_filename, const Filename &new_filename)
Attempts to copy the contents of the indicated file to the indicated file.
virtual bool write_file(const Filename &file, bool do_compress, const unsigned char *data, size_t data_size)
Writes the indicated data to the file, if it is a writable file.
VirtualFileSystem * get_file_system() const
Returns the file system this mount object is attached to.
virtual std::ostream * open_write_file(const Filename &file, bool truncate)
Opens the file for writing.
virtual std::ostream * open_append_file(const Filename &file)
Works like open_write_file(), but the file is opened in append mode.
virtual bool get_system_info(const Filename &file, SubfileInfo &info)
Populates the SubfileInfo structure with the data representing where the file actually resides on dis...
virtual bool atomic_compare_and_exchange_contents(const Filename &file, std::string &orig_contents, const std::string &old_contents, const std::string &new_contents)
See Filename::atomic_compare_and_exchange_contents().
virtual std::iostream * open_read_append_file(const Filename &file)
Works like open_read_write_file(), but the file is opened in append mode.
virtual bool rename_file(const Filename &orig_filename, const Filename &new_filename)
Attempts to rename the contents of the indicated file to the indicated file.
virtual void close_read_file(std::istream *stream) const
Closes a file opened by a previous call to open_read_file().
A simple file or directory within the VirtualFileSystem: this maps to exactly one file on one mount p...
virtual bool read_file(vector_uchar &result, bool auto_unwrap) const
Fills up the indicated pvector with the contents of the file, if it is a regular file.
virtual std::ostream * open_append_file()
Works like open_write_file(), but the file is opened in append mode.
virtual bool atomic_compare_and_exchange_contents(std::string &orig_contents, const std::string &old_contents, const std::string &new_contents)
See Filename::atomic_compare_and_exchange_contents().
virtual bool atomic_read_contents(std::string &contents) const
See Filename::atomic_read_contents().
virtual bool get_system_info(SubfileInfo &info)
Populates the SubfileInfo structure with the data representing where the file actually resides on dis...
virtual bool is_regular_file() const
Returns true if this file represents a regular file (and read_file() may be called),...
virtual bool has_file() const
Returns true if this file exists, false otherwise.
virtual std::ostream * open_write_file(bool auto_wrap, bool truncate)
Opens the file for writing.
virtual VirtualFileSystem * get_file_system() const
Returns the VirtualFileSystem this file is associated with.
virtual bool delete_file()
Attempts to delete this file or directory.
virtual bool write_file(const unsigned char *data, size_t data_size, bool auto_wrap)
Writes the indicated data to the file, if it is writable.
virtual bool copy_file(VirtualFile *new_file)
Attempts to copy the contents of this file to the indicated file.
virtual std::iostream * open_read_write_file(bool truncate)
Opens the file for writing.
virtual std::istream * open_read_file(bool auto_unwrap) const
Opens the file for reading.
virtual time_t get_timestamp() const
Returns a time_t value that represents the time the file was last modified, to within whatever precis...
virtual std::iostream * open_read_append_file()
Works like open_read_write_file(), but the file is opened in append mode.
virtual void close_write_file(std::ostream *stream)
Closes a file opened by a previous call to open_write_file().
virtual void close_read_file(std::istream *stream) const
Closes a file opened by a previous call to open_read_file().
virtual bool rename_file(VirtualFile *new_file)
Attempts to move or rename this file or directory.
virtual bool is_directory() const
Returns true if this file represents a directory (and scan_directory() may be called),...
virtual bool is_writable() const
Returns true if this file represents a writable regular file (and write_file() may be called),...
virtual void close_read_write_file(std::iostream *stream)
Closes a file opened by a previous call to open_read_write_file().
virtual Filename get_filename() const
Returns the full pathname to this file within the virtual file system.
virtual std::streamsize get_file_size() const
Returns the current size on disk (or wherever it is) of the file before it has been opened.
A hierarchy of directories and files that appears to be one continuous file system,...
The abstract base class for a file or directory within the VirtualFileSystem.
Definition: virtualFile.h:35
virtual bool delete_file()
Attempts to delete this file or directory.
Definition: virtualFile.cxx:69
virtual std::ostream * open_write_file(bool auto_wrap, bool truncate)
Opens the file for writing.
virtual bool is_directory() const
Returns true if this file represents a directory (and scan_directory() may be called),...
Definition: virtualFile.cxx:41
virtual void close_write_file(std::ostream *stream)
Closes a file opened by a previous call to open_write_file().
iterator_0 end()
Returns the iterator that marks the end of the ordered vector.
A specialization of ordered_vector that emulates a standard STL set: one copy of each element is allo...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.