virtualFile.cxx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. // Filename: virtualFile.cxx
  2. // Created by: drose (03Aug02)
  3. //
  4. ////////////////////////////////////////////////////////////////////
  5. //
  6. // PANDA 3D SOFTWARE
  7. // Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
  8. //
  9. // All use of this software is subject to the terms of the Panda 3d
  10. // Software license. You should have received a copy of this license
  11. // along with this source code; you will also find a current copy of
  12. // the license at http://etc.cmu.edu/panda3d/docs/license/ .
  13. //
  14. // To contact the maintainers of this program write to
  15. // [email protected] .
  16. //
  17. ////////////////////////////////////////////////////////////////////
  18. #include "virtualFile.h"
  19. #include "virtualFileSystem.h"
  20. #include "virtualFileList.h"
  21. #include "config_express.h"
  22. #include "pvector.h"
  23. TypeHandle VirtualFile::_type_handle;
  24. ////////////////////////////////////////////////////////////////////
  25. // Function: VirtualFile::is_directory
  26. // Access: Published, Virtual
  27. // Description: Returns true if this file represents a directory (and
  28. // scan_directory() may be called), false otherwise.
  29. ////////////////////////////////////////////////////////////////////
  30. bool VirtualFile::
  31. is_directory() const {
  32. return false;
  33. }
  34. ////////////////////////////////////////////////////////////////////
  35. // Function: VirtualFile::is_regular_file
  36. // Access: Published, Virtual
  37. // Description: Returns true if this file represents a regular file
  38. // (and read_file() may be called), false otherwise.
  39. ////////////////////////////////////////////////////////////////////
  40. bool VirtualFile::
  41. is_regular_file() const {
  42. return false;
  43. }
  44. ////////////////////////////////////////////////////////////////////
  45. // Function: VirtualFile::scan_directory
  46. // Access: Published
  47. // Description: If the file represents a directory (that is,
  48. // is_directory() returns true), this returns the list
  49. // of files within the directory at the current time.
  50. // Returns NULL if the file is not a directory or if the
  51. // directory cannot be read.
  52. ////////////////////////////////////////////////////////////////////
  53. PT(VirtualFileList) VirtualFile::
  54. scan_directory() const {
  55. // First, we have to make sure there aren't any mount points attached
  56. // under this directory. These will override any local filenames.
  57. VirtualFileSystem *file_system = get_file_system();
  58. Filename this_filename = get_filename();
  59. vector_string mount_points_flat;
  60. file_system->scan_mount_points(mount_points_flat, this_filename);
  61. // Copy the set of nested mount points to a sorted list so we can
  62. // search it quickly.
  63. ov_set<string> mount_points;
  64. copy(mount_points_flat.begin(), mount_points_flat.end(),
  65. back_inserter(mount_points));
  66. mount_points.sort();
  67. PT(VirtualFileList) file_list = new VirtualFileList;
  68. // Each of those mount points maps to a directory root or something
  69. // from the file system.
  70. ov_set<string>::const_iterator mi;
  71. for (mi = mount_points.begin(); mi != mount_points.end(); ++mi) {
  72. const string &basename = (*mi);
  73. Filename filename(this_filename, basename);
  74. PT(VirtualFile) file = file_system->get_file(filename);
  75. file_list->add_file(file);
  76. }
  77. // Now, get the actual local files in this directory.
  78. vector_string names;
  79. if (!scan_local_directory(file_list, mount_points)) {
  80. // Not a directory, or unable to read directory.
  81. if (file_list->get_num_files() == 0) {
  82. return NULL;
  83. }
  84. // We couldn't read the physical directory, but we do have some
  85. // mounted files to return.
  86. return file_list;
  87. }
  88. return file_list;
  89. }
  90. ////////////////////////////////////////////////////////////////////
  91. // Function: VirtualFile::output
  92. // Access: Published
  93. // Description:
  94. ////////////////////////////////////////////////////////////////////
  95. void VirtualFile::
  96. output(ostream &out) const {
  97. out << get_filename();
  98. }
  99. ////////////////////////////////////////////////////////////////////
  100. // Function: VirtualFile::ls
  101. // Access: Published
  102. // Description: If the file represents a directory, lists its
  103. // contents.
  104. ////////////////////////////////////////////////////////////////////
  105. void VirtualFile::
  106. ls(ostream &out) const {
  107. CPT(VirtualFileList) contents = scan_directory();
  108. if (contents == (VirtualFileList *)NULL) {
  109. if (!is_directory()) {
  110. out << get_filename() << "\n";
  111. } else {
  112. out << get_filename() << " cannot be read.\n";
  113. }
  114. return;
  115. }
  116. int num_files = contents->get_num_files();
  117. for (int i = 0; i < num_files; i++) {
  118. VirtualFile *file = contents->get_file(i);
  119. out << file->get_filename().get_basename() << "\n";
  120. }
  121. }
  122. ////////////////////////////////////////////////////////////////////
  123. // Function: VirtualFile::ls_all
  124. // Access: Published
  125. // Description: If the file represents a directory, recursively lists
  126. // its contents and those of all subdirectories.
  127. ////////////////////////////////////////////////////////////////////
  128. void VirtualFile::
  129. ls_all(ostream &out) const {
  130. if (!is_directory()) {
  131. out << get_filename() << " is not a directory.\n";
  132. } else {
  133. r_ls_all(out, get_filename());
  134. }
  135. }
  136. ////////////////////////////////////////////////////////////////////
  137. // Function: VirtualFile::open_read_file
  138. // Access: Published, Virtual
  139. // Description: Opens the file for reading. Returns a newly
  140. // allocated istream on success (which you should
  141. // eventually delete when you are done reading).
  142. // Returns NULL on failure.
  143. ////////////////////////////////////////////////////////////////////
  144. istream *VirtualFile::
  145. open_read_file(bool auto_unwrap) const {
  146. return NULL;
  147. }
  148. ////////////////////////////////////////////////////////////////////
  149. // Function: VirtualFile::get_file_size
  150. // Access: Published, Virtual
  151. // Description: Returns the current size on disk (or wherever it is)
  152. // of the already-open file. Pass in the stream that
  153. // was returned by open_read_file(); some
  154. // implementations may require this stream to determine
  155. // the size.
  156. ////////////////////////////////////////////////////////////////////
  157. off_t VirtualFile::
  158. get_file_size(istream *stream) const {
  159. return 0;
  160. }
  161. ////////////////////////////////////////////////////////////////////
  162. // Function: VirtualFile::get_file_size
  163. // Access: Published, Virtual
  164. // Description: Returns the current size on disk (or wherever it is)
  165. // of the file before it has been opened.
  166. ////////////////////////////////////////////////////////////////////
  167. off_t VirtualFile::
  168. get_file_size() const {
  169. return 0;
  170. }
  171. ////////////////////////////////////////////////////////////////////
  172. // Function: VirtualFile::get_timestamp
  173. // Access: Published, Virtual
  174. // Description: Returns a time_t value that represents the time the
  175. // file was last modified, to within whatever precision
  176. // the operating system records this information (on a
  177. // Windows95 system, for instance, this may only be
  178. // accurate to within 2 seconds).
  179. //
  180. // If the timestamp cannot be determined, either because
  181. // it is not supported by the operating system or
  182. // because there is some error (such as file not found),
  183. // returns 0.
  184. ////////////////////////////////////////////////////////////////////
  185. time_t VirtualFile::
  186. get_timestamp() const {
  187. return 0;
  188. }
  189. ////////////////////////////////////////////////////////////////////
  190. // Function: VirtualFile::close_read_file
  191. // Access: Public
  192. // Description: Closes a file opened by a previous call to
  193. // open_read_file(). This really just deletes the
  194. // istream pointer, but it is recommended to use this
  195. // interface instead of deleting it explicitly, to help
  196. // work around compiler issues.
  197. ////////////////////////////////////////////////////////////////////
  198. void VirtualFile::
  199. close_read_file(istream *stream) const {
  200. if (stream != (istream *)NULL) {
  201. // For some reason--compiler bug in gcc 3.2?--explicitly deleting
  202. // the stream pointer does not call the appropriate global delete
  203. // function; instead apparently calling the system delete
  204. // function. So we call the delete function by hand instead.
  205. #if !defined(USE_MEMORY_NOWRAPPERS) && defined(REDEFINE_GLOBAL_OPERATOR_NEW)
  206. stream->~istream();
  207. (*global_operator_delete)(stream);
  208. #else
  209. delete stream;
  210. #endif
  211. }
  212. }
  213. ////////////////////////////////////////////////////////////////////
  214. // Function: VirtualFile::read_file
  215. // Access: Public
  216. // Description: Fills up the indicated string with the contents of
  217. // the file, if it is a regular file. Returns true on
  218. // success, false otherwise.
  219. ////////////////////////////////////////////////////////////////////
  220. bool VirtualFile::
  221. read_file(string &result, bool auto_unwrap) const {
  222. result = string();
  223. pvector<unsigned char> pv;
  224. if (!read_file(pv, auto_unwrap)) {
  225. return false;
  226. }
  227. if (!pv.empty()) {
  228. result.append((const char *)&pv[0], pv.size());
  229. }
  230. return true;
  231. }
  232. ////////////////////////////////////////////////////////////////////
  233. // Function: VirtualFile::read_file
  234. // Access: Public
  235. // Description: Fills up the indicated pvector with the contents of
  236. // the file, if it is a regular file. Returns true on
  237. // success, false otherwise.
  238. ////////////////////////////////////////////////////////////////////
  239. bool VirtualFile::
  240. read_file(pvector<unsigned char> &result, bool auto_unwrap) const {
  241. result.clear();
  242. istream *in = open_read_file(auto_unwrap);
  243. if (in == (istream *)NULL) {
  244. express_cat.info()
  245. << "Unable to read " << get_filename() << "\n";
  246. return false;
  247. }
  248. bool okflag = read_file(in, result);
  249. close_read_file(in);
  250. if (!okflag) {
  251. express_cat.info()
  252. << "Error while reading " << get_filename() << "\n";
  253. }
  254. return okflag;
  255. }
  256. ////////////////////////////////////////////////////////////////////
  257. // Function: VirtualFile::read_file
  258. // Access: Public, Static
  259. // Description: Fills up the indicated pvector with the contents of
  260. // the just-opened file. Returns true on success, false
  261. // otherwise. If the pvector was not empty on entry, the
  262. // data read from the file will be appended onto it.
  263. ////////////////////////////////////////////////////////////////////
  264. bool VirtualFile::
  265. read_file(istream *in, pvector<unsigned char> &result) {
  266. pvector<char> result_vec;
  267. static const size_t buffer_size = 1024;
  268. char buffer[buffer_size];
  269. in->read(buffer, buffer_size);
  270. size_t count = in->gcount();
  271. while (count != 0) {
  272. thread_consider_yield();
  273. result.insert(result.end(), buffer, buffer + count);
  274. in->read(buffer, buffer_size);
  275. count = in->gcount();
  276. }
  277. return (!in->fail() || in->eof());
  278. }
  279. ////////////////////////////////////////////////////////////////////
  280. // Function: VirtualFile::read_file
  281. // Access: Public, Static
  282. // Description: As in read_file() with two parameters, above, but
  283. // only reads up to max_bytes bytes from the file.
  284. ////////////////////////////////////////////////////////////////////
  285. bool VirtualFile::
  286. read_file(istream *in, pvector<unsigned char> &result, size_t max_bytes) {
  287. static const size_t buffer_size = 1024;
  288. char buffer[buffer_size];
  289. in->read(buffer, min(buffer_size, max_bytes));
  290. size_t count = in->gcount();
  291. while (count != 0) {
  292. thread_consider_yield();
  293. nassertr(count <= max_bytes, false);
  294. result.insert(result.end(), buffer, buffer + count);
  295. max_bytes -= count;
  296. in->read(buffer, min(buffer_size, max_bytes));
  297. count = in->gcount();
  298. }
  299. return (!in->fail() || in->eof());
  300. }
  301. ////////////////////////////////////////////////////////////////////
  302. // Function: VirtualFile::scan_local_directory
  303. // Access: Protected, Virtual
  304. // Description: Fills file_list up with the list of files that are
  305. // within this directory, excluding those whose
  306. // basenames are listed in mount_points. Returns true
  307. // if successful, false if the file is not a directory
  308. // or the directory cannot be read.
  309. ////////////////////////////////////////////////////////////////////
  310. bool VirtualFile::
  311. scan_local_directory(VirtualFileList *, const ov_set<string> &) const {
  312. return false;
  313. }
  314. ////////////////////////////////////////////////////////////////////
  315. // Function: VirtualFile::r_ls_all
  316. // Access: Private
  317. // Description: The recursive implementation of ls_all().
  318. ////////////////////////////////////////////////////////////////////
  319. void VirtualFile::
  320. r_ls_all(ostream &out, const Filename &root) const {
  321. CPT(VirtualFileList) contents = scan_directory();
  322. if (contents == (VirtualFileList *)NULL) {
  323. return;
  324. }
  325. int num_files = contents->get_num_files();
  326. for (int i = 0; i < num_files; i++) {
  327. VirtualFile *file = contents->get_file(i);
  328. Filename filename = file->get_filename();
  329. filename.make_relative_to(root);
  330. out << filename << "\n";
  331. if (file->is_directory()) {
  332. file->r_ls_all(out, root);
  333. }
  334. }
  335. }