dolphin/Source/Core/Common/Src/MappedFile.cpp

233 lines
4.2 KiB
C++

// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifdef _WIN32
#include <windows.h>
#elif __linux__
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#endif
#include "Common.h"
#include "MappedFile.h"
namespace Common
{
class CMappedFile
: public IMappedFile
{
public:
CMappedFile(void);
~CMappedFile(void);
bool Open(const char* _szFilename);
bool IsOpen(void);
void Close(void);
u64 GetSize(void);
u8* Lock(u64 _offset, u64 _size);
void Unlock(u8* ptr);
private:
u64 size;
typedef std::map<u8*, u8*>Lockmap;
Lockmap lockMap;
#ifdef _WIN32
HANDLE hFile;
HANDLE hFileMapping;
#elif POSIX
int fd;
typedef std::map<u8*, size_t>Sizemap;
Sizemap sizeMap;
#endif
int granularity;
};
CMappedFile::CMappedFile()
{
#ifdef _WIN32
hFile = INVALID_HANDLE_VALUE;
SYSTEM_INFO info;
GetSystemInfo(&info);
granularity = (int)info.dwAllocationGranularity;
#elif POSIX
fd = -1;
granularity = getpagesize(); //sysconf(_SC_PAGE_SIZE);
#endif
}
CMappedFile::~CMappedFile()
{
Close();
}
bool CMappedFile::Open(const char* filename)
{
Close();
#ifdef _WIN32
hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
return(false);
}
hFileMapping = CreateFileMapping(hFile, 0, PAGE_READONLY, 0, 0, NULL);
if (hFileMapping == NULL)
{
CloseHandle(hFile);
hFile = 0;
return(false);
}
u32 high = 0;
u32 low = GetFileSize(hFile, (LPDWORD)&high);
size = (u64)low | ((u64)high << 32);
#elif POSIX
fd = open(filename, O_RDONLY);
size = 0; //TODO
#endif
return(true);
}
bool CMappedFile::IsOpen()
{
#ifdef _WIN32
return(hFile != INVALID_HANDLE_VALUE);
#elif POSIX
return(fd != -1);
#endif
}
u64 CMappedFile::GetSize()
{
return(size);
}
void CMappedFile::Close()
{
#ifdef _WIN32
if (hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hFileMapping);
CloseHandle(hFile);
lockMap.clear();
hFile = INVALID_HANDLE_VALUE;
}
#elif POSIX
if (fd != -1)
{
lockMap.clear();
sizeMap.clear();
close(fd);
}
fd = -1;
#endif
}
u8* CMappedFile::Lock(u64 offset, u64 size)
{
#ifdef _WIN32
if (hFile != INVALID_HANDLE_VALUE)
#elif POSIX
if (fd != -1)
#endif
{
u64 realOffset = offset & ~(granularity - 1);
s64 difference = offset - realOffset;
u64 fake_size = ((offset & 4095) + size + 4095) & 4095;
#ifdef _WIN32
u8* realPtr = (u8*)MapViewOfFile(hFileMapping, FILE_MAP_READ, (DWORD)(realOffset >> 32), (DWORD)realOffset, (SIZE_T)(size));
if (realPtr == NULL)
{
return(NULL);
}
#elif POSIX
// TODO
u8* realPtr = (u8*)mmap(0, fake_size, PROT_READ, MAP_PRIVATE, fd, (off_t)realOffset);
if (!realPtr)
{
PanicAlert("Map Failed");
exit(0);
}
#endif
u8* fakePtr = realPtr + difference;
//add to map
lockMap[fakePtr] = realPtr;
#ifndef _WIN32
sizeMap[fakePtr] = size + difference;
#endif
return(fakePtr);
}
else
{
return(0);
}
}
void CMappedFile::Unlock(u8* ptr)
{
if (ptr != 0)
{
Lockmap::iterator iter = lockMap.find(ptr);
if (iter != lockMap.end())
{
#ifdef _WIN32
UnmapViewOfFile((*iter).second);
#else
munmap((*iter).second, sizeMap[ptr]);
#endif
lockMap.erase(iter);
}
else
{
PanicAlert("CMappedFile : Unlock failed");
}
}
}
IMappedFile* IMappedFile::CreateMappedFile(void)
{
return(new CMappedFile);
}
} // end of namespace Common