From e6d817d20d9831dbd6e0d95acdb75e2112542d53 Mon Sep 17 00:00:00 2001 From: jules Date: Sun, 17 Feb 2013 22:38:25 +0000 Subject: [PATCH] Extended MemoryMappedFile to allow loading of file subsections. --- modules/juce_core/files/juce_File.cpp | 13 +++++++++ .../juce_core/files/juce_MemoryMappedFile.h | 28 +++++++++++++++++-- .../juce_core/native/juce_posix_SharedCode.h | 25 +++++++++-------- modules/juce_core/native/juce_win32_Files.cpp | 24 ++++++++++------ 4 files changed, 67 insertions(+), 23 deletions(-) diff --git a/modules/juce_core/files/juce_File.cpp b/modules/juce_core/files/juce_File.cpp index 6d5a603240..0f4972d1c2 100644 --- a/modules/juce_core/files/juce_File.cpp +++ b/modules/juce_core/files/juce_File.cpp @@ -881,6 +881,19 @@ File File::createTempFile (const String& fileNameEnding) return tempFile; } +//============================================================================== +MemoryMappedFile::MemoryMappedFile (const File& file, MemoryMappedFile::AccessMode mode) + : address (nullptr), range (0, file.getSize()), fileHandle (0) +{ + openInternal (file, mode); +} + +MemoryMappedFile::MemoryMappedFile (const File& file, const Range& fileRange, AccessMode mode) + : address (nullptr), range (fileRange.getIntersectionWith (Range (0, file.getSize()))), fileHandle (0) +{ + openInternal (file, mode); +} + //============================================================================== #if JUCE_UNIT_TESTS diff --git a/modules/juce_core/files/juce_MemoryMappedFile.h b/modules/juce_core/files/juce_MemoryMappedFile.h index c801a053ba..62ddfd54d6 100644 --- a/modules/juce_core/files/juce_MemoryMappedFile.h +++ b/modules/juce_core/files/juce_MemoryMappedFile.h @@ -57,6 +57,26 @@ public: */ MemoryMappedFile (const File& file, AccessMode mode); + /** Opens a section of a file and maps it to an area of virtual memory. + + The file should already exist, and should already be the size that you want to work with + when you call this. If the file is resized after being opened, the behaviour is undefined. + + If the file exists and the operation succeeds, the getData() and getSize() methods will + return the location and size of the data that can be read or written. Note that the entire + file is not read into memory immediately - the OS simply creates a virtual mapping, which + will lazily pull the data into memory when blocks are accessed. + + If the file can't be opened for some reason, the getData() method will return a null pointer. + + NOTE: the start of the actual range used may be rounded-down to a multiple of the OS's page-size, + so do not assume that the mapped memory will begin at exactly the position you requested - always + use getRange() to check the actual range that is being used. + */ + MemoryMappedFile (const File& file, + const Range& fileRange, + AccessMode mode); + /** Destructor. */ ~MemoryMappedFile(); @@ -68,13 +88,15 @@ public: /** Returns the number of bytes of data that are available for reading or writing. This will normally be the size of the file. */ - size_t getSize() const noexcept { return length; } + size_t getSize() const noexcept { return (size_t) range.getLength(); } + /** Returns the section of the file at which the mapped memory represents. */ + Range getRange() const noexcept { return range; } private: //============================================================================== void* address; - size_t length; + Range range; #if JUCE_WINDOWS void* fileHandle; @@ -82,6 +104,8 @@ private: int fileHandle; #endif + void openInternal (const File&, AccessMode); + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryMappedFile) }; diff --git a/modules/juce_core/native/juce_posix_SharedCode.h b/modules/juce_core/native/juce_posix_SharedCode.h index 67f9a3dbd4..a885440a02 100644 --- a/modules/juce_core/native/juce_posix_SharedCode.h +++ b/modules/juce_core/native/juce_posix_SharedCode.h @@ -546,36 +546,37 @@ String SystemStats::getEnvironmentVariable (const String& name, const String& de } //============================================================================== -MemoryMappedFile::MemoryMappedFile (const File& file, MemoryMappedFile::AccessMode mode) - : address (nullptr), - length (0), - fileHandle (0) +void MemoryMappedFile::openInternal (const File& file, AccessMode mode) { jassert (mode == readOnly || mode == readWrite); + if (range.getStart() > 0) + { + const long pageSize = sysconf (_SC_PAGE_SIZE); + range.setStart (range.getStart() - (range.getStart() % pageSize)); + } + fileHandle = open (file.getFullPathName().toUTF8(), mode == readWrite ? (O_CREAT + O_RDWR) : O_RDONLY, 00644); if (fileHandle != -1) { - const int64 fileSize = file.getSize(); - - void* m = mmap (0, (size_t) fileSize, + void* m = mmap (0, (size_t) range.getLength(), mode == readWrite ? (PROT_READ | PROT_WRITE) : PROT_READ, - MAP_SHARED, fileHandle, 0); + MAP_SHARED, fileHandle, + (off_t) range.getStart()); if (m != MAP_FAILED) - { address = m; - length = (size_t) fileSize; - } + else + range = Range(); } } MemoryMappedFile::~MemoryMappedFile() { if (address != nullptr) - munmap (address, length); + munmap (address, range.getLength()); if (fileHandle != 0) close (fileHandle); diff --git a/modules/juce_core/native/juce_win32_Files.cpp b/modules/juce_core/native/juce_win32_Files.cpp index 58202f91f8..509b9eaf17 100644 --- a/modules/juce_core/native/juce_win32_Files.cpp +++ b/modules/juce_core/native/juce_win32_Files.cpp @@ -310,13 +310,18 @@ Result FileOutputStream::truncate() } //============================================================================== -MemoryMappedFile::MemoryMappedFile (const File& file, MemoryMappedFile::AccessMode mode) - : address (nullptr), - length (0), - fileHandle (nullptr) +void MemoryMappedFile::openInternal (const File& file, AccessMode mode) { jassert (mode == readOnly || mode == readWrite); + if (range.getStart() > 0) + { + SYSTEM_INFO systemInfo; + GetNativeSystemInfo (&systemInfo); + + range.setStart (range.getStart() - (range.getStart() % systemInfo.dwAllocationGranularity)); + } + DWORD accessMode = GENERIC_READ, createType = OPEN_EXISTING; DWORD protect = PAGE_READONLY, access = FILE_MAP_READ; @@ -334,15 +339,16 @@ MemoryMappedFile::MemoryMappedFile (const File& file, MemoryMappedFile::AccessMo if (h != INVALID_HANDLE_VALUE) { fileHandle = (void*) h; - const int64 fileSize = file.getSize(); - HANDLE mappingHandle = CreateFileMapping (h, 0, protect, (DWORD) (fileSize >> 32), (DWORD) fileSize, 0); + HANDLE mappingHandle = CreateFileMapping (h, 0, protect, (DWORD) (range.getEnd() >> 32), (DWORD) range.getEnd(), 0); + if (mappingHandle != 0) { - address = MapViewOfFile (mappingHandle, access, 0, 0, (SIZE_T) fileSize); + address = MapViewOfFile (mappingHandle, access, (DWORD) (range.getStart() >> 32), + (DWORD) range.getStart(), (SIZE_T) range.getLength()); - if (address != nullptr) - length = (size_t) fileSize; + if (address == nullptr) + range = Range(); CloseHandle (mappingHandle); }