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