| @@ -898,6 +898,7 @@ | |||
| 4EEF0B0BB4C3D1956B04122B = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_FileOutputStream.h; path = ../../src/io/files/juce_FileOutputStream.h; sourceTree = SOURCE_ROOT; }; | |||
| 59B2FFF817679AEA84375E1B = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_FileSearchPath.cpp; path = ../../src/io/files/juce_FileSearchPath.cpp; sourceTree = SOURCE_ROOT; }; | |||
| 49BF2B02A6D7B4438FC24839 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_FileSearchPath.h; path = ../../src/io/files/juce_FileSearchPath.h; sourceTree = SOURCE_ROOT; }; | |||
| 00B348FA35A7F691AEF84FBA = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_MemoryMappedFile.h; path = ../../src/io/files/juce_MemoryMappedFile.h; sourceTree = SOURCE_ROOT; }; | |||
| D9B3C04F8EB4228DD59002E7 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_NamedPipe.cpp; path = ../../src/io/files/juce_NamedPipe.cpp; sourceTree = SOURCE_ROOT; }; | |||
| 42DA88264F768BAACD0414A3 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_NamedPipe.h; path = ../../src/io/files/juce_NamedPipe.h; sourceTree = SOURCE_ROOT; }; | |||
| 17C3AF03FF7AE88AE0C73311 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_TemporaryFile.cpp; path = ../../src/io/files/juce_TemporaryFile.cpp; sourceTree = SOURCE_ROOT; }; | |||
| @@ -1713,6 +1714,7 @@ | |||
| 4EEF0B0BB4C3D1956B04122B, | |||
| 59B2FFF817679AEA84375E1B, | |||
| 49BF2B02A6D7B4438FC24839, | |||
| 00B348FA35A7F691AEF84FBA, | |||
| D9B3C04F8EB4228DD59002E7, | |||
| 42DA88264F768BAACD0414A3, | |||
| 17C3AF03FF7AE88AE0C73311, | |||
| @@ -787,6 +787,7 @@ | |||
| <File RelativePath="..\..\src\io\files\juce_FileOutputStream.h"/> | |||
| <File RelativePath="..\..\src\io\files\juce_FileSearchPath.cpp"/> | |||
| <File RelativePath="..\..\src\io\files\juce_FileSearchPath.h"/> | |||
| <File RelativePath="..\..\src\io\files\juce_MemoryMappedFile.h"/> | |||
| <File RelativePath="..\..\src\io\files\juce_NamedPipe.cpp"/> | |||
| <File RelativePath="..\..\src\io\files\juce_NamedPipe.h"/> | |||
| <File RelativePath="..\..\src\io\files\juce_TemporaryFile.cpp"/> | |||
| @@ -787,6 +787,7 @@ | |||
| <File RelativePath="..\..\src\io\files\juce_FileOutputStream.h"/> | |||
| <File RelativePath="..\..\src\io\files\juce_FileSearchPath.cpp"/> | |||
| <File RelativePath="..\..\src\io\files\juce_FileSearchPath.h"/> | |||
| <File RelativePath="..\..\src\io\files\juce_MemoryMappedFile.h"/> | |||
| <File RelativePath="..\..\src\io\files\juce_NamedPipe.cpp"/> | |||
| <File RelativePath="..\..\src\io\files\juce_NamedPipe.h"/> | |||
| <File RelativePath="..\..\src\io\files\juce_TemporaryFile.cpp"/> | |||
| @@ -789,6 +789,7 @@ | |||
| <File RelativePath="..\..\src\io\files\juce_FileOutputStream.h"/> | |||
| <File RelativePath="..\..\src\io\files\juce_FileSearchPath.cpp"/> | |||
| <File RelativePath="..\..\src\io\files\juce_FileSearchPath.h"/> | |||
| <File RelativePath="..\..\src\io\files\juce_MemoryMappedFile.h"/> | |||
| <File RelativePath="..\..\src\io\files\juce_NamedPipe.cpp"/> | |||
| <File RelativePath="..\..\src\io\files\juce_NamedPipe.h"/> | |||
| <File RelativePath="..\..\src\io\files\juce_TemporaryFile.cpp"/> | |||
| @@ -741,6 +741,7 @@ | |||
| <ClInclude Include="..\..\src\io\files\juce_FileInputStream.h"/> | |||
| <ClInclude Include="..\..\src\io\files\juce_FileOutputStream.h"/> | |||
| <ClInclude Include="..\..\src\io\files\juce_FileSearchPath.h"/> | |||
| <ClInclude Include="..\..\src\io\files\juce_MemoryMappedFile.h"/> | |||
| <ClInclude Include="..\..\src\io\files\juce_NamedPipe.h"/> | |||
| <ClInclude Include="..\..\src\io\files\juce_TemporaryFile.h"/> | |||
| <ClInclude Include="..\..\src\io\files\juce_ZipFile.h"/> | |||
| @@ -2154,6 +2154,9 @@ | |||
| <ClInclude Include="..\..\src\io\files\juce_FileSearchPath.h"> | |||
| <Filter>Juce\Source\io\files</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="..\..\src\io\files\juce_MemoryMappedFile.h"> | |||
| <Filter>Juce\Source\io\files</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="..\..\src\io\files\juce_NamedPipe.h"> | |||
| <Filter>Juce\Source\io\files</Filter> | |||
| </ClInclude> | |||
| @@ -898,6 +898,7 @@ | |||
| 4EEF0B0BB4C3D1956B04122B = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_FileOutputStream.h; path = ../../src/io/files/juce_FileOutputStream.h; sourceTree = SOURCE_ROOT; }; | |||
| 59B2FFF817679AEA84375E1B = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_FileSearchPath.cpp; path = ../../src/io/files/juce_FileSearchPath.cpp; sourceTree = SOURCE_ROOT; }; | |||
| 49BF2B02A6D7B4438FC24839 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_FileSearchPath.h; path = ../../src/io/files/juce_FileSearchPath.h; sourceTree = SOURCE_ROOT; }; | |||
| 00B348FA35A7F691AEF84FBA = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_MemoryMappedFile.h; path = ../../src/io/files/juce_MemoryMappedFile.h; sourceTree = SOURCE_ROOT; }; | |||
| D9B3C04F8EB4228DD59002E7 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_NamedPipe.cpp; path = ../../src/io/files/juce_NamedPipe.cpp; sourceTree = SOURCE_ROOT; }; | |||
| 42DA88264F768BAACD0414A3 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_NamedPipe.h; path = ../../src/io/files/juce_NamedPipe.h; sourceTree = SOURCE_ROOT; }; | |||
| 17C3AF03FF7AE88AE0C73311 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_TemporaryFile.cpp; path = ../../src/io/files/juce_TemporaryFile.cpp; sourceTree = SOURCE_ROOT; }; | |||
| @@ -1713,6 +1714,7 @@ | |||
| 4EEF0B0BB4C3D1956B04122B, | |||
| 59B2FFF817679AEA84375E1B, | |||
| 49BF2B02A6D7B4438FC24839, | |||
| 00B348FA35A7F691AEF84FBA, | |||
| D9B3C04F8EB4228DD59002E7, | |||
| 42DA88264F768BAACD0414A3, | |||
| 17C3AF03FF7AE88AE0C73311, | |||
| @@ -1177,6 +1177,8 @@ | |||
| file="src/io/files/juce_FileSearchPath.cpp"/> | |||
| <FILE id="YJYo7slcr" name="juce_FileSearchPath.h" compile="0" resource="0" | |||
| file="src/io/files/juce_FileSearchPath.h"/> | |||
| <FILE id="gPKPMY" name="juce_MemoryMappedFile.h" compile="0" resource="0" | |||
| file="src/io/files/juce_MemoryMappedFile.h"/> | |||
| <FILE id="hwijIMGzE" name="juce_NamedPipe.cpp" compile="1" resource="0" | |||
| file="src/io/files/juce_NamedPipe.cpp"/> | |||
| <FILE id="Jv4ugNwIx" name="juce_NamedPipe.h" compile="0" resource="0" | |||
| @@ -773,6 +773,7 @@ protected: | |||
| #include <sys/ptrace.h> | |||
| #include <sys/vfs.h> | |||
| #include <sys/wait.h> | |||
| #include <sys/mman.h> | |||
| #include <fnmatch.h> | |||
| #include <utime.h> | |||
| #include <pwd.h> | |||
| @@ -922,6 +923,7 @@ protected: | |||
| #include <sys/param.h> | |||
| #include <sys/mount.h> | |||
| #include <sys/utsname.h> | |||
| #include <sys/mman.h> | |||
| #include <fnmatch.h> | |||
| #include <utime.h> | |||
| #include <dlfcn.h> | |||
| @@ -961,6 +963,7 @@ protected: | |||
| #include <sys/statfs.h> | |||
| #include <sys/ptrace.h> | |||
| #include <sys/sysinfo.h> | |||
| #include <sys/mman.h> | |||
| #include <pwd.h> | |||
| #include <dirent.h> | |||
| #include <fnmatch.h> | |||
| @@ -7857,53 +7860,48 @@ bool File::isAbsolutePath (const String& path) | |||
| const File File::getChildFile (String relativePath) const | |||
| { | |||
| if (isAbsolutePath (relativePath)) | |||
| { | |||
| // the path is really absolute.. | |||
| return File (relativePath); | |||
| } | |||
| else | |||
| String path (fullPath); | |||
| // It's relative, so remove any ../ or ./ bits at the start.. | |||
| if (relativePath[0] == '.') | |||
| { | |||
| // it's relative, so remove any ../ or ./ bits at the start. | |||
| String path (fullPath); | |||
| #if JUCE_WINDOWS | |||
| relativePath = relativePath.replaceCharacter ('/', '\\').trimStart(); | |||
| #else | |||
| relativePath = relativePath.trimStart(); | |||
| #endif | |||
| if (relativePath[0] == '.') | |||
| while (relativePath[0] == '.') | |||
| { | |||
| #if JUCE_WINDOWS | |||
| relativePath = relativePath.replaceCharacter ('/', '\\').trimStart(); | |||
| #else | |||
| relativePath = relativePath.trimStart(); | |||
| #endif | |||
| while (relativePath[0] == '.') | |||
| if (relativePath[1] == '.') | |||
| { | |||
| if (relativePath[1] == '.') | |||
| if (relativePath [2] == 0 || relativePath[2] == separator) | |||
| { | |||
| if (relativePath [2] == 0 || relativePath[2] == separator) | |||
| { | |||
| const int lastSlash = path.lastIndexOfChar (separator); | |||
| if (lastSlash >= 0) | |||
| path = path.substring (0, lastSlash); | |||
| const int lastSlash = path.lastIndexOfChar (separator); | |||
| if (lastSlash >= 0) | |||
| path = path.substring (0, lastSlash); | |||
| relativePath = relativePath.substring (3); | |||
| } | |||
| else | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| else if (relativePath[1] == separator) | |||
| { | |||
| relativePath = relativePath.substring (2); | |||
| relativePath = relativePath.substring (3); | |||
| } | |||
| else | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| else if (relativePath[1] == separator) | |||
| { | |||
| relativePath = relativePath.substring (2); | |||
| } | |||
| else | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| return File (addTrailingSeparator (path) + relativePath); | |||
| } | |||
| return File (addTrailingSeparator (path) + relativePath); | |||
| } | |||
| const File File::getSiblingFile (const String& fileName) const | |||
| @@ -8481,6 +8479,39 @@ public: | |||
| expect (mb[0] == '0'); | |||
| } | |||
| beginTest ("Memory-mapped files"); | |||
| { | |||
| MemoryMappedFile mmf (tempFile, MemoryMappedFile::readOnly); | |||
| expect (mmf.getSize() == 10); | |||
| expect (mmf.getData() != nullptr); | |||
| expect (memcmp (mmf.getData(), "0123456789", 10) == 0); | |||
| } | |||
| { | |||
| const File tempFile2 (tempFile.getNonexistentSibling (false)); | |||
| expect (tempFile2.create()); | |||
| expect (tempFile2.appendData ("xxxxxxxxxx", 10)); | |||
| { | |||
| MemoryMappedFile mmf (tempFile2, MemoryMappedFile::readWrite); | |||
| expect (mmf.getSize() == 10); | |||
| expect (mmf.getData() != nullptr); | |||
| memcpy (mmf.getData(), "abcdefghij", 10); | |||
| } | |||
| { | |||
| MemoryMappedFile mmf (tempFile2, MemoryMappedFile::readWrite); | |||
| expect (mmf.getSize() == 10); | |||
| expect (mmf.getData() != nullptr); | |||
| expect (memcmp (mmf.getData(), "abcdefghij", 10) == 0); | |||
| } | |||
| expect (tempFile2.deleteFile()); | |||
| } | |||
| beginTest ("More writing"); | |||
| expect (tempFile.appendData ("abcdefghij", 10)); | |||
| expect (tempFile.getSize() == 20); | |||
| expect (tempFile.replaceWithData ("abcdefghij", 10)); | |||
| @@ -244800,6 +244831,55 @@ void FileOutputStream::flushInternal() | |||
| status = WindowsFileHelpers::getResultForLastError(); | |||
| } | |||
| MemoryMappedFile::MemoryMappedFile (const File& file, MemoryMappedFile::AccessMode mode) | |||
| : address (nullptr), | |||
| internal (nullptr), | |||
| length (0) | |||
| { | |||
| jassert (mode == readOnly || mode == readWrite); | |||
| DWORD accessMode = GENERIC_READ, shareMode = FILE_SHARE_READ, createType = OPEN_EXISTING; | |||
| DWORD protect = PAGE_READONLY, access = FILE_MAP_READ; | |||
| if (mode == readWrite) | |||
| { | |||
| accessMode = GENERIC_READ | GENERIC_WRITE; | |||
| createType = OPEN_ALWAYS; | |||
| protect = PAGE_READWRITE; | |||
| access = FILE_MAP_ALL_ACCESS; | |||
| } | |||
| HANDLE h = CreateFile (file.getFullPathName().toWideCharPointer(), accessMode, FILE_SHARE_READ, 0, | |||
| createType, FILE_ATTRIBUTE_NORMAL, 0); | |||
| internal = (void*) h; | |||
| if (h != INVALID_HANDLE_VALUE) | |||
| { | |||
| const int64 fileSize = file.getSize(); | |||
| HANDLE mappingHandle = CreateFileMapping (h, 0, protect, (DWORD) (fileSize >> 32), (DWORD) fileSize, 0); | |||
| if (mappingHandle != 0) | |||
| { | |||
| address = MapViewOfFile (mappingHandle, access, 0, 0, (SIZE_T) fileSize); | |||
| if (address != nullptr) | |||
| length = (size_t) fileSize; | |||
| CloseHandle (mappingHandle); | |||
| } | |||
| } | |||
| } | |||
| MemoryMappedFile::~MemoryMappedFile() | |||
| { | |||
| if (address != nullptr) | |||
| UnmapViewOfFile (address); | |||
| if (internal != nullptr) | |||
| CloseHandle ((HANDLE) internal); | |||
| } | |||
| int64 File::getSize() const | |||
| { | |||
| WIN32_FILE_ATTRIBUTE_DATA attributes; | |||
| @@ -260588,6 +260668,46 @@ void FileOutputStream::flushInternal() | |||
| status = getResultForErrno(); | |||
| } | |||
| MemoryMappedFile::MemoryMappedFile (const File& file, MemoryMappedFile::AccessMode mode) | |||
| : address (nullptr), | |||
| internal (nullptr), | |||
| length (0) | |||
| { | |||
| jassert (mode == readOnly || mode == readWrite); | |||
| const int fd = open (file.getFullPathName().toUTF8(), | |||
| mode == readWrite ? (O_CREAT + O_RDWR) : O_RDONLY, 00644); | |||
| internal = reinterpret_cast<void*> (fd); | |||
| if (fd != -1) | |||
| { | |||
| const int64 fileSize = file.getSize(); | |||
| address = mmap (0, (size_t) fileSize, | |||
| mode == readWrite ? (PROT_READ | PROT_WRITE) : PROT_READ, | |||
| MAP_SHARED, fd, 0); | |||
| if (address == MAP_FAILED) | |||
| address = nullptr; | |||
| else | |||
| length = (size_t) fileSize; | |||
| } | |||
| } | |||
| MemoryMappedFile::~MemoryMappedFile() | |||
| { | |||
| const int fd = reinterpret_cast <int> (internal); | |||
| if (fd != 0) | |||
| { | |||
| if (address != nullptr) | |||
| munmap (address, length); | |||
| close (fd); | |||
| } | |||
| } | |||
| const File juce_getExecutableFile() | |||
| { | |||
| #if JUCE_ANDROID | |||
| @@ -270579,6 +270699,46 @@ void FileOutputStream::flushInternal() | |||
| status = getResultForErrno(); | |||
| } | |||
| MemoryMappedFile::MemoryMappedFile (const File& file, MemoryMappedFile::AccessMode mode) | |||
| : address (nullptr), | |||
| internal (nullptr), | |||
| length (0) | |||
| { | |||
| jassert (mode == readOnly || mode == readWrite); | |||
| const int fd = open (file.getFullPathName().toUTF8(), | |||
| mode == readWrite ? (O_CREAT + O_RDWR) : O_RDONLY, 00644); | |||
| internal = reinterpret_cast<void*> (fd); | |||
| if (fd != -1) | |||
| { | |||
| const int64 fileSize = file.getSize(); | |||
| address = mmap (0, (size_t) fileSize, | |||
| mode == readWrite ? (PROT_READ | PROT_WRITE) : PROT_READ, | |||
| MAP_SHARED, fd, 0); | |||
| if (address == MAP_FAILED) | |||
| address = nullptr; | |||
| else | |||
| length = (size_t) fileSize; | |||
| } | |||
| } | |||
| MemoryMappedFile::~MemoryMappedFile() | |||
| { | |||
| const int fd = reinterpret_cast <int> (internal); | |||
| if (fd != 0) | |||
| { | |||
| if (address != nullptr) | |||
| munmap (address, length); | |||
| close (fd); | |||
| } | |||
| } | |||
| const File juce_getExecutableFile() | |||
| { | |||
| #if JUCE_ANDROID | |||
| @@ -287465,6 +287625,46 @@ void FileOutputStream::flushInternal() | |||
| status = getResultForErrno(); | |||
| } | |||
| MemoryMappedFile::MemoryMappedFile (const File& file, MemoryMappedFile::AccessMode mode) | |||
| : address (nullptr), | |||
| internal (nullptr), | |||
| length (0) | |||
| { | |||
| jassert (mode == readOnly || mode == readWrite); | |||
| const int fd = open (file.getFullPathName().toUTF8(), | |||
| mode == readWrite ? (O_CREAT + O_RDWR) : O_RDONLY, 00644); | |||
| internal = reinterpret_cast<void*> (fd); | |||
| if (fd != -1) | |||
| { | |||
| const int64 fileSize = file.getSize(); | |||
| address = mmap (0, (size_t) fileSize, | |||
| mode == readWrite ? (PROT_READ | PROT_WRITE) : PROT_READ, | |||
| MAP_SHARED, fd, 0); | |||
| if (address == MAP_FAILED) | |||
| address = nullptr; | |||
| else | |||
| length = (size_t) fileSize; | |||
| } | |||
| } | |||
| MemoryMappedFile::~MemoryMappedFile() | |||
| { | |||
| const int fd = reinterpret_cast <int> (internal); | |||
| if (fd != 0) | |||
| { | |||
| if (address != nullptr) | |||
| munmap (address, length); | |||
| close (fd); | |||
| } | |||
| } | |||
| const File juce_getExecutableFile() | |||
| { | |||
| #if JUCE_ANDROID | |||
| @@ -73,7 +73,7 @@ namespace JuceDummyNamespace {} | |||
| */ | |||
| #define JUCE_MAJOR_VERSION 1 | |||
| #define JUCE_MINOR_VERSION 53 | |||
| #define JUCE_BUILDNUMBER 88 | |||
| #define JUCE_BUILDNUMBER 89 | |||
| /** Current Juce version number. | |||
| @@ -19409,6 +19409,68 @@ private: | |||
| /*** End of inlined file: juce_FileSearchPath.h ***/ | |||
| #endif | |||
| #ifndef __JUCE_MEMORYMAPPEDFILE_JUCEHEADER__ | |||
| /*** Start of inlined file: juce_MemoryMappedFile.h ***/ | |||
| #ifndef __JUCE_MEMORYMAPPEDFILE_JUCEHEADER__ | |||
| #define __JUCE_MEMORYMAPPEDFILE_JUCEHEADER__ | |||
| /** | |||
| Maps a file into virtual memory for easy reading and/or writing. | |||
| */ | |||
| class JUCE_API MemoryMappedFile | |||
| { | |||
| public: | |||
| /** The read/write flags used when opening a memory mapped file. */ | |||
| enum AccessMode | |||
| { | |||
| readOnly, /**< Indicates that the memory can only be read. */ | |||
| readWrite /**< Indicates that the memory can be read and written to - changes that are | |||
| made will be flushed back to disk at the whim of the OS. */ | |||
| }; | |||
| /** Opens 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. | |||
| */ | |||
| MemoryMappedFile (const File& file, AccessMode mode); | |||
| /** Destructor. */ | |||
| ~MemoryMappedFile(); | |||
| /** Returns the address at which this file has been mapped, or a null pointer if | |||
| the file couldn't be successfully mapped. | |||
| */ | |||
| void* getData() const noexcept { return address; } | |||
| /** 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; } | |||
| private: | |||
| void* address; | |||
| void* internal; | |||
| size_t length; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryMappedFile); | |||
| }; | |||
| #endif // __JUCE_MEMORYMAPPEDFILE_JUCEHEADER__ | |||
| /*** End of inlined file: juce_MemoryMappedFile.h ***/ | |||
| #endif | |||
| #ifndef __JUCE_NAMEDPIPE_JUCEHEADER__ | |||
| @@ -33,7 +33,7 @@ | |||
| */ | |||
| #define JUCE_MAJOR_VERSION 1 | |||
| #define JUCE_MINOR_VERSION 53 | |||
| #define JUCE_BUILDNUMBER 88 | |||
| #define JUCE_BUILDNUMBER 89 | |||
| /** Current Juce version number. | |||
| @@ -380,53 +380,48 @@ bool File::isAbsolutePath (const String& path) | |||
| const File File::getChildFile (String relativePath) const | |||
| { | |||
| if (isAbsolutePath (relativePath)) | |||
| { | |||
| // the path is really absolute.. | |||
| return File (relativePath); | |||
| } | |||
| else | |||
| String path (fullPath); | |||
| // It's relative, so remove any ../ or ./ bits at the start.. | |||
| if (relativePath[0] == '.') | |||
| { | |||
| // it's relative, so remove any ../ or ./ bits at the start. | |||
| String path (fullPath); | |||
| #if JUCE_WINDOWS | |||
| relativePath = relativePath.replaceCharacter ('/', '\\').trimStart(); | |||
| #else | |||
| relativePath = relativePath.trimStart(); | |||
| #endif | |||
| if (relativePath[0] == '.') | |||
| while (relativePath[0] == '.') | |||
| { | |||
| #if JUCE_WINDOWS | |||
| relativePath = relativePath.replaceCharacter ('/', '\\').trimStart(); | |||
| #else | |||
| relativePath = relativePath.trimStart(); | |||
| #endif | |||
| while (relativePath[0] == '.') | |||
| if (relativePath[1] == '.') | |||
| { | |||
| if (relativePath[1] == '.') | |||
| if (relativePath [2] == 0 || relativePath[2] == separator) | |||
| { | |||
| if (relativePath [2] == 0 || relativePath[2] == separator) | |||
| { | |||
| const int lastSlash = path.lastIndexOfChar (separator); | |||
| if (lastSlash >= 0) | |||
| path = path.substring (0, lastSlash); | |||
| relativePath = relativePath.substring (3); | |||
| } | |||
| else | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| else if (relativePath[1] == separator) | |||
| { | |||
| relativePath = relativePath.substring (2); | |||
| const int lastSlash = path.lastIndexOfChar (separator); | |||
| if (lastSlash >= 0) | |||
| path = path.substring (0, lastSlash); | |||
| relativePath = relativePath.substring (3); | |||
| } | |||
| else | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| else if (relativePath[1] == separator) | |||
| { | |||
| relativePath = relativePath.substring (2); | |||
| } | |||
| else | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| return File (addTrailingSeparator (path) + relativePath); | |||
| } | |||
| return File (addTrailingSeparator (path) + relativePath); | |||
| } | |||
| const File File::getSiblingFile (const String& fileName) const | |||
| @@ -904,6 +899,8 @@ const File File::createTempFile (const String& fileNameEnding) | |||
| #include "../../utilities/juce_UnitTest.h" | |||
| #include "../../maths/juce_Random.h" | |||
| #include "juce_MemoryMappedFile.h" | |||
| class FileTests : public UnitTest | |||
| { | |||
| @@ -1022,6 +1019,39 @@ public: | |||
| expect (mb[0] == '0'); | |||
| } | |||
| beginTest ("Memory-mapped files"); | |||
| { | |||
| MemoryMappedFile mmf (tempFile, MemoryMappedFile::readOnly); | |||
| expect (mmf.getSize() == 10); | |||
| expect (mmf.getData() != nullptr); | |||
| expect (memcmp (mmf.getData(), "0123456789", 10) == 0); | |||
| } | |||
| { | |||
| const File tempFile2 (tempFile.getNonexistentSibling (false)); | |||
| expect (tempFile2.create()); | |||
| expect (tempFile2.appendData ("xxxxxxxxxx", 10)); | |||
| { | |||
| MemoryMappedFile mmf (tempFile2, MemoryMappedFile::readWrite); | |||
| expect (mmf.getSize() == 10); | |||
| expect (mmf.getData() != nullptr); | |||
| memcpy (mmf.getData(), "abcdefghij", 10); | |||
| } | |||
| { | |||
| MemoryMappedFile mmf (tempFile2, MemoryMappedFile::readWrite); | |||
| expect (mmf.getSize() == 10); | |||
| expect (mmf.getData() != nullptr); | |||
| expect (memcmp (mmf.getData(), "abcdefghij", 10) == 0); | |||
| } | |||
| expect (tempFile2.deleteFile()); | |||
| } | |||
| beginTest ("More writing"); | |||
| expect (tempFile.appendData ("abcdefghij", 10)); | |||
| expect (tempFile.getSize() == 20); | |||
| expect (tempFile.replaceWithData ("abcdefghij", 10)); | |||
| @@ -0,0 +1,84 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-11 by Raw Material Software Ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||
| Public License (Version 2), as published by the Free Software Foundation. | |||
| A copy of the license is included in the JUCE distribution, or can be found | |||
| online at www.gnu.org/licenses. | |||
| JUCE 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 for more details. | |||
| ------------------------------------------------------------------------------ | |||
| To release a closed-source product which uses JUCE, commercial licenses are | |||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_MEMORYMAPPEDFILE_JUCEHEADER__ | |||
| #define __JUCE_MEMORYMAPPEDFILE_JUCEHEADER__ | |||
| #include "juce_File.h" | |||
| //============================================================================== | |||
| /** | |||
| Maps a file into virtual memory for easy reading and/or writing. | |||
| */ | |||
| class JUCE_API MemoryMappedFile | |||
| { | |||
| public: | |||
| /** The read/write flags used when opening a memory mapped file. */ | |||
| enum AccessMode | |||
| { | |||
| readOnly, /**< Indicates that the memory can only be read. */ | |||
| readWrite /**< Indicates that the memory can be read and written to - changes that are | |||
| made will be flushed back to disk at the whim of the OS. */ | |||
| }; | |||
| /** Opens 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. | |||
| */ | |||
| MemoryMappedFile (const File& file, AccessMode mode); | |||
| /** Destructor. */ | |||
| ~MemoryMappedFile(); | |||
| /** Returns the address at which this file has been mapped, or a null pointer if | |||
| the file couldn't be successfully mapped. | |||
| */ | |||
| void* getData() const noexcept { return address; } | |||
| /** 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; } | |||
| private: | |||
| //============================================================================== | |||
| void* address; | |||
| void* internal; | |||
| size_t length; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryMappedFile); | |||
| }; | |||
| #endif // __JUCE_MEMORYMAPPEDFILE_JUCEHEADER__ | |||
| @@ -146,6 +146,9 @@ | |||
| #ifndef __JUCE_FILESEARCHPATH_JUCEHEADER__ | |||
| #include "io/files/juce_FileSearchPath.h" | |||
| #endif | |||
| #ifndef __JUCE_MEMORYMAPPEDFILE_JUCEHEADER__ | |||
| #include "io/files/juce_MemoryMappedFile.h" | |||
| #endif | |||
| #ifndef __JUCE_NAMEDPIPE_JUCEHEADER__ | |||
| #include "io/files/juce_NamedPipe.h" | |||
| #endif | |||
| @@ -53,6 +53,7 @@ BEGIN_JUCE_NAMESPACE | |||
| #include "../../io/files/juce_FileOutputStream.h" | |||
| #include "../../io/files/juce_NamedPipe.h" | |||
| #include "../../io/files/juce_DirectoryIterator.h" | |||
| #include "../../io/files/juce_MemoryMappedFile.h" | |||
| #include "../../io/network/juce_URL.h" | |||
| #include "../../io/network/juce_MACAddress.h" | |||
| #include "../../core/juce_PlatformUtilities.h" | |||
| @@ -43,6 +43,7 @@ | |||
| #include <sys/statfs.h> | |||
| #include <sys/ptrace.h> | |||
| #include <sys/sysinfo.h> | |||
| #include <sys/mman.h> | |||
| #include <pwd.h> | |||
| #include <dirent.h> | |||
| #include <fnmatch.h> | |||
| @@ -523,6 +523,47 @@ void FileOutputStream::flushInternal() | |||
| status = getResultForErrno(); | |||
| } | |||
| //============================================================================== | |||
| MemoryMappedFile::MemoryMappedFile (const File& file, MemoryMappedFile::AccessMode mode) | |||
| : address (nullptr), | |||
| internal (nullptr), | |||
| length (0) | |||
| { | |||
| jassert (mode == readOnly || mode == readWrite); | |||
| const int fd = open (file.getFullPathName().toUTF8(), | |||
| mode == readWrite ? (O_CREAT + O_RDWR) : O_RDONLY, 00644); | |||
| internal = reinterpret_cast<void*> (fd); | |||
| if (fd != -1) | |||
| { | |||
| const int64 fileSize = file.getSize(); | |||
| address = mmap (0, (size_t) fileSize, | |||
| mode == readWrite ? (PROT_READ | PROT_WRITE) : PROT_READ, | |||
| MAP_SHARED, fd, 0); | |||
| if (address == MAP_FAILED) | |||
| address = nullptr; | |||
| else | |||
| length = (size_t) fileSize; | |||
| } | |||
| } | |||
| MemoryMappedFile::~MemoryMappedFile() | |||
| { | |||
| const int fd = reinterpret_cast <int> (internal); | |||
| if (fd != 0) | |||
| { | |||
| if (address != nullptr) | |||
| munmap (address, length); | |||
| close (fd); | |||
| } | |||
| } | |||
| //============================================================================== | |||
| const File juce_getExecutableFile() | |||
| { | |||
| @@ -64,6 +64,7 @@ BEGIN_JUCE_NAMESPACE | |||
| #include "../../io/files/juce_FileInputStream.h" | |||
| #include "../../io/files/juce_FileOutputStream.h" | |||
| #include "../../io/files/juce_DirectoryIterator.h" | |||
| #include "../../io/files/juce_MemoryMappedFile.h" | |||
| #include "../../io/network/juce_URL.h" | |||
| #include "../../io/network/juce_MACAddress.h" | |||
| #include "../../io/streams/juce_MemoryInputStream.h" | |||
| @@ -42,6 +42,7 @@ | |||
| #include <sys/ptrace.h> | |||
| #include <sys/vfs.h> | |||
| #include <sys/wait.h> | |||
| #include <sys/mman.h> | |||
| #include <fnmatch.h> | |||
| #include <utime.h> | |||
| #include <pwd.h> | |||
| @@ -53,6 +53,7 @@ BEGIN_JUCE_NAMESPACE | |||
| #include "../../io/files/juce_FileOutputStream.h" | |||
| #include "../../io/files/juce_NamedPipe.h" | |||
| #include "../../io/files/juce_DirectoryIterator.h" | |||
| #include "../../io/files/juce_MemoryMappedFile.h" | |||
| #include "../../io/network/juce_URL.h" | |||
| #include "../../io/network/juce_MACAddress.h" | |||
| #include "../../io/streams/juce_MemoryInputStream.h" | |||
| @@ -70,6 +70,7 @@ | |||
| #include <sys/param.h> | |||
| #include <sys/mount.h> | |||
| #include <sys/utsname.h> | |||
| #include <sys/mman.h> | |||
| #include <fnmatch.h> | |||
| #include <utime.h> | |||
| #include <dlfcn.h> | |||
| @@ -299,6 +299,56 @@ void FileOutputStream::flushInternal() | |||
| status = WindowsFileHelpers::getResultForLastError(); | |||
| } | |||
| //============================================================================== | |||
| MemoryMappedFile::MemoryMappedFile (const File& file, MemoryMappedFile::AccessMode mode) | |||
| : address (nullptr), | |||
| internal (nullptr), | |||
| length (0) | |||
| { | |||
| jassert (mode == readOnly || mode == readWrite); | |||
| DWORD accessMode = GENERIC_READ, shareMode = FILE_SHARE_READ, createType = OPEN_EXISTING; | |||
| DWORD protect = PAGE_READONLY, access = FILE_MAP_READ; | |||
| if (mode == readWrite) | |||
| { | |||
| accessMode = GENERIC_READ | GENERIC_WRITE; | |||
| createType = OPEN_ALWAYS; | |||
| protect = PAGE_READWRITE; | |||
| access = FILE_MAP_ALL_ACCESS; | |||
| } | |||
| HANDLE h = CreateFile (file.getFullPathName().toWideCharPointer(), accessMode, FILE_SHARE_READ, 0, | |||
| createType, FILE_ATTRIBUTE_NORMAL, 0); | |||
| internal = (void*) h; | |||
| if (h != INVALID_HANDLE_VALUE) | |||
| { | |||
| const int64 fileSize = file.getSize(); | |||
| HANDLE mappingHandle = CreateFileMapping (h, 0, protect, (DWORD) (fileSize >> 32), (DWORD) fileSize, 0); | |||
| if (mappingHandle != 0) | |||
| { | |||
| address = MapViewOfFile (mappingHandle, access, 0, 0, (SIZE_T) fileSize); | |||
| if (address != nullptr) | |||
| length = (size_t) fileSize; | |||
| CloseHandle (mappingHandle); | |||
| } | |||
| } | |||
| } | |||
| MemoryMappedFile::~MemoryMappedFile() | |||
| { | |||
| if (address != nullptr) | |||
| UnmapViewOfFile (address); | |||
| if (internal != nullptr) | |||
| CloseHandle ((HANDLE) internal); | |||
| } | |||
| //============================================================================== | |||
| int64 File::getSize() const | |||
| { | |||
| @@ -54,6 +54,7 @@ BEGIN_JUCE_NAMESPACE | |||
| #include "../../io/streams/juce_MemoryOutputStream.h" | |||
| #include "../../io/files/juce_NamedPipe.h" | |||
| #include "../../io/files/juce_DirectoryIterator.h" | |||
| #include "../../io/files/juce_MemoryMappedFile.h" | |||
| #include "../../io/network/juce_URL.h" | |||
| #include "../../io/network/juce_MACAddress.h" | |||
| #include "../../core/juce_PlatformUtilities.h" | |||