Panda3D
 All Classes Functions Variables Enumerations
virtualFile.cxx
00001 // Filename: virtualFile.cxx
00002 // Created by:  drose (03Aug02)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "virtualFile.h"
00016 #include "virtualFileSystem.h"
00017 #include "virtualFileList.h"
00018 #include "config_express.h"
00019 #include "pvector.h"
00020 #include <iterator>
00021 
00022 TypeHandle VirtualFile::_type_handle;
00023 
00024 ////////////////////////////////////////////////////////////////////
00025 //     Function: VirtualFile::has_file
00026 //       Access: Published, Virtual
00027 //  Description: Returns true if this file exists, false otherwise.
00028 ////////////////////////////////////////////////////////////////////
00029 bool VirtualFile::
00030 has_file() const {
00031   return false;
00032 }
00033 
00034 ////////////////////////////////////////////////////////////////////
00035 //     Function: VirtualFile::is_directory
00036 //       Access: Published, Virtual
00037 //  Description: Returns true if this file represents a directory (and
00038 //               scan_directory() may be called), false otherwise.
00039 ////////////////////////////////////////////////////////////////////
00040 bool VirtualFile::
00041 is_directory() const {
00042   return false;
00043 }
00044 
00045 ////////////////////////////////////////////////////////////////////
00046 //     Function: VirtualFile::is_regular_file
00047 //       Access: Published, Virtual
00048 //  Description: Returns true if this file represents a regular file
00049 //               (and read_file() may be called), false otherwise.
00050 ////////////////////////////////////////////////////////////////////
00051 bool VirtualFile::
00052 is_regular_file() const {
00053   return false;
00054 }
00055 
00056 ////////////////////////////////////////////////////////////////////
00057 //     Function: VirtualFile::is_writable
00058 //       Access: Published, Virtual
00059 //  Description: Returns true if this file may be written to, which
00060 //               implies write_file() may be called (unless it is a
00061 //               directory instead of a regular file).
00062 ////////////////////////////////////////////////////////////////////
00063 bool VirtualFile::
00064 is_writable() const {
00065   return false;
00066 }
00067 
00068 ////////////////////////////////////////////////////////////////////
00069 //     Function: VirtualFile::delete_file
00070 //       Access: Public
00071 //  Description: Attempts to delete this file or directory.  This can
00072 //               remove a single file or an empty directory.  It will
00073 //               not remove a nonempty directory.  Returns true on
00074 //               success, false on failure.
00075 ////////////////////////////////////////////////////////////////////
00076 bool VirtualFile::
00077 delete_file() {
00078   return false;
00079 }
00080 
00081 ////////////////////////////////////////////////////////////////////
00082 //     Function: VirtualFile::rename_file
00083 //       Access: Public
00084 //  Description: Attempts to move or rename this file or directory.
00085 //               If the original file is an ordinary file, it will
00086 //               quietly replace any already-existing file in the new
00087 //               filename (but not a directory).  If the original file
00088 //               is a directory, the new filename must not already
00089 //               exist.
00090 //
00091 //               If the file is a directory, the new filename must be
00092 //               within the same mount point.  If the file is an
00093 //               ordinary file, the new filename may be anywhere; but
00094 //               if it is not within the same mount point then the
00095 //               rename operation is automatically performed as a
00096 //               two-step copy-and-delete operation.
00097 ////////////////////////////////////////////////////////////////////
00098 bool VirtualFile::
00099 rename_file(VirtualFile *new_file) {
00100   return false;
00101 }
00102 
00103 ////////////////////////////////////////////////////////////////////
00104 //     Function: VirtualFile::copy_file
00105 //       Access: Public
00106 //  Description: Attempts to copy the contents of this file to the
00107 //               indicated file.  Returns true on success, false on
00108 //               failure.
00109 ////////////////////////////////////////////////////////////////////
00110 bool VirtualFile::
00111 copy_file(VirtualFile *new_file) {
00112   return false;
00113 }
00114 
00115 ////////////////////////////////////////////////////////////////////
00116 //     Function: VirtualFile::scan_directory
00117 //       Access: Published
00118 //  Description: If the file represents a directory (that is,
00119 //               is_directory() returns true), this returns the list
00120 //               of files within the directory at the current time.
00121 //               Returns NULL if the file is not a directory or if the
00122 //               directory cannot be read.
00123 ////////////////////////////////////////////////////////////////////
00124 PT(VirtualFileList) VirtualFile::
00125 scan_directory() const {
00126   // First, we have to make sure there aren't any mount points attached
00127   // under this directory.  These will override any local filenames.
00128   VirtualFileSystem *file_system = get_file_system();
00129   Filename this_filename = get_filename();
00130   vector_string mount_points_flat;
00131   file_system->scan_mount_points(mount_points_flat, this_filename);
00132 
00133   // Copy the set of nested mount points to a sorted list so we can
00134   // search it quickly.
00135   ov_set<string> mount_points;
00136   copy(mount_points_flat.begin(), mount_points_flat.end(),
00137        back_inserter(mount_points));
00138   mount_points.sort();
00139 
00140   
00141   PT(VirtualFileList) file_list = new VirtualFileList;
00142 
00143   // Each of those mount points maps to a directory root or something
00144   // from the file system.
00145   ov_set<string>::const_iterator mi;
00146   for (mi = mount_points.begin(); mi != mount_points.end(); ++mi) {
00147     const string &basename = (*mi);
00148     Filename filename(this_filename, basename);
00149     PT(VirtualFile) file = file_system->get_file(filename);
00150     file_list->add_file(file);
00151   }
00152 
00153   // Now, get the actual local files in this directory.
00154   vector_string names;
00155   if (!scan_local_directory(file_list, mount_points)) {
00156     // Not a directory, or unable to read directory.
00157     if (file_list->get_num_files() == 0) {
00158       return NULL;
00159     }
00160 
00161     // We couldn't read the physical directory, but we do have some
00162     // mounted files to return.
00163     return file_list;
00164   }
00165 
00166   return file_list;
00167 }
00168 
00169 ////////////////////////////////////////////////////////////////////
00170 //     Function: VirtualFile::output
00171 //       Access: Published
00172 //  Description: 
00173 ////////////////////////////////////////////////////////////////////
00174 void VirtualFile::
00175 output(ostream &out) const {
00176   out << get_filename();
00177 }
00178 
00179 ////////////////////////////////////////////////////////////////////
00180 //     Function: VirtualFile::ls
00181 //       Access: Published
00182 //  Description: If the file represents a directory, lists its
00183 //               contents.
00184 ////////////////////////////////////////////////////////////////////
00185 void VirtualFile::
00186 ls(ostream &out) const {
00187   CPT(VirtualFileList) contents = scan_directory();
00188   if (contents == (VirtualFileList *)NULL) {
00189     if (!is_directory()) {
00190       out << get_filename() << "\n";
00191     } else {
00192       out << get_filename() << " cannot be read.\n";
00193     }
00194     return;
00195   }
00196 
00197   int num_files = contents->get_num_files();
00198   for (int i = 0; i < num_files; i++) {
00199     VirtualFile *file = contents->get_file(i);
00200     out << file->get_filename().get_basename() << "\n";
00201   }
00202 }
00203 
00204 ////////////////////////////////////////////////////////////////////
00205 //     Function: VirtualFile::ls_all
00206 //       Access: Published
00207 //  Description: If the file represents a directory, recursively lists
00208 //               its contents and those of all subdirectories.
00209 ////////////////////////////////////////////////////////////////////
00210 void VirtualFile::
00211 ls_all(ostream &out) const {
00212   if (!is_directory()) {
00213     out << get_filename() << " is not a directory.\n";
00214   } else {
00215     r_ls_all(out, get_filename());
00216   }
00217 }
00218 
00219 ////////////////////////////////////////////////////////////////////
00220 //     Function: VirtualFile::open_read_file
00221 //       Access: Published, Virtual
00222 //  Description: Opens the file for reading.  Returns a newly
00223 //               allocated istream on success (which you should
00224 //               eventually delete when you are done reading).
00225 //               Returns NULL on failure.
00226 ////////////////////////////////////////////////////////////////////
00227 istream *VirtualFile::
00228 open_read_file(bool auto_unwrap) const {
00229   return NULL;
00230 }
00231 
00232 ////////////////////////////////////////////////////////////////////
00233 //     Function: VirtualFile::close_read_file
00234 //       Access: Published
00235 //  Description: Closes a file opened by a previous call to
00236 //               open_read_file().  This really just deletes the
00237 //               istream pointer, but it is recommended to use this
00238 //               interface instead of deleting it explicitly, to help
00239 //               work around compiler issues.
00240 ////////////////////////////////////////////////////////////////////
00241 void VirtualFile::
00242 close_read_file(istream *stream) const {
00243   nassertv(false);
00244 }
00245 
00246 ////////////////////////////////////////////////////////////////////
00247 //     Function: VirtualFile::was_read_successful
00248 //       Access: Published, Virtual
00249 //  Description: Call this method after a reading the istream returned
00250 //               by open_read_file() to completion.  If it returns
00251 //               true, the file was read completely and without error;
00252 //               if it returns false, there may have been some errors
00253 //               or a truncated file read.  This is particularly
00254 //               likely if the stream is a VirtualFileHTTP.
00255 ////////////////////////////////////////////////////////////////////
00256 bool VirtualFile::
00257 was_read_successful() const {
00258   return true;
00259 }
00260 
00261 ////////////////////////////////////////////////////////////////////
00262 //     Function: VirtualFile::open_write_file
00263 //       Access: Published, Virtual
00264 //  Description: Opens the file for writing.  Returns a newly
00265 //               allocated ostream on success (which you should
00266 //               eventually delete when you are done writing).
00267 //               Returns NULL on failure.
00268 ////////////////////////////////////////////////////////////////////
00269 ostream *VirtualFile::
00270 open_write_file(bool auto_wrap, bool truncate) {
00271   return NULL;
00272 }
00273 
00274 ////////////////////////////////////////////////////////////////////
00275 //     Function: VirtualFile::open_append_file
00276 //       Access: Published, Virtual
00277 //  Description: Works like open_write_file(), but the file is opened
00278 //               in append mode.  Like open_write_file, the returned
00279 //               pointer should eventually be passed to
00280 //               close_write_file().
00281 ////////////////////////////////////////////////////////////////////
00282 ostream *VirtualFile::
00283 open_append_file() {
00284   return NULL;
00285 }
00286 
00287 ////////////////////////////////////////////////////////////////////
00288 //     Function: VirtualFile::close_write_file
00289 //       Access: Published
00290 //  Description: Closes a file opened by a previous call to
00291 //               open_write_file().  This really just deletes the
00292 //               ostream pointer, but it is recommended to use this
00293 //               interface instead of deleting it explicitly, to help
00294 //               work around compiler issues.
00295 ////////////////////////////////////////////////////////////////////
00296 void VirtualFile::
00297 close_write_file(ostream *stream) {
00298   nassertv(false);
00299 }
00300 
00301 ////////////////////////////////////////////////////////////////////
00302 //     Function: VirtualFile::open_read_write_file
00303 //       Access: Published, Virtual
00304 //  Description: Opens the file for writing.  Returns a newly
00305 //               allocated iostream on success (which you should
00306 //               eventually delete when you are done writing).
00307 //               Returns NULL on failure.
00308 ////////////////////////////////////////////////////////////////////
00309 iostream *VirtualFile::
00310 open_read_write_file(bool truncate) {
00311   return NULL;
00312 }
00313 
00314 ////////////////////////////////////////////////////////////////////
00315 //     Function: VirtualFile::open_read_append_file
00316 //       Access: Published, Virtual
00317 //  Description: Works like open_read_write_file(), but the file is opened
00318 //               in append mode.  Like open_read_write_file, the returned
00319 //               pointer should eventually be passed to
00320 //               close_read_write_file().
00321 ////////////////////////////////////////////////////////////////////
00322 iostream *VirtualFile::
00323 open_read_append_file() {
00324   return NULL;
00325 }
00326 
00327 ////////////////////////////////////////////////////////////////////
00328 //     Function: VirtualFile::close_read_write_file
00329 //       Access: Published
00330 //  Description: Closes a file opened by a previous call to
00331 //               open_read_write_file().  This really just deletes the
00332 //               iostream pointer, but it is recommended to use this
00333 //               interface instead of deleting it explicitly, to help
00334 //               work around compiler issues.
00335 ////////////////////////////////////////////////////////////////////
00336 void VirtualFile::
00337 close_read_write_file(iostream *stream) {
00338   nassertv(false);
00339 }
00340 
00341 ////////////////////////////////////////////////////////////////////
00342 //     Function: VirtualFile::get_file_size
00343 //       Access: Published, Virtual
00344 //  Description: Returns the current size on disk (or wherever it is)
00345 //               of the already-open file.  Pass in the stream that
00346 //               was returned by open_read_file(); some
00347 //               implementations may require this stream to determine
00348 //               the size.
00349 ////////////////////////////////////////////////////////////////////
00350 off_t VirtualFile::
00351 get_file_size(istream *stream) const {
00352   return get_file_size();
00353 }
00354 
00355 ////////////////////////////////////////////////////////////////////
00356 //     Function: VirtualFile::get_file_size
00357 //       Access: Published, Virtual
00358 //  Description: Returns the current size on disk (or wherever it is)
00359 //               of the file before it has been opened.
00360 ////////////////////////////////////////////////////////////////////
00361 off_t VirtualFile::
00362 get_file_size() const {
00363   return 0;
00364 }
00365 
00366 ////////////////////////////////////////////////////////////////////
00367 //     Function: VirtualFile::get_timestamp
00368 //       Access: Published, Virtual
00369 //  Description: Returns a time_t value that represents the time the
00370 //               file was last modified, to within whatever precision
00371 //               the operating system records this information (on a
00372 //               Windows95 system, for instance, this may only be
00373 //               accurate to within 2 seconds).
00374 //
00375 //               If the timestamp cannot be determined, either because
00376 //               it is not supported by the operating system or
00377 //               because there is some error (such as file not found),
00378 //               returns 0.
00379 ////////////////////////////////////////////////////////////////////
00380 time_t VirtualFile::
00381 get_timestamp() const {
00382   return 0;
00383 }
00384 
00385 ////////////////////////////////////////////////////////////////////
00386 //     Function: VirtualFile::get_system_info
00387 //       Access: Published, Virtual
00388 //  Description: Populates the SubfileInfo structure with the data
00389 //               representing where the file actually resides on disk,
00390 //               if this is knowable.  Returns true if the file might
00391 //               reside on disk, and the info is populated, or false
00392 //               if it does not (or it is not known where the file
00393 //               resides), in which case the info is meaningless.
00394 ////////////////////////////////////////////////////////////////////
00395 bool VirtualFile::
00396 get_system_info(SubfileInfo &info) {
00397   return false;
00398 }
00399 
00400 ////////////////////////////////////////////////////////////////////
00401 //     Function: VirtualFile::atomic_compare_and_exchange_contents
00402 //       Access: Public, Virtual
00403 //  Description: See Filename::atomic_compare_and_exchange_contents().
00404 ////////////////////////////////////////////////////////////////////
00405 bool VirtualFile::
00406 atomic_compare_and_exchange_contents(string &orig_contents,
00407                                      const string &old_contents, 
00408                                      const string &new_contents) {
00409   return false;
00410 }
00411 
00412 ////////////////////////////////////////////////////////////////////
00413 //     Function: VirtualFile::atomic_read_contents
00414 //       Access: Public, Virtual
00415 //  Description: See Filename::atomic_read_contents().
00416 ////////////////////////////////////////////////////////////////////
00417 bool VirtualFile::
00418 atomic_read_contents(string &contents) const {
00419   return false;
00420 }
00421 
00422 ////////////////////////////////////////////////////////////////////
00423 //     Function: VirtualFile::read_file
00424 //       Access: Public
00425 //  Description: Fills up the indicated string with the contents of
00426 //               the file, if it is a regular file.  Returns true on
00427 //               success, false otherwise.
00428 ////////////////////////////////////////////////////////////////////
00429 bool VirtualFile::
00430 read_file(string &result, bool auto_unwrap) const {
00431   result = string();
00432 
00433   pvector<unsigned char> pv;
00434   if (!read_file(pv, auto_unwrap)) {
00435     return false;
00436   }
00437 
00438   if (!pv.empty()) {
00439     result.append((const char *)&pv[0], pv.size());
00440   }
00441 
00442   return true;
00443 }
00444 
00445 ////////////////////////////////////////////////////////////////////
00446 //     Function: VirtualFile::read_file
00447 //       Access: Public, Virtual
00448 //  Description: Fills up the indicated pvector with the contents of
00449 //               the file, if it is a regular file.  Returns true on
00450 //               success, false otherwise.
00451 ////////////////////////////////////////////////////////////////////
00452 bool VirtualFile::
00453 read_file(pvector<unsigned char> &result, bool auto_unwrap) const {
00454   return false;
00455 }
00456 
00457 ////////////////////////////////////////////////////////////////////
00458 //     Function: VirtualFile::write_file
00459 //       Access: Public, Virtual
00460 //  Description: Writes the indicated data to the file, if it is
00461 //               writable.  Returns true on success, false otherwise.
00462 ////////////////////////////////////////////////////////////////////
00463 bool VirtualFile::
00464 write_file(const unsigned char *data, size_t data_size, bool auto_wrap) {
00465   return false;
00466 }
00467 
00468 ////////////////////////////////////////////////////////////////////
00469 //     Function: VirtualFile::simple_read_file
00470 //       Access: Public, Static
00471 //  Description: Fills up the indicated pvector with the contents of
00472 //               the just-opened file.  Returns true on success, false
00473 //               otherwise.  If the pvector was not empty on entry, the
00474 //               data read from the file will be appended onto it.
00475 ////////////////////////////////////////////////////////////////////
00476 bool VirtualFile::
00477 simple_read_file(istream *in, pvector<unsigned char> &result) {
00478   static const size_t buffer_size = 4096;
00479   char buffer[buffer_size];
00480 
00481   in->read(buffer, buffer_size);
00482   size_t count = in->gcount();
00483   while (count != 0) {
00484     thread_consider_yield();
00485     result.insert(result.end(), buffer, buffer + count);
00486     in->read(buffer, buffer_size);
00487     count = in->gcount();
00488   }
00489 
00490   return (!in->fail() || in->eof());
00491 }
00492 
00493 ////////////////////////////////////////////////////////////////////
00494 //     Function: VirtualFile::simple_read_file
00495 //       Access: Public
00496 //  Description: As in simple_read_file() with two parameters, above,
00497 //               but only reads up to max_bytes bytes from the file.
00498 ////////////////////////////////////////////////////////////////////
00499 bool VirtualFile::
00500 simple_read_file(istream *in, pvector<unsigned char> &result, size_t max_bytes) {
00501   static const size_t buffer_size = 4096;
00502   char buffer[buffer_size];
00503 
00504   in->read(buffer, min(buffer_size, max_bytes));
00505   size_t count = in->gcount();
00506   while (count != 0) {
00507     thread_consider_yield();
00508     nassertr(count <= max_bytes, false);
00509     result.insert(result.end(), buffer, buffer + count);
00510     max_bytes -= count;
00511     in->read(buffer, min(buffer_size, max_bytes));
00512     count = in->gcount();
00513   }
00514 
00515   return (!in->fail() || in->eof());
00516 }
00517 
00518 ////////////////////////////////////////////////////////////////////
00519 //     Function: VirtualFile::scan_local_directory
00520 //       Access: Protected, Virtual
00521 //  Description: Fills file_list up with the list of files that are
00522 //               within this directory, excluding those whose
00523 //               basenames are listed in mount_points.  Returns true
00524 //               if successful, false if the file is not a directory
00525 //               or the directory cannot be read.
00526 ////////////////////////////////////////////////////////////////////
00527 bool VirtualFile::
00528 scan_local_directory(VirtualFileList *, const ov_set<string> &) const {
00529   return false;
00530 }
00531 
00532 ////////////////////////////////////////////////////////////////////
00533 //     Function: VirtualFile::r_ls_all
00534 //       Access: Private
00535 //  Description: The recursive implementation of ls_all().
00536 ////////////////////////////////////////////////////////////////////
00537 void VirtualFile::
00538 r_ls_all(ostream &out, const Filename &root) const {
00539   CPT(VirtualFileList) contents = scan_directory();
00540   if (contents == (VirtualFileList *)NULL) {
00541     return;
00542   }
00543 
00544   int num_files = contents->get_num_files();
00545   for (int i = 0; i < num_files; i++) {
00546     VirtualFile *file = contents->get_file(i);
00547     Filename filename = file->get_filename();
00548     filename.make_relative_to(root);
00549     out << filename << "\n";
00550     if (file->is_directory()) {
00551       file->r_ls_all(out, root);
00552     }
00553   }
00554 }
 All Classes Functions Variables Enumerations