memVolume.cpp

Engine/source/core/memVolume.cpp

More...

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