1 #ifndef _FILE_HANDLER_ 2 #define _FILE_HANDLER_ 3 /* 4 5 Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc. 6 and the "Aleph One" developers. 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 This license is contained in the file "COPYING", 19 which is included with this source code; it is available online at 20 http://www.gnu.org/licenses/gpl.html 21 22 File-handler classes 23 by Loren Petrich, 24 August 11, 2000 25 26 These are designed to provide some abstract interfaces to file and directory objects. 27 28 Most of these routines return whether they had succeeded; 29 more detailed error codes are API-specific. 30 Attempted to support stdio I/O directly, but on my Macintosh, at least, 31 the performance was much poorer. This is possibly due to "fseek" having to 32 actually read the file or something. 33 34 Merged all the Macintosh-specific code into these base classes, so that 35 it will be selected with a preprocessor statement when more than one file-I/O 36 API is supported. 37 38 Dec 7, 2000 (Loren Petrich): 39 Added a MacOS-specific file-creation function that allows direct specification 40 of type and creator codes 41 42 Jan 25, 2002 (Br'fin (Jeremy Parsons)): 43 Added TARGET_API_MAC_CARBON for Carbon.h 44 Rearranged initializers in DirectorySpecifier constructor to appease compiler warnings 45 46 March 18, 2002 (Br'fin (Jeremy Parsons)): 47 Added FileSpecifier::SetParentToResources for Carbon 48 */ 49 50 // For the filetypes 51 #include "tags.h" 52 53 #include <stddef.h> // For size_t 54 #include <time.h> // For time_t 55 #include <vector> 56 #include <SDL.h> 57 58 #include <errno.h> 59 #include <string> 60 #ifndef NO_STD_NAMESPACE 61 using std::string; 62 using std::vector; 63 #endif 64 65 #ifdef __WIN32__ 66 #include <windows.h> 67 #ifdef GetFreeSpace 68 #undef GetFreeSpace 69 #endif 70 #ifdef CreateDirectory 71 #undef CreateDirectory 72 #endif 73 #endif 74 75 #include <boost/iostreams/categories.hpp> 76 #include <boost/iostreams/positioning.hpp> 77 78 /* 79 Abstraction for opened files; it does reading, writing, and closing of such files, 80 without doing anything to the files' specifications 81 */ 82 class OpenedFile 83 { 84 // This class will need to set the refnum and error value appropriately 85 friend class FileSpecifier; 86 friend class opened_file_device; 87 88 public: 89 bool IsOpen(); 90 bool Close(); 91 92 bool GetPosition(int32& Position); 93 bool SetPosition(int32 Position); 94 95 bool GetLength(int32& Length); 96 bool SetLength(int32 Length); 97 98 bool Read(int32 Count, void *Buffer); 99 bool Write(int32 Count, void *Buffer); 100 101 OpenedFile(); ~OpenedFile()102 ~OpenedFile() {Close();} // Auto-close when destroying 103 GetError()104 int GetError() {return err;} GetRWops()105 SDL_RWops *GetRWops() {return f;} 106 SDL_RWops *TakeRWops(); // Hand over SDL_RWops 107 108 private: 109 SDL_RWops *f; // File handle 110 int err; // Error code 111 bool is_forked; 112 int32 fork_offset, fork_length; 113 }; 114 115 class opened_file_device { 116 public: 117 typedef char char_type; 118 typedef boost::iostreams::seekable_device_tag category; 119 std::streamsize read(char* s, std::streamsize n); 120 std::streamsize write(const char* s, std::streamsize n); 121 std::streampos seek(boost::iostreams::stream_offset off, std::ios_base::seekdir way); 122 123 opened_file_device(OpenedFile& f); 124 125 private: 126 OpenedFile& f; 127 }; 128 129 /* 130 Abstraction for loaded resources; 131 this object will release that resource when it finishes. 132 MacOS resource handles will be assumed to be locked. 133 */ 134 class LoadedResource 135 { 136 // This class grabs a resource to be loaded into here 137 friend class OpenedResourceFile; 138 139 public: 140 // Resource loaded? 141 bool IsLoaded(); 142 143 // Unloads the resource 144 void Unload(); 145 146 // Get size of loaded resource 147 size_t GetLength(); 148 149 // Get pointer (always present) 150 void *GetPointer(bool DoDetach = false); 151 152 // Make resource from raw resource data; the caller gives up ownership 153 // of the pointed to memory block 154 void SetData(void *data, size_t length); 155 156 LoadedResource(); ~LoadedResource()157 ~LoadedResource() {Unload();} // Auto-unload when destroying 158 159 private: 160 // Detaches an allocated resource from this object 161 // (keep private to avoid memory leaks) 162 void Detach(); 163 164 public: 165 void *p; // Pointer to resource data (malloc()ed) 166 size_t size; // Size of data 167 }; 168 169 170 /* 171 Abstraction for opened resource files: 172 it does opening, setting, and closing of such files; 173 also getting "LoadedResource" objects that return pointers 174 */ 175 class OpenedResourceFile 176 { 177 // This class will need to set the refnum and error value appropriately 178 friend class FileSpecifier; 179 180 public: 181 182 // Pushing and popping the current file -- necessary in the MacOS version, 183 // since resource forks are globally open with one of them the current top one. 184 // Push() saves the earlier top one makes the current one the top one, 185 // while Pop() restores the earlier top one. 186 // Will leave SetResLoad in the state of true. 187 bool Push(); 188 bool Pop(); 189 190 // Pushing and popping are unnecessary for the MacOS versions of Get() and Check() 191 // Check simply checks if a resource is present; returns whether it is or not 192 // Get loads a resource; returns whether or not one had been successfully loaded 193 // CB: added functions that take 4 characters instead of uint32, which is more portable 194 bool Check(uint32 Type, int16 ID); Check(uint8 t1,uint8 t2,uint8 t3,uint8 t4,int16 ID)195 bool Check(uint8 t1, uint8 t2, uint8 t3, uint8 t4, int16 ID) {return Check(FOUR_CHARS_TO_INT(t1, t2, t3, t4), ID);} 196 bool Get(uint32 Type, int16 ID, LoadedResource& Rsrc); Get(uint8 t1,uint8 t2,uint8 t3,uint8 t4,int16 ID,LoadedResource & Rsrc)197 bool Get(uint8 t1, uint8 t2, uint8 t3, uint8 t4, int16 ID, LoadedResource& Rsrc) {return Get(FOUR_CHARS_TO_INT(t1, t2, t3, t4), ID, Rsrc);} 198 199 bool IsOpen(); 200 bool Close(); 201 202 OpenedResourceFile(); ~OpenedResourceFile()203 ~OpenedResourceFile() {Close();} // Auto-close when destroying 204 GetError()205 int GetError() {return err;} 206 207 private: 208 int err; // Error code 209 SDL_RWops *f, *saved_f; 210 }; 211 212 213 // Directories are treated like files 214 #define DirectorySpecifier FileSpecifier 215 216 // Directory entry, returned by FileSpecifier::ReadDirectory() 217 struct dir_entry { dir_entrydir_entry218 dir_entry() : size(0), is_directory(false), is_volume(false) {} 219 dir_entry(const string &n, int32 s, bool is_dir, bool is_vol = false, TimeType d = 0) namedir_entry220 : name(n), size(s), is_directory(is_dir), is_volume(is_vol), date(d) {} ~dir_entrydir_entry221 ~dir_entry() {} 222 223 bool operator<(const dir_entry &other) const 224 { 225 if (is_directory == other.is_directory) 226 return name < other.name; 227 else // Sort directories before files 228 return is_directory > other.is_directory; 229 } 230 231 bool operator==(const dir_entry& other) const { 232 return is_directory == other.is_directory && name == other.name; 233 } 234 235 string name; // Entry name 236 int32 size; // File size (only valid if !is_directory) 237 bool is_directory; // Entry is a directory (plain file otherwise) 238 bool is_volume; // Entry is a volume (for platforms that have volumes, is_directory must also be set) 239 TimeType date; // modification date 240 }; 241 242 243 /* 244 Abstraction for file specifications; 245 designed to encapsulate both directly-specified paths 246 and MacOS FSSpecs 247 */ 248 class FileSpecifier 249 { 250 public: 251 // The typecodes here are the symbolic constants defined in tags.h (_typecode_creator, etc.) 252 253 // Get the name (final path element) as a C string: 254 // assumes enough space to hold it if getting (max. 256 bytes) 255 void GetName(char *Name) const; 256 257 // Looks in all directories in the current data search 258 // path for a file with the relative path "NameWithPath" and 259 // sets the file specifier to the full path of the first file 260 // found. 261 // "NameWithPath" follows Unix-like syntax: <dirname>/<dirname>/<dirname>/filename 262 // A ":" will be translated into a "/" in the MacOS. 263 // Returns whether or not the setting was successful 264 bool SetNameWithPath(const char *NameWithPath); 265 bool SetNameWithPath(const char* NameWithPath, const DirectorySpecifier& Directory); 266 267 void SetTempName(const FileSpecifier& other); 268 269 // Move the directory specification 270 void ToDirectory(DirectorySpecifier& Dir); 271 void FromDirectory(DirectorySpecifier& Dir); 272 273 // These functions take an appropriate one of the typecodes used earlier; 274 // this is to try to cover the cases of both typecode attributes 275 // and typecode suffixes. 276 bool Create(Typecode Type); 277 278 // Opens a file: 279 bool Open(OpenedFile& OFile, bool Writable=false); 280 281 // Opens either a MacOS resource fork or some imitation of it: 282 bool Open(OpenedResourceFile& OFile, bool Writable=false); 283 284 // These calls are for creating dialog boxes to set the filespec 285 // A null pointer means an empty string 286 bool ReadDialog(Typecode Type, const char *Prompt=NULL); 287 bool WriteDialog(Typecode Type, const char *Prompt=NULL, const char *DefaultName=NULL); 288 289 // Write dialog box for savegames (must be asynchronous, allowing the sound 290 // to continue in the background) 291 bool WriteDialogAsync(Typecode Type, char *Prompt=NULL, char *DefaultName=NULL); 292 293 // Check on whether a file exists, and its type 294 bool Exists(); 295 bool IsDir(); 296 297 // Gets the modification date 298 TimeType GetDate(); 299 300 // Returns _typecode_unknown if the type could not be identified; 301 // the types returned are the _typecode_stuff in tags.h 302 Typecode GetType(); 303 304 // How many bytes are free in the disk that the file lives in? 305 bool GetFreeSpace(uint32& FreeSpace); 306 307 // Copy file contents 308 bool CopyContents(FileSpecifier& File); 309 310 // Delete file 311 bool Delete(); 312 313 // Rename file 314 bool Rename(const FileSpecifier& Destination); 315 316 // Copy file specification 317 const FileSpecifier &operator=(const FileSpecifier &other); 318 319 // hide extensions known to Aleph One 320 static std::string HideExtension(const std::string& filename); 321 GetPath(void)322 const char *GetPath(void) const {return name.c_str();} 323 324 FileSpecifier(); FileSpecifier(const string & s)325 FileSpecifier(const string &s) : name(s), err(0) {canonicalize_path();} FileSpecifier(const char * s)326 FileSpecifier(const char *s) : name(s), err(0) {canonicalize_path();} FileSpecifier(const FileSpecifier & other)327 FileSpecifier(const FileSpecifier &other) : name(other.name), err(other.err) {} 328 329 bool operator==(const FileSpecifier &other) const {return name == other.name;} 330 bool operator!=(const FileSpecifier &other) const {return name != other.name;} 331 332 void SetToLocalDataDir(); // Per-user directory (for temporary files) 333 void SetToPreferencesDir(); // Directory for preferences (per-user) 334 void SetToSavedGamesDir(); // Directory for saved games (per-user) 335 void SetToQuickSavesDir(); // Directory for auto-named saved games (per-user) 336 void SetToImageCacheDir(); // Directory for image cache (per-user) 337 void SetToRecordingsDir(); // Directory for recordings (per-user) 338 339 void AddPart(const string &part); 340 FileSpecifier &operator+=(const FileSpecifier &other) {AddPart(other.name); return *this;} 341 FileSpecifier &operator+=(const string &part) {AddPart(part); return *this;} 342 FileSpecifier &operator+=(const char *part) {AddPart(string(part)); return *this;} 343 FileSpecifier operator+(const FileSpecifier &other) const {FileSpecifier a(name); a.AddPart(other.name); return a;} 344 FileSpecifier operator+(const string &part) const {FileSpecifier a(name); a.AddPart(part); return a;} 345 FileSpecifier operator+(const char *part) const {FileSpecifier a(name); a.AddPart(string(part)); return a;} 346 347 void SplitPath(string &base, string &part) const; SplitPath(DirectorySpecifier & base,string & part)348 void SplitPath(DirectorySpecifier &base, string &part) const {string b; SplitPath(b, part); base = b;} 349 350 bool CreateDirectory(); 351 bool ReadDirectory(vector<dir_entry> &vec); 352 GetError()353 int GetError() const {return err;} 354 355 private: 356 void canonicalize_path(void); 357 358 string name; // Path name 359 int err; 360 }; 361 362 // inserts dir before the search path, then restores the original path 363 // when going out of scope 364 class ScopedSearchPath 365 { 366 public: 367 ScopedSearchPath(const DirectorySpecifier& dir); 368 ~ScopedSearchPath(); 369 }; 370 371 #endif 372 373