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