Panda3D
 All Classes Functions Variables Enumerations
virtualFile.cxx
1 // Filename: virtualFile.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 "virtualFile.h"
16 #include "virtualFileSystem.h"
17 #include "virtualFileList.h"
18 #include "config_express.h"
19 #include "pvector.h"
20 #include <iterator>
21 
22 TypeHandle VirtualFile::_type_handle;
23 
24 ////////////////////////////////////////////////////////////////////
25 // Function: VirtualFile::has_file
26 // Access: Published, Virtual
27 // Description: Returns true if this file exists, false otherwise.
28 ////////////////////////////////////////////////////////////////////
29 bool VirtualFile::
30 has_file() const {
31  return false;
32 }
33 
34 ////////////////////////////////////////////////////////////////////
35 // Function: VirtualFile::is_directory
36 // Access: Published, Virtual
37 // Description: Returns true if this file represents a directory (and
38 // scan_directory() may be called), false otherwise.
39 ////////////////////////////////////////////////////////////////////
40 bool VirtualFile::
41 is_directory() const {
42  return false;
43 }
44 
45 ////////////////////////////////////////////////////////////////////
46 // Function: VirtualFile::is_regular_file
47 // Access: Published, Virtual
48 // Description: Returns true if this file represents a regular file
49 // (and read_file() may be called), false otherwise.
50 ////////////////////////////////////////////////////////////////////
51 bool VirtualFile::
52 is_regular_file() const {
53  return false;
54 }
55 
56 ////////////////////////////////////////////////////////////////////
57 // Function: VirtualFile::is_writable
58 // Access: Published, Virtual
59 // Description: Returns true if this file may be written to, which
60 // implies write_file() may be called (unless it is a
61 // directory instead of a regular file).
62 ////////////////////////////////////////////////////////////////////
63 bool VirtualFile::
64 is_writable() const {
65  return false;
66 }
67 
68 ////////////////////////////////////////////////////////////////////
69 // Function: VirtualFile::delete_file
70 // Access: Public
71 // Description: Attempts to delete this file or directory. This can
72 // remove a single file or an empty directory. It will
73 // not remove a nonempty directory. Returns true on
74 // success, false on failure.
75 ////////////////////////////////////////////////////////////////////
76 bool VirtualFile::
78  return false;
79 }
80 
81 ////////////////////////////////////////////////////////////////////
82 // Function: VirtualFile::rename_file
83 // Access: Public
84 // Description: Attempts to move or rename this file or directory.
85 // If the original file is an ordinary file, it will
86 // quietly replace any already-existing file in the new
87 // filename (but not a directory). If the original file
88 // is a directory, the new filename must not already
89 // exist.
90 //
91 // If the file is a directory, the new filename must be
92 // within the same mount point. If the file is an
93 // ordinary file, the new filename may be anywhere; but
94 // if it is not within the same mount point then the
95 // rename operation is automatically performed as a
96 // two-step copy-and-delete operation.
97 ////////////////////////////////////////////////////////////////////
98 bool VirtualFile::
100  return false;
101 }
102 
103 ////////////////////////////////////////////////////////////////////
104 // Function: VirtualFile::copy_file
105 // Access: Public
106 // Description: Attempts to copy the contents of this file to the
107 // indicated file. Returns true on success, false on
108 // failure.
109 ////////////////////////////////////////////////////////////////////
110 bool VirtualFile::
111 copy_file(VirtualFile *new_file) {
112  return false;
113 }
114 
115 ////////////////////////////////////////////////////////////////////
116 // Function: VirtualFile::scan_directory
117 // Access: Published
118 // Description: If the file represents a directory (that is,
119 // is_directory() returns true), this returns the list
120 // of files within the directory at the current time.
121 // Returns NULL if the file is not a directory or if the
122 // directory cannot be read.
123 ////////////////////////////////////////////////////////////////////
125 scan_directory() const {
126  // First, we have to make sure there aren't any mount points attached
127  // under this directory. These will override any local filenames.
128  VirtualFileSystem *file_system = get_file_system();
129  Filename this_filename = get_filename();
130  vector_string mount_points_flat;
131  file_system->scan_mount_points(mount_points_flat, this_filename);
132 
133  // Copy the set of nested mount points to a sorted list so we can
134  // search it quickly.
135  ov_set<string> mount_points;
136  copy(mount_points_flat.begin(), mount_points_flat.end(),
137  back_inserter(mount_points));
138  mount_points.sort();
139 
140 
141  PT(VirtualFileList) file_list = new VirtualFileList;
142 
143  // Each of those mount points maps to a directory root or something
144  // from the file system.
145  ov_set<string>::const_iterator mi;
146  for (mi = mount_points.begin(); mi != mount_points.end(); ++mi) {
147  const string &basename = (*mi);
148  Filename filename(this_filename, basename);
149  PT(VirtualFile) file = file_system->get_file(filename);
150  file_list->add_file(file);
151  }
152 
153  // Now, get the actual local files in this directory.
154  vector_string names;
155  if (!scan_local_directory(file_list, mount_points)) {
156  // Not a directory, or unable to read directory.
157  if (file_list->get_num_files() == 0) {
158  return NULL;
159  }
160 
161  // We couldn't read the physical directory, but we do have some
162  // mounted files to return.
163  return file_list;
164  }
165 
166  return file_list;
167 }
168 
169 ////////////////////////////////////////////////////////////////////
170 // Function: VirtualFile::output
171 // Access: Published
172 // Description:
173 ////////////////////////////////////////////////////////////////////
174 void VirtualFile::
175 output(ostream &out) const {
176  out << get_filename();
177 }
178 
179 ////////////////////////////////////////////////////////////////////
180 // Function: VirtualFile::ls
181 // Access: Published
182 // Description: If the file represents a directory, lists its
183 // contents.
184 ////////////////////////////////////////////////////////////////////
185 void VirtualFile::
186 ls(ostream &out) const {
187  CPT(VirtualFileList) contents = scan_directory();
188  if (contents == (VirtualFileList *)NULL) {
189  if (!is_directory()) {
190  out << get_filename() << "\n";
191  } else {
192  out << get_filename() << " cannot be read.\n";
193  }
194  return;
195  }
196 
197  int num_files = contents->get_num_files();
198  for (int i = 0; i < num_files; i++) {
199  VirtualFile *file = contents->get_file(i);
200  out << file->get_filename().get_basename() << "\n";
201  }
202 }
203 
204 ////////////////////////////////////////////////////////////////////
205 // Function: VirtualFile::ls_all
206 // Access: Published
207 // Description: If the file represents a directory, recursively lists
208 // its contents and those of all subdirectories.
209 ////////////////////////////////////////////////////////////////////
210 void VirtualFile::
211 ls_all(ostream &out) const {
212  if (!is_directory()) {
213  out << get_filename() << " is not a directory.\n";
214  } else {
215  r_ls_all(out, get_filename());
216  }
217 }
218 
219 ////////////////////////////////////////////////////////////////////
220 // Function: VirtualFile::open_read_file
221 // Access: Published, Virtual
222 // Description: Opens the file for reading. Returns a newly
223 // allocated istream on success (which you should
224 // eventually delete when you are done reading).
225 // Returns NULL on failure.
226 ////////////////////////////////////////////////////////////////////
227 istream *VirtualFile::
228 open_read_file(bool auto_unwrap) const {
229  return NULL;
230 }
231 
232 ////////////////////////////////////////////////////////////////////
233 // Function: VirtualFile::close_read_file
234 // Access: Published
235 // Description: Closes a file opened by a previous call to
236 // open_read_file(). This really just deletes the
237 // istream pointer, but it is recommended to use this
238 // interface instead of deleting it explicitly, to help
239 // work around compiler issues.
240 ////////////////////////////////////////////////////////////////////
241 void VirtualFile::
242 close_read_file(istream *stream) const {
243  nassertv(false);
244 }
245 
246 ////////////////////////////////////////////////////////////////////
247 // Function: VirtualFile::was_read_successful
248 // Access: Published, Virtual
249 // Description: Call this method after a reading the istream returned
250 // by open_read_file() to completion. If it returns
251 // true, the file was read completely and without error;
252 // if it returns false, there may have been some errors
253 // or a truncated file read. This is particularly
254 // likely if the stream is a VirtualFileHTTP.
255 ////////////////////////////////////////////////////////////////////
256 bool VirtualFile::
258  return true;
259 }
260 
261 ////////////////////////////////////////////////////////////////////
262 // Function: VirtualFile::open_write_file
263 // Access: Published, Virtual
264 // Description: Opens the file for writing. Returns a newly
265 // allocated ostream on success (which you should
266 // eventually delete when you are done writing).
267 // Returns NULL on failure.
268 ////////////////////////////////////////////////////////////////////
269 ostream *VirtualFile::
270 open_write_file(bool auto_wrap, bool truncate) {
271  return NULL;
272 }
273 
274 ////////////////////////////////////////////////////////////////////
275 // Function: VirtualFile::open_append_file
276 // Access: Published, Virtual
277 // Description: Works like open_write_file(), but the file is opened
278 // in append mode. Like open_write_file, the returned
279 // pointer should eventually be passed to
280 // close_write_file().
281 ////////////////////////////////////////////////////////////////////
282 ostream *VirtualFile::
284  return NULL;
285 }
286 
287 ////////////////////////////////////////////////////////////////////
288 // Function: VirtualFile::close_write_file
289 // Access: Published
290 // Description: Closes a file opened by a previous call to
291 // open_write_file(). This really just deletes the
292 // ostream pointer, but it is recommended to use this
293 // interface instead of deleting it explicitly, to help
294 // work around compiler issues.
295 ////////////////////////////////////////////////////////////////////
296 void VirtualFile::
297 close_write_file(ostream *stream) {
298  nassertv(false);
299 }
300 
301 ////////////////////////////////////////////////////////////////////
302 // Function: VirtualFile::open_read_write_file
303 // Access: Published, Virtual
304 // Description: Opens the file for writing. Returns a newly
305 // allocated iostream on success (which you should
306 // eventually delete when you are done writing).
307 // Returns NULL on failure.
308 ////////////////////////////////////////////////////////////////////
309 iostream *VirtualFile::
310 open_read_write_file(bool truncate) {
311  return NULL;
312 }
313 
314 ////////////////////////////////////////////////////////////////////
315 // Function: VirtualFile::open_read_append_file
316 // Access: Published, Virtual
317 // Description: Works like open_read_write_file(), but the file is opened
318 // in append mode. Like open_read_write_file, the returned
319 // pointer should eventually be passed to
320 // close_read_write_file().
321 ////////////////////////////////////////////////////////////////////
322 iostream *VirtualFile::
324  return NULL;
325 }
326 
327 ////////////////////////////////////////////////////////////////////
328 // Function: VirtualFile::close_read_write_file
329 // Access: Published
330 // Description: Closes a file opened by a previous call to
331 // open_read_write_file(). This really just deletes the
332 // iostream pointer, but it is recommended to use this
333 // interface instead of deleting it explicitly, to help
334 // work around compiler issues.
335 ////////////////////////////////////////////////////////////////////
336 void VirtualFile::
337 close_read_write_file(iostream *stream) {
338  nassertv(false);
339 }
340 
341 ////////////////////////////////////////////////////////////////////
342 // Function: VirtualFile::get_file_size
343 // Access: Published, Virtual
344 // Description: Returns the current size on disk (or wherever it is)
345 // of the already-open file. Pass in the stream that
346 // was returned by open_read_file(); some
347 // implementations may require this stream to determine
348 // the size.
349 ////////////////////////////////////////////////////////////////////
350 streamsize VirtualFile::
351 get_file_size(istream *stream) const {
352  return get_file_size();
353 }
354 
355 ////////////////////////////////////////////////////////////////////
356 // Function: VirtualFile::get_file_size
357 // Access: Published, Virtual
358 // Description: Returns the current size on disk (or wherever it is)
359 // of the file before it has been opened.
360 ////////////////////////////////////////////////////////////////////
361 streamsize VirtualFile::
362 get_file_size() const {
363  return 0;
364 }
365 
366 ////////////////////////////////////////////////////////////////////
367 // Function: VirtualFile::get_timestamp
368 // Access: Published, Virtual
369 // Description: Returns a time_t value that represents the time the
370 // file was last modified, to within whatever precision
371 // the operating system records this information (on a
372 // Windows95 system, for instance, this may only be
373 // accurate to within 2 seconds).
374 //
375 // If the timestamp cannot be determined, either because
376 // it is not supported by the operating system or
377 // because there is some error (such as file not found),
378 // returns 0.
379 ////////////////////////////////////////////////////////////////////
380 time_t VirtualFile::
381 get_timestamp() const {
382  return 0;
383 }
384 
385 ////////////////////////////////////////////////////////////////////
386 // Function: VirtualFile::get_system_info
387 // Access: Published, Virtual
388 // Description: Populates the SubfileInfo structure with the data
389 // representing where the file actually resides on disk,
390 // if this is knowable. Returns true if the file might
391 // reside on disk, and the info is populated, or false
392 // if it does not (or it is not known where the file
393 // resides), in which case the info is meaningless.
394 ////////////////////////////////////////////////////////////////////
395 bool VirtualFile::
397  return false;
398 }
399 
400 ////////////////////////////////////////////////////////////////////
401 // Function: VirtualFile::atomic_compare_and_exchange_contents
402 // Access: Public, Virtual
403 // Description: See Filename::atomic_compare_and_exchange_contents().
404 ////////////////////////////////////////////////////////////////////
405 bool VirtualFile::
407  const string &old_contents,
408  const string &new_contents) {
409  return false;
410 }
411 
412 ////////////////////////////////////////////////////////////////////
413 // Function: VirtualFile::atomic_read_contents
414 // Access: Public, Virtual
415 // Description: See Filename::atomic_read_contents().
416 ////////////////////////////////////////////////////////////////////
417 bool VirtualFile::
418 atomic_read_contents(string &contents) const {
419  return false;
420 }
421 
422 ////////////////////////////////////////////////////////////////////
423 // Function: VirtualFile::read_file
424 // Access: Public
425 // Description: Fills up the indicated string with the contents of
426 // the file, if it is a regular file. Returns true on
427 // success, false otherwise.
428 ////////////////////////////////////////////////////////////////////
429 bool VirtualFile::
430 read_file(string &result, bool auto_unwrap) const {
431  result = string();
432 
434  if (!read_file(pv, auto_unwrap)) {
435  return false;
436  }
437 
438  if (!pv.empty()) {
439  result.append((const char *)&pv[0], pv.size());
440  }
441 
442  return true;
443 }
444 
445 ////////////////////////////////////////////////////////////////////
446 // Function: VirtualFile::read_file
447 // Access: Public, Virtual
448 // Description: Fills up the indicated pvector with the contents of
449 // the file, if it is a regular file. Returns true on
450 // success, false otherwise.
451 ////////////////////////////////////////////////////////////////////
452 bool VirtualFile::
453 read_file(pvector<unsigned char> &result, bool auto_unwrap) const {
454  return false;
455 }
456 
457 ////////////////////////////////////////////////////////////////////
458 // Function: VirtualFile::write_file
459 // Access: Public, Virtual
460 // Description: Writes the indicated data to the file, if it is
461 // writable. Returns true on success, false otherwise.
462 ////////////////////////////////////////////////////////////////////
463 bool VirtualFile::
464 write_file(const unsigned char *data, size_t data_size, bool auto_wrap) {
465  return false;
466 }
467 
468 ////////////////////////////////////////////////////////////////////
469 // Function: VirtualFile::simple_read_file
470 // Access: Public, Static
471 // Description: Fills up the indicated pvector with the contents of
472 // the just-opened file. Returns true on success, false
473 // otherwise. If the pvector was not empty on entry, the
474 // data read from the file will be appended onto it.
475 ////////////////////////////////////////////////////////////////////
476 bool VirtualFile::
478  static const size_t buffer_size = 4096;
479  char buffer[buffer_size];
480 
481  in->read(buffer, buffer_size);
482  size_t count = in->gcount();
483  while (count != 0) {
484  thread_consider_yield();
485  result.insert(result.end(), buffer, buffer + count);
486  in->read(buffer, buffer_size);
487  count = in->gcount();
488  }
489 
490  return (!in->fail() || in->eof());
491 }
492 
493 ////////////////////////////////////////////////////////////////////
494 // Function: VirtualFile::simple_read_file
495 // Access: Public
496 // Description: As in simple_read_file() with two parameters, above,
497 // but only reads up to max_bytes bytes from the file.
498 ////////////////////////////////////////////////////////////////////
499 bool VirtualFile::
500 simple_read_file(istream *in, pvector<unsigned char> &result, size_t max_bytes) {
501  static const size_t buffer_size = 4096;
502  char buffer[buffer_size];
503 
504  in->read(buffer, min(buffer_size, max_bytes));
505  size_t count = in->gcount();
506  while (count != 0) {
507  thread_consider_yield();
508  nassertr(count <= max_bytes, false);
509  result.insert(result.end(), buffer, buffer + count);
510  max_bytes -= count;
511  in->read(buffer, min(buffer_size, max_bytes));
512  count = in->gcount();
513  }
514 
515  return (!in->fail() || in->eof());
516 }
517 
518 ////////////////////////////////////////////////////////////////////
519 // Function: VirtualFile::scan_local_directory
520 // Access: Protected, Virtual
521 // Description: Fills file_list up with the list of files that are
522 // within this directory, excluding those whose
523 // basenames are listed in mount_points. Returns true
524 // if successful, false if the file is not a directory
525 // or the directory cannot be read.
526 ////////////////////////////////////////////////////////////////////
527 bool VirtualFile::
528 scan_local_directory(VirtualFileList *, const ov_set<string> &) const {
529  return false;
530 }
531 
532 ////////////////////////////////////////////////////////////////////
533 // Function: VirtualFile::r_ls_all
534 // Access: Private
535 // Description: The recursive implementation of ls_all().
536 ////////////////////////////////////////////////////////////////////
537 void VirtualFile::
538 r_ls_all(ostream &out, const Filename &root) const {
539  CPT(VirtualFileList) contents = scan_directory();
540  if (contents == (VirtualFileList *)NULL) {
541  return;
542  }
543 
544  int num_files = contents->get_num_files();
545  for (int i = 0; i < num_files; i++) {
546  VirtualFile *file = contents->get_file(i);
547  Filename filename = file->get_filename();
548  filename.make_relative_to(root);
549  out << filename << "\n";
550  if (file->is_directory()) {
551  file->r_ls_all(out, root);
552  }
553  }
554 }
void scan_mount_points(vector_string &names, const Filename &path) const
Adds to names a list of all the mount points in use that are one directory below path, if any.
void ls_all(ostream &out=cout) const
If the file represents a directory, recursively lists its contents and those of all subdirectories...
virtual ostream * open_append_file()
Works like open_write_file(), but the file is opened in append mode.
virtual istream * open_read_file(bool auto_unwrap) const
Opens the file for reading.
virtual void close_read_write_file(iostream *stream)
Closes a file opened by a previous call to open_read_write_file().
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.
virtual bool atomic_read_contents(string &contents) const
See Filename::atomic_read_contents().
virtual ostream * open_write_file(bool auto_wrap, bool truncate)
Opens the file for writing.
iterator_0 begin()
Returns the iterator that marks the first element in the ordered vector.
virtual bool copy_file(VirtualFile *new_file)
Attempts to copy the contents of this file to the indicated file.
virtual bool is_writable() const
Returns true if this file may be written to, which implies write_file() may be called (unless it is a...
Definition: virtualFile.cxx:64
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
PointerTo< VirtualFileList > scan_directory() const
If the file represents a directory (that is, is_directory() returns true), this returns the list of f...
A specialization of ordered_vector that emulates a standard STL set: one copy of each element is allo...
virtual bool is_regular_file() const
Returns true if this file represents a regular file (and read_file() may be called), false otherwise.
Definition: virtualFile.cxx:52
virtual bool has_file() const
Returns true if this file exists, false otherwise.
Definition: virtualFile.cxx:30
virtual bool get_system_info(SubfileInfo &info)
Populates the SubfileInfo structure with the data representing where the file actually resides on dis...
virtual iostream * open_read_write_file(bool truncate)
Opens the file for writing.
virtual time_t get_timestamp() const
Returns a time_t value that represents the time the file was last modified, to within whatever precis...
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
void sort()
Maps to sort_unique().
virtual iostream * open_read_append_file()
Works like open_read_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
void ls(ostream &out=cout) const
If the file represents a directory, lists its contents.
virtual void close_read_file(istream *stream) const
Closes a file opened by a previous call to open_read_file().
bool make_relative_to(Filename directory, bool allow_backups=true)
Adjusts this filename, which must be a fully-specified pathname beginning with a slash, to make it a relative filename, relative to the fully-specified directory indicated (which must also begin with, and may or may not end with, a slash–a terminating slash is ignored).
Definition: filename.cxx:1766
PointerTo< VirtualFile > get_file(const Filename &filename, bool status_only=false) const
Looks up the file by the indicated name in the file system.
bool write_file(const string &data, bool auto_wrap)
Writes the entire contents of the file as a string, if it is writable.
Definition: virtualFile.I:56
string get_basename() const
Returns the basename part of the filename.
Definition: filename.I:436
virtual bool was_read_successful() const
Call this method after a reading the istream returned by open_read_file() to completion.
string read_file(bool auto_unwrap) const
Returns the entire contents of the file as a string.
Definition: virtualFile.I:43
virtual bool rename_file(VirtualFile *new_file)
Attempts to move or rename this file or directory.
Definition: virtualFile.cxx:99
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().
This class records a particular byte sub-range within an existing file on disk.
Definition: subfileInfo.h:29
virtual streamsize get_file_size() const
Returns the current size on disk (or wherever it is) of the file before it has been opened...
static bool simple_read_file(istream *stream, pvector< unsigned char > &result)
Fills up the indicated pvector with the contents of the just-opened file.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
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