memVolume.cpp
Engine/source/core/memVolume.cpp
Classes:
Namespaces:
namespace
namespace
Detailed Description
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "platform/platform.h" 25#include "core/memVolume.h" 26 27#include "core/crc.h" 28#include "core/frameAllocator.h" 29#include "core/util/str.h" 30#include "core/strings/stringFunctions.h" 31#include "platform/platformVolume.h" 32 33namespace Torque 34{ 35 namespace Mem 36 { 37 38 // Multiple MemFile's can reference the same path, so this is here to contain 39 // the actual data at a Path. 40 struct MemFileData 41 { 42 MemFileData(MemFileSystem* fs, const Path& path) 43 { 44 mPath = path; 45 mBufferSize = 1024; 46 mFileSize = 0; 47 mBuffer = dMalloc(mBufferSize); 48 dMemset(mBuffer, 0, mBufferSize); 49 mModified = Time::getCurrentTime(); 50 mLastAccess = mModified; 51 mFileSystem = fs; 52 } 53 54 ~MemFileData() 55 { 56 dFree(mBuffer); 57 } 58 59 bool getAttributes(FileNode::Attributes* attr) 60 { 61 attr->name = mPath; 62 attr->flags = FileNode::File; 63 attr->size = mFileSize; 64 attr->mtime = mModified; 65 attr->atime = mLastAccess; 66 return true; 67 } 68 69 FileNodeRef resolve(const Path& path) 70 { 71 // Is it me? 72 String sThisPath(mPath); 73 String sTargetPath(path); 74 if (sThisPath == sTargetPath) 75 return new MemFile(mFileSystem, this); 76 // Nope 77 return NULL; 78 } 79 80 Path mPath; 81 void* mBuffer; 82 U32 mBufferSize; // This is the size of the memory buffer >= mFileSize 83 U32 mFileSize; // This is the size of the "file" <= mBufferSize 84 Time mModified; // Last modified 85 Time mLastAccess; // Last access 86 MemFileSystem* mFileSystem; 87 }; 88 89 struct MemDirectoryData 90 { 91 Path mPath; 92 MemFileSystem* mFileSystem; 93 Vector<MemFileData*> mFiles; 94 Vector<MemDirectoryData*> mDirectories; 95 96 MemDirectoryData(MemFileSystem* fs, const Path& path) 97 { 98 mFileSystem = fs; 99 mPath = path; 100 } 101 102 ~MemDirectoryData() 103 { 104 for (U32 i = 0; i < mFiles.size(); i++) 105 { 106 delete mFiles[i]; 107 } 108 for (U32 i = 0; i < mDirectories.size(); i++) 109 { 110 delete mDirectories[i]; 111 } 112 } 113 114 bool getAttributes(FileNode::Attributes* attr) 115 { 116 attr->name = mPath; 117 attr->flags = FileNode::Directory; 118 return true; 119 } 120 121 FileNodeRef resolve(const Path& path) 122 { 123 // Is it me? 124 String sThisPath(mPath); 125 String sTargetPath(path); 126 if (sThisPath == sTargetPath) 127 return new MemDirectory(mFileSystem, this); 128 // Is it one of my children? 129 if (sTargetPath.find(sThisPath) == 0) 130 { 131 FileNodeRef result; 132 for (U32 i = 0; i < mDirectories.size() && result.isNull(); i++) 133 result = mDirectories[i]->resolve(path); 134 for (U32 i = 0; i < mFiles.size() && result.isNull(); i++) 135 result = mFiles[i]->resolve(path); 136 return result; 137 } 138 // Nope 139 return NULL; 140 } 141 }; 142 143 //----------------------------------------------------------------------------- 144 MemFileSystem::MemFileSystem(String volume) 145 { 146 mVolume = volume; 147 mRootDir = new MemDirectoryData(this, volume); 148 } 149 150 MemFileSystem::~MemFileSystem() 151 { 152 delete mRootDir; 153 } 154 155 FileNodeRef MemFileSystem::resolve(const Path& path) 156 { 157 return mRootDir->resolve(path); 158 } 159 160 // 161 MemDirectory* MemFileSystem::getParentDir(const Path& path, FileNodeRef& parentRef) 162 { 163 parentRef = mRootDir->resolve(path.getRoot() + ":" + path.getPath()); 164 if (parentRef.isNull()) 165 return NULL; 166 167 MemDirectory* result = dynamic_cast<MemDirectory*>(parentRef.getPointer()); 168 return result; 169 } 170 171 FileNodeRef MemFileSystem::create(const Path& path, FileNode::Mode mode) 172 { 173 // Already exists 174 FileNodeRef result = mRootDir->resolve(path); 175 if (result.isValid()) 176 return result; 177 178 // Doesn't exist, try to get parent node. 179 FileNodeRef parentRef; 180 MemDirectory* mDir = getParentDir(path, parentRef); 181 if (mDir) 182 { 183 MemDirectoryData* mdd = mDir->mDirectoryData; 184 switch (mode) 185 { 186 case FileNode::File : 187 { 188 MemFileData* mfd = new MemFileData(this, path); 189 mdd->mFiles.push_back(mfd); 190 return new MemFile(this, mfd); 191 } 192 break; 193 case FileNode::Directory : 194 { 195 MemDirectoryData* mfd = new MemDirectoryData(this, path); 196 mdd->mDirectories.push_back(mfd); 197 return new MemDirectory(this, mfd); 198 } 199 break; 200 default: 201 // anything else we ignore 202 break; 203 } 204 } 205 return NULL; 206 } 207 208 bool MemFileSystem::remove(const Path& path) 209 { 210 FileNodeRef parentRef; 211 MemDirectory* mDir = getParentDir(path, parentRef); 212 MemDirectoryData* mdd = mDir->mDirectoryData; 213 for (U32 i = 0; i < mdd->mDirectories.size(); i++) 214 { 215 if (mdd->mDirectories[i]->mPath == path) 216 { 217 delete mdd->mDirectories[i]; 218 mdd->mDirectories.erase_fast(i); 219 return true; 220 } 221 } 222 for (U32 i = 0; i < mdd->mFiles.size(); i++) 223 { 224 if (mdd->mFiles[i]->mPath == path) 225 { 226 delete mdd->mFiles[i]; 227 mdd->mFiles.erase_fast(i); 228 return true; 229 } 230 } 231 return false; 232 } 233 234 bool MemFileSystem::rename(const Path& from,const Path& to) 235 { 236 // Source must exist 237 FileNodeRef source = mRootDir->resolve(from); 238 if (source.isNull()) 239 return false; 240 241 // Destination must not exist 242 FileNodeRef dest = mRootDir->resolve(to); 243 if (source.isValid()) 244 return false; 245 246 // Get source parent 247 FileNodeRef sourceParentRef; 248 MemDirectory* sourceDir = getParentDir(from, sourceParentRef); 249 250 // Get dest parent 251 FileNodeRef destRef; 252 MemDirectory* mDir = getParentDir(to, destRef); 253 254 // Now move it/rename it 255 if (dynamic_cast<MemDirectory*>(source.getPointer())) 256 { 257 MemDirectoryData* sourcedd; 258 MemDirectoryData* d = sourceDir->mDirectoryData; 259 for (U32 i = 0; i < d->mDirectories.size(); i++) 260 { 261 if (d->mDirectories[i]->mPath == from) 262 { 263 sourcedd = d->mDirectories[i]; 264 d->mDirectories.erase_fast(i); 265 sourcedd->mPath = to; 266 mDir->mDirectoryData->mDirectories.push_back(sourcedd); 267 return true; 268 } 269 } 270 } else { 271 MemFileData* sourceFile; 272 MemDirectoryData* d = sourceDir->mDirectoryData; 273 for (U32 i = 0; i < d->mFiles.size(); i++) 274 { 275 if (d->mFiles[i]->mPath == from) 276 { 277 sourceFile = d->mFiles[i]; 278 d->mFiles.erase_fast(i); 279 sourceFile->mPath = to; 280 mDir->mDirectoryData->mFiles.push_back(sourceFile); 281 return true; 282 } 283 } 284 } 285 return false; 286 } 287 288 Path MemFileSystem::mapTo(const Path& path) 289 { 290 String file = mVolume; 291 file = Path::Join(file, '/', path.getPath()); 292 file = Path::Join(file, '/', path.getFileName()); 293 file = Path::Join(file, '.', path.getExtension()); 294 return file; 295 } 296 297 Path MemFileSystem::mapFrom(const Path& path) 298 { 299 const String::SizeType volumePathLen = mVolume.length(); 300 301 String pathStr = path.getFullPath(); 302 303 if ( mVolume.compare( pathStr, volumePathLen, String::NoCase )) 304 return Path(); 305 306 return pathStr.substr( volumePathLen, pathStr.length() - volumePathLen ); 307 } 308 309 //----------------------------------------------------------------------------- 310 311 MemFile::MemFile(MemFileSystem* fs, MemFileData* fileData) 312 { 313 mFileData = fileData; 314 mStatus = Closed; 315 mCurrentPos = U32_MAX; 316 mFileSystem = fs; 317 } 318 319 MemFile::~MemFile() 320 { 321 } 322 323 Path MemFile::getName() const 324 { 325 return mFileData->mPath; 326 } 327 328 FileNode::NodeStatus MemFile::getStatus() const 329 { 330 return mStatus; 331 } 332 333 bool MemFile::getAttributes(Attributes* attr) 334 { 335 return mFileData->getAttributes(attr); 336 } 337 338 U32 MemFile::calculateChecksum() 339 { 340 return CRC::calculateCRC(mFileData->mBuffer, mFileData->mFileSize); 341 } 342 343 bool MemFile::open(AccessMode mode) 344 { 345 mStatus = Open; 346 mCurrentPos = 0; 347 switch (mode) 348 { 349 case Read : 350 case ReadWrite : 351 mCurrentPos = 0; 352 break; 353 case Write : 354 mCurrentPos = 0; 355 mFileData->mFileSize = 0; 356 break; 357 case WriteAppend : 358 mCurrentPos = mFileData->mFileSize; 359 break; 360 } 361 return true; 362 } 363 364 bool MemFile::close() 365 { 366 mStatus = Closed; 367 return true; 368 } 369 370 U32 MemFile::getPosition() 371 { 372 if (mStatus == Open || mStatus == EndOfFile) 373 return mCurrentPos; 374 return 0; 375 } 376 377 U32 MemFile::setPosition(U32 delta, SeekMode mode) 378 { 379 if (mStatus != Open && mStatus != EndOfFile) 380 return 0; 381 382 switch (mode) 383 { 384 case Begin: 385 mCurrentPos = delta; 386 break; 387 case Current: 388 mCurrentPos += delta; 389 break; 390 case End: 391 mCurrentPos = mFileData->mFileSize - delta; 392 break; 393 } 394 395 mStatus = Open; 396 397 return mCurrentPos; 398 } 399 400 U32 MemFile::read(void* dst, U32 size) 401 { 402 if (mStatus != Open && mStatus != EndOfFile) 403 return 0; 404 405 U32 copyAmount = getMin(size, mFileData->mFileSize - mCurrentPos); 406 dMemcpy(dst, (U8*) mFileData->mBuffer + mCurrentPos, copyAmount); 407 mCurrentPos += copyAmount; 408 mFileData->mLastAccess = Time::getCurrentTime(); 409 if (mCurrentPos == mFileData->mFileSize) 410 mStatus = EndOfFile; 411 return copyAmount; 412 } 413 414 U32 MemFile::write(const void* src, U32 size) 415 { 416 if ((mStatus != Open && mStatus != EndOfFile) || !size) 417 return 0; 418 419 if (mFileData->mFileSize + size > mFileData->mBufferSize) 420 { 421 // Keep doubling our buffer size until we're big enough. 422 while (mFileData->mFileSize + size > mFileData->mBufferSize) 423 mFileData->mBufferSize *= 2; 424 mFileData->mBuffer = dRealloc(mFileData->mBuffer, mFileData->mBufferSize); 425 if (!mFileData->mBuffer) 426 { 427 mStatus = FileSystemFull; 428 return 0; 429 } 430 } 431 432 dMemcpy((U8*)mFileData->mBuffer + mCurrentPos, src, size); 433 mCurrentPos += size; 434 mFileData->mFileSize = getMax(mFileData->mFileSize, mCurrentPos); 435 mFileData->mLastAccess = Time::getCurrentTime(); 436 mFileData->mModified = mFileData->mLastAccess; 437 438 return size; 439 } 440 441 //----------------------------------------------------------------------------- 442 443 MemDirectory::MemDirectory(MemFileSystem* fs, MemDirectoryData* dir) 444 { 445 mStatus = Closed; 446 mDirectoryData = dir; 447 mFileSystem = fs; 448 } 449 450 MemDirectory::~MemDirectory() 451 { 452 } 453 454 Path MemDirectory::getName() const 455 { 456 return mDirectoryData->mPath; 457 } 458 459 bool MemDirectory::open() 460 { 461 mSearchIndex = 0; 462 mStatus = Open; 463 return true; 464 } 465 466 bool MemDirectory::close() 467 { 468 return true; 469 } 470 471 bool MemDirectory::read(Attributes* entry) 472 { 473 if (mStatus != Open) 474 return false; 475 476 if (mSearchIndex < mDirectoryData->mDirectories.size()) 477 { 478 mDirectoryData->mDirectories[mSearchIndex]->getAttributes(entry); 479 mSearchIndex++; 480 return true; 481 } 482 483 AssertFatal(mSearchIndex > mDirectoryData->mDirectories.size(), "This should not happen!"); 484 U32 fileIndex = mSearchIndex - mDirectoryData->mDirectories.size(); 485 if (fileIndex < mDirectoryData->mFiles.size()) 486 { 487 mDirectoryData->mFiles[mSearchIndex]->getAttributes(entry); 488 mSearchIndex++; 489 return true; 490 } 491 492 return false; 493 } 494 495 U32 MemDirectory::calculateChecksum() 496 { 497 // Return checksum of current entry 498 return 0; 499 } 500 501 bool MemDirectory::getAttributes(Attributes* attr) 502 { 503 return mDirectoryData->getAttributes(attr); 504 } 505 506 FileNode::NodeStatus MemDirectory::getStatus() const 507 { 508 return mStatus; 509 } 510 } // Namespace Mem 511 512} // Namespace Torque 513