mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-27 22:45:52 +00:00
Add Beast fork from JUCE commit 265fb0e8ebc26e1469d6edcc68d2ca9acefeb508
This commit is contained in:
24
.gitignore
vendored
24
.gitignore
vendored
@@ -1,3 +1,25 @@
|
||||
._*
|
||||
*.mode1v3
|
||||
*.pbxuser
|
||||
*.perspectivev3
|
||||
*.user
|
||||
*.ncb
|
||||
*.suo
|
||||
*.obj
|
||||
*.ilk
|
||||
*.pch
|
||||
*.pdb
|
||||
*.dep
|
||||
*.idb
|
||||
*.manifest
|
||||
*.manifest.res
|
||||
*.o
|
||||
*.d
|
||||
*.sdf
|
||||
xcuserdata
|
||||
contents.xcworkspacedata
|
||||
.DS_Store
|
||||
.svn
|
||||
profile
|
||||
Builds/VisualStudio2012/Debug
|
||||
Builds/VisualStudio2012/Release
|
||||
Builds/VisualStudio2012/*.user
|
||||
|
||||
23
Builds/VisualStudio2012/BeastConfig.h
Normal file
23
Builds/VisualStudio2012/BeastConfig.h
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
#ifndef BEAST_BEASTCONFIG_HEADER
|
||||
#define BEAST_BEASTCONFIG_HEADER
|
||||
|
||||
// beast_core flags:
|
||||
|
||||
#ifndef BEAST_FORCE_DEBUG
|
||||
//#define BEAST_FORCE_DEBUG
|
||||
#endif
|
||||
|
||||
#ifndef BEAST_LOG_ASSERTIONS
|
||||
//#define BEAST_LOG_ASSERTIONS 1
|
||||
#endif
|
||||
|
||||
#ifndef BEAST_CHECK_MEMORY_LEAKS
|
||||
//#define BEAST_CHECK_MEMORY_LEAKS
|
||||
#endif
|
||||
|
||||
#ifndef BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||
//#define BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -13,14 +13,482 @@
|
||||
<ItemGroup>
|
||||
<None Include="..\..\CodingStyle.md" />
|
||||
<None Include="..\..\modules\beast_core\beast_core.mm" />
|
||||
<None Include="..\..\modules\beast_core\native\beast_mac_Files.mm">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</None>
|
||||
<None Include="..\..\modules\beast_core\native\beast_mac_Network.mm">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</None>
|
||||
<None Include="..\..\modules\beast_core\native\beast_mac_Strings.mm">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</None>
|
||||
<None Include="..\..\modules\beast_core\native\beast_mac_SystemStats.mm">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</None>
|
||||
<None Include="..\..\modules\beast_core\native\beast_mac_Threads.mm">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</None>
|
||||
<None Include="..\..\modules\beast_core\native\java\BeastAppActivity.java">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</None>
|
||||
<None Include="..\..\modules\beast_core\zip\zlib\README" />
|
||||
<None Include="..\..\README.md" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\modules\beast_core\beast_core.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_AbstractFifo.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_Array.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_ArrayAllocationBase.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_DynamicObject.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_ElementComparator.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_HashMap.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_LinkedListPointer.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_NamedValueSet.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_OwnedArray.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_PropertySet.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_ReferenceCountedArray.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_ScopedValueSetter.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_SortedSet.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_SparseSet.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_Variant.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\files\beast_DirectoryIterator.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\files\beast_File.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\files\beast_FileInputStream.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\files\beast_FileOutputStream.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\files\beast_FileSearchPath.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\files\beast_MemoryMappedFile.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\files\beast_TemporaryFile.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\json\beast_JSON.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\logging\beast_FileLogger.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\logging\beast_Logger.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\maths\beast_BigInteger.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\maths\beast_Expression.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\maths\beast_MathsFunctions.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\maths\beast_Random.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\maths\beast_Range.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\memory\beast_Atomic.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\memory\beast_ByteOrder.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\memory\beast_HeapBlock.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\memory\beast_LeakedObjectDetector.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\memory\beast_Memory.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\memory\beast_MemoryBlock.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\memory\beast_OptionalScopedPointer.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\memory\beast_ReferenceCountedObject.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\memory\beast_ScopedPointer.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\memory\beast_Singleton.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\memory\beast_WeakReference.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\misc\beast_Result.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\misc\beast_Uuid.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\misc\beast_WindowsRegistry.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\native\beast_android_JNIHelpers.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\native\beast_BasicNativeHeaders.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\native\beast_osx_ObjCHelpers.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\native\beast_posix_SharedCode.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\native\beast_win32_ComSmartPtr.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\network\beast_IPAddress.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\network\beast_MACAddress.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\network\beast_NamedPipe.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\network\beast_Socket.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\network\beast_URL.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\streams\beast_BufferedInputStream.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\streams\beast_FileInputSource.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\streams\beast_InputSource.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\streams\beast_InputStream.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\streams\beast_MemoryInputStream.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\streams\beast_MemoryOutputStream.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\streams\beast_OutputStream.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\streams\beast_SubregionStream.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\system\beast_PlatformDefs.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\system\beast_StandardHeader.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\system\beast_SystemStats.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\system\beast_TargetPlatform.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\text\beast_CharacterFunctions.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\text\beast_CharPointer_ASCII.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\text\beast_CharPointer_UTF16.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\text\beast_CharPointer_UTF32.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\text\beast_CharPointer_UTF8.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\text\beast_Identifier.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\text\beast_LocalisedStrings.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\text\beast_NewLine.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\text\beast_String.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\text\beast_StringArray.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\text\beast_StringPairArray.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\text\beast_StringPool.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\text\beast_TextDiff.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_ChildProcess.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_CriticalSection.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_DynamicLibrary.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_HighResolutionTimer.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_InterProcessLock.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_Process.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_ReadWriteLock.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_ScopedLock.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_ScopedReadLock.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_ScopedWriteLock.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_SpinLock.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_Thread.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_ThreadLocalValue.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_ThreadPool.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_TimeSliceThread.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_WaitableEvent.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\time\beast_PerformanceCounter.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\time\beast_RelativeTime.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\time\beast_Time.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\unit_tests\beast_UnitTest.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\xml\beast_XmlDocument.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\xml\beast_XmlElement.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\beast_GZIPCompressorOutputStream.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\beast_GZIPDecompressorInputStream.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\beast_ZipFile.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\zlib\crc32.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\zlib\deflate.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\zlib\inffast.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\zlib\inffixed.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\zlib\inflate.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\zlib\inftrees.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\zlib\trees.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\zlib\zconf.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\zlib\zconf.in.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\zlib\zlib.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\zlib\zutil.h" />
|
||||
<ClInclude Include="BeastConfig.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\modules\beast_core\beast_core.cpp" />
|
||||
<ClCompile Include="..\..\modules\beast_core\containers\beast_AbstractFifo.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\containers\beast_DynamicObject.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\containers\beast_NamedValueSet.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\containers\beast_PropertySet.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\containers\beast_Variant.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\files\beast_DirectoryIterator.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\files\beast_File.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\files\beast_FileInputStream.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\files\beast_FileOutputStream.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\files\beast_FileSearchPath.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\files\beast_TemporaryFile.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\json\beast_JSON.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\logging\beast_FileLogger.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\logging\beast_Logger.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\maths\beast_BigInteger.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\maths\beast_Expression.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\maths\beast_Random.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\memory\beast_MemoryBlock.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\misc\beast_Result.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\misc\beast_Uuid.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_android_Files.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_android_Misc.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_android_Network.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_android_SystemStats.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_android_Threads.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_linux_Files.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_linux_Network.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_linux_SystemStats.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_linux_Threads.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_posix_NamedPipe.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_win32_Files.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_win32_Network.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_win32_Registry.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_win32_SystemStats.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_win32_Threads.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\network\beast_IPAddress.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\network\beast_MACAddress.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\network\beast_NamedPipe.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\network\beast_Socket.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\network\beast_URL.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\streams\beast_BufferedInputStream.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\streams\beast_FileInputSource.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\streams\beast_InputStream.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\streams\beast_MemoryInputStream.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\streams\beast_MemoryOutputStream.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\streams\beast_OutputStream.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\streams\beast_SubregionStream.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\system\beast_SystemStats.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\text\beast_CharacterFunctions.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\text\beast_Identifier.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\text\beast_LocalisedStrings.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\text\beast_String.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\text\beast_StringArray.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\text\beast_StringPairArray.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\text\beast_StringPool.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\text\beast_TextDiff.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\threads\beast_ChildProcess.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\threads\beast_HighResolutionTimer.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\threads\beast_ReadWriteLock.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\threads\beast_Thread.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\threads\beast_ThreadPool.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\threads\beast_TimeSliceThread.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\time\beast_PerformanceCounter.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\time\beast_RelativeTime.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\time\beast_Time.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\unit_tests\beast_UnitTest.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\xml\beast_XmlDocument.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\xml\beast_XmlElement.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\beast_GZIPCompressorOutputStream.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\beast_GZIPDecompressorInputStream.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\beast_ZipFile.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\zlib\adler32.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\zlib\compress.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\zlib\crc32.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\zlib\deflate.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\zlib\infback.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\zlib\inffast.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\zlib\inflate.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\zlib\inftrees.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\zlib\trees.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\zlib\uncompr.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\zlib\zutil.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}</ProjectGuid>
|
||||
@@ -59,6 +527,7 @@
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -74,6 +543,7 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
||||
@@ -6,26 +6,690 @@
|
||||
<None Include="..\..\modules\beast_core\beast_core.mm">
|
||||
<Filter>beast_core</Filter>
|
||||
</None>
|
||||
<None Include="..\..\modules\beast_core\native\beast_mac_Files.mm">
|
||||
<Filter>beast_core\native</Filter>
|
||||
</None>
|
||||
<None Include="..\..\modules\beast_core\native\beast_mac_Network.mm">
|
||||
<Filter>beast_core\native</Filter>
|
||||
</None>
|
||||
<None Include="..\..\modules\beast_core\native\beast_mac_Strings.mm">
|
||||
<Filter>beast_core\native</Filter>
|
||||
</None>
|
||||
<None Include="..\..\modules\beast_core\native\beast_mac_SystemStats.mm">
|
||||
<Filter>beast_core\native</Filter>
|
||||
</None>
|
||||
<None Include="..\..\modules\beast_core\native\beast_mac_Threads.mm">
|
||||
<Filter>beast_core\native</Filter>
|
||||
</None>
|
||||
<None Include="..\..\modules\beast_core\zip\zlib\README">
|
||||
<Filter>beast_core\zip\zlib</Filter>
|
||||
</None>
|
||||
<None Include="..\..\modules\beast_core\native\java\BeastAppActivity.java">
|
||||
<Filter>beast_core\native\java</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="beast_core">
|
||||
<UniqueIdentifier>{6dafd8d5-2901-4b41-85b7-52f6e86baacc}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_core\containers">
|
||||
<UniqueIdentifier>{7cc041c8-fdf4-4e98-a56a-df516c2a9aa2}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_core\files">
|
||||
<UniqueIdentifier>{3b7d8d7e-eabc-423c-a631-2ff37bf9b9eb}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_core\json">
|
||||
<UniqueIdentifier>{abe24d69-c1d1-49e2-98a1-1e7bf760b97a}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_core\logging">
|
||||
<UniqueIdentifier>{0fa6b76b-305f-473c-9b94-c1028a3af3fc}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_core\maths">
|
||||
<UniqueIdentifier>{e2339099-bb8e-4437-ae8b-d4f64ef1e3f3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_core\memory">
|
||||
<UniqueIdentifier>{883f776d-bec2-4e7a-b4e8-726ed3039071}</UniqueIdentifier>
|
||||
<UniqueIdentifier>{a89aa17e-4e01-4c2d-ba7e-196e9e0b67bb}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_core\misc">
|
||||
<UniqueIdentifier>{64a314e1-0361-428a-a294-0615d8140f58}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_core\native">
|
||||
<UniqueIdentifier>{1d018a70-71b3-4d70-9280-02efd4f348de}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_core\network">
|
||||
<UniqueIdentifier>{ad675f57-9303-4712-9ff2-c7f59f959e7b}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_core\streams">
|
||||
<UniqueIdentifier>{016d839c-4860-4bc3-8f6c-e965f50c2bfa}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_core\system">
|
||||
<UniqueIdentifier>{7fb77af6-ce16-4f53-823e-906963b42985}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_core\text">
|
||||
<UniqueIdentifier>{4603580c-5668-4e70-bed8-77f00f03f0ff}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_core\threads">
|
||||
<UniqueIdentifier>{3409dc7a-92b5-43aa-b678-fde9f82ced55}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_core\time">
|
||||
<UniqueIdentifier>{d3ea4af5-ae48-4144-a2ef-a212342d72ee}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_core\unit_tests">
|
||||
<UniqueIdentifier>{0a8a6870-87a4-4f19-bbd3-b277f94bb83e}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_core\xml">
|
||||
<UniqueIdentifier>{a1a38659-7779-41d6-8a3c-068433c4deaf}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_core\zip">
|
||||
<UniqueIdentifier>{df5f5a69-5919-4a24-bbce-b3f87e4903cf}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_core\native\java">
|
||||
<UniqueIdentifier>{b0d206d9-c002-4be1-b503-4ad16aca838a}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_core\zip\zlib">
|
||||
<UniqueIdentifier>{31038502-9139-4c19-bd67-8f90f08a70ca}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\modules\beast_core\memory\beast_ScopedPointer.h">
|
||||
<Filter>beast_core\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\beast_core.h">
|
||||
<Filter>beast_core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_AbstractFifo.h">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_Array.h">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_ArrayAllocationBase.h">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_DynamicObject.h">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_ElementComparator.h">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_HashMap.h">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_LinkedListPointer.h">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_NamedValueSet.h">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_OwnedArray.h">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_PropertySet.h">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_ReferenceCountedArray.h">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_ScopedValueSetter.h">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_SortedSet.h">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_SparseSet.h">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_Variant.h">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\files\beast_DirectoryIterator.h">
|
||||
<Filter>beast_core\files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\files\beast_File.h">
|
||||
<Filter>beast_core\files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\files\beast_FileInputStream.h">
|
||||
<Filter>beast_core\files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\files\beast_FileOutputStream.h">
|
||||
<Filter>beast_core\files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\files\beast_FileSearchPath.h">
|
||||
<Filter>beast_core\files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\files\beast_MemoryMappedFile.h">
|
||||
<Filter>beast_core\files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\files\beast_TemporaryFile.h">
|
||||
<Filter>beast_core\files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\json\beast_JSON.h">
|
||||
<Filter>beast_core\json</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\logging\beast_FileLogger.h">
|
||||
<Filter>beast_core\logging</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\logging\beast_Logger.h">
|
||||
<Filter>beast_core\logging</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\maths\beast_BigInteger.h">
|
||||
<Filter>beast_core\maths</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\maths\beast_Expression.h">
|
||||
<Filter>beast_core\maths</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\maths\beast_MathsFunctions.h">
|
||||
<Filter>beast_core\maths</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\maths\beast_Random.h">
|
||||
<Filter>beast_core\maths</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\maths\beast_Range.h">
|
||||
<Filter>beast_core\maths</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\memory\beast_Atomic.h">
|
||||
<Filter>beast_core\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\memory\beast_ByteOrder.h">
|
||||
<Filter>beast_core\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\memory\beast_HeapBlock.h">
|
||||
<Filter>beast_core\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\memory\beast_LeakedObjectDetector.h">
|
||||
<Filter>beast_core\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\memory\beast_Memory.h">
|
||||
<Filter>beast_core\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\memory\beast_MemoryBlock.h">
|
||||
<Filter>beast_core\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\memory\beast_OptionalScopedPointer.h">
|
||||
<Filter>beast_core\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\memory\beast_ReferenceCountedObject.h">
|
||||
<Filter>beast_core\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\memory\beast_ScopedPointer.h">
|
||||
<Filter>beast_core\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\memory\beast_Singleton.h">
|
||||
<Filter>beast_core\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\memory\beast_WeakReference.h">
|
||||
<Filter>beast_core\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\misc\beast_Result.h">
|
||||
<Filter>beast_core\misc</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\misc\beast_Uuid.h">
|
||||
<Filter>beast_core\misc</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\misc\beast_WindowsRegistry.h">
|
||||
<Filter>beast_core\misc</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\native\beast_android_JNIHelpers.h">
|
||||
<Filter>beast_core\native</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\native\beast_BasicNativeHeaders.h">
|
||||
<Filter>beast_core\native</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\native\beast_osx_ObjCHelpers.h">
|
||||
<Filter>beast_core\native</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\native\beast_posix_SharedCode.h">
|
||||
<Filter>beast_core\native</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\native\beast_win32_ComSmartPtr.h">
|
||||
<Filter>beast_core\native</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\network\beast_IPAddress.h">
|
||||
<Filter>beast_core\network</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\network\beast_MACAddress.h">
|
||||
<Filter>beast_core\network</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\network\beast_NamedPipe.h">
|
||||
<Filter>beast_core\network</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\network\beast_Socket.h">
|
||||
<Filter>beast_core\network</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\network\beast_URL.h">
|
||||
<Filter>beast_core\network</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\streams\beast_BufferedInputStream.h">
|
||||
<Filter>beast_core\streams</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\streams\beast_FileInputSource.h">
|
||||
<Filter>beast_core\streams</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\streams\beast_InputSource.h">
|
||||
<Filter>beast_core\streams</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\streams\beast_InputStream.h">
|
||||
<Filter>beast_core\streams</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\streams\beast_MemoryInputStream.h">
|
||||
<Filter>beast_core\streams</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\streams\beast_MemoryOutputStream.h">
|
||||
<Filter>beast_core\streams</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\streams\beast_OutputStream.h">
|
||||
<Filter>beast_core\streams</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\streams\beast_SubregionStream.h">
|
||||
<Filter>beast_core\streams</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\system\beast_PlatformDefs.h">
|
||||
<Filter>beast_core\system</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\system\beast_StandardHeader.h">
|
||||
<Filter>beast_core\system</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\system\beast_SystemStats.h">
|
||||
<Filter>beast_core\system</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\system\beast_TargetPlatform.h">
|
||||
<Filter>beast_core\system</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\text\beast_CharacterFunctions.h">
|
||||
<Filter>beast_core\text</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\text\beast_CharPointer_ASCII.h">
|
||||
<Filter>beast_core\text</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\text\beast_CharPointer_UTF8.h">
|
||||
<Filter>beast_core\text</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\text\beast_CharPointer_UTF16.h">
|
||||
<Filter>beast_core\text</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\text\beast_CharPointer_UTF32.h">
|
||||
<Filter>beast_core\text</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\text\beast_Identifier.h">
|
||||
<Filter>beast_core\text</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\text\beast_LocalisedStrings.h">
|
||||
<Filter>beast_core\text</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\text\beast_NewLine.h">
|
||||
<Filter>beast_core\text</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\text\beast_String.h">
|
||||
<Filter>beast_core\text</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\text\beast_StringArray.h">
|
||||
<Filter>beast_core\text</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\text\beast_StringPairArray.h">
|
||||
<Filter>beast_core\text</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\text\beast_StringPool.h">
|
||||
<Filter>beast_core\text</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\text\beast_TextDiff.h">
|
||||
<Filter>beast_core\text</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_ChildProcess.h">
|
||||
<Filter>beast_core\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_CriticalSection.h">
|
||||
<Filter>beast_core\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_DynamicLibrary.h">
|
||||
<Filter>beast_core\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_HighResolutionTimer.h">
|
||||
<Filter>beast_core\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_InterProcessLock.h">
|
||||
<Filter>beast_core\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_Process.h">
|
||||
<Filter>beast_core\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_ReadWriteLock.h">
|
||||
<Filter>beast_core\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_ScopedLock.h">
|
||||
<Filter>beast_core\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_ScopedReadLock.h">
|
||||
<Filter>beast_core\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_ScopedWriteLock.h">
|
||||
<Filter>beast_core\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_SpinLock.h">
|
||||
<Filter>beast_core\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_Thread.h">
|
||||
<Filter>beast_core\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_ThreadLocalValue.h">
|
||||
<Filter>beast_core\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_ThreadPool.h">
|
||||
<Filter>beast_core\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_TimeSliceThread.h">
|
||||
<Filter>beast_core\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\threads\beast_WaitableEvent.h">
|
||||
<Filter>beast_core\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\time\beast_PerformanceCounter.h">
|
||||
<Filter>beast_core\time</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\time\beast_RelativeTime.h">
|
||||
<Filter>beast_core\time</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\time\beast_Time.h">
|
||||
<Filter>beast_core\time</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\unit_tests\beast_UnitTest.h">
|
||||
<Filter>beast_core\unit_tests</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\xml\beast_XmlDocument.h">
|
||||
<Filter>beast_core\xml</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\xml\beast_XmlElement.h">
|
||||
<Filter>beast_core\xml</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\beast_GZIPCompressorOutputStream.h">
|
||||
<Filter>beast_core\zip</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\beast_GZIPDecompressorInputStream.h">
|
||||
<Filter>beast_core\zip</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\beast_ZipFile.h">
|
||||
<Filter>beast_core\zip</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\zlib\crc32.h">
|
||||
<Filter>beast_core\zip\zlib</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\zlib\deflate.h">
|
||||
<Filter>beast_core\zip\zlib</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\zlib\inffast.h">
|
||||
<Filter>beast_core\zip\zlib</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\zlib\inffixed.h">
|
||||
<Filter>beast_core\zip\zlib</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\zlib\inflate.h">
|
||||
<Filter>beast_core\zip\zlib</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\zlib\inftrees.h">
|
||||
<Filter>beast_core\zip\zlib</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\zlib\trees.h">
|
||||
<Filter>beast_core\zip\zlib</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\zlib\zconf.h">
|
||||
<Filter>beast_core\zip\zlib</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\zlib\zconf.in.h">
|
||||
<Filter>beast_core\zip\zlib</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\zlib\zlib.h">
|
||||
<Filter>beast_core\zip\zlib</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\zip\zlib\zutil.h">
|
||||
<Filter>beast_core\zip\zlib</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="BeastConfig.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\modules\beast_core\beast_core.cpp">
|
||||
<Filter>beast_core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\containers\beast_AbstractFifo.cpp">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\containers\beast_DynamicObject.cpp">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\containers\beast_NamedValueSet.cpp">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\containers\beast_PropertySet.cpp">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\containers\beast_Variant.cpp">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\files\beast_DirectoryIterator.cpp">
|
||||
<Filter>beast_core\files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\files\beast_File.cpp">
|
||||
<Filter>beast_core\files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\files\beast_FileInputStream.cpp">
|
||||
<Filter>beast_core\files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\files\beast_FileOutputStream.cpp">
|
||||
<Filter>beast_core\files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\files\beast_FileSearchPath.cpp">
|
||||
<Filter>beast_core\files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\files\beast_TemporaryFile.cpp">
|
||||
<Filter>beast_core\files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\json\beast_JSON.cpp">
|
||||
<Filter>beast_core\json</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\logging\beast_FileLogger.cpp">
|
||||
<Filter>beast_core\logging</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\logging\beast_Logger.cpp">
|
||||
<Filter>beast_core\logging</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\maths\beast_BigInteger.cpp">
|
||||
<Filter>beast_core\maths</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\maths\beast_Expression.cpp">
|
||||
<Filter>beast_core\maths</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\maths\beast_Random.cpp">
|
||||
<Filter>beast_core\maths</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\memory\beast_MemoryBlock.cpp">
|
||||
<Filter>beast_core\memory</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\misc\beast_Result.cpp">
|
||||
<Filter>beast_core\misc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\misc\beast_Uuid.cpp">
|
||||
<Filter>beast_core\misc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_android_Files.cpp">
|
||||
<Filter>beast_core\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_android_Misc.cpp">
|
||||
<Filter>beast_core\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_android_Network.cpp">
|
||||
<Filter>beast_core\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_android_SystemStats.cpp">
|
||||
<Filter>beast_core\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_android_Threads.cpp">
|
||||
<Filter>beast_core\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_linux_Files.cpp">
|
||||
<Filter>beast_core\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_linux_Network.cpp">
|
||||
<Filter>beast_core\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_linux_SystemStats.cpp">
|
||||
<Filter>beast_core\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_linux_Threads.cpp">
|
||||
<Filter>beast_core\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_posix_NamedPipe.cpp">
|
||||
<Filter>beast_core\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_win32_Files.cpp">
|
||||
<Filter>beast_core\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_win32_Network.cpp">
|
||||
<Filter>beast_core\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_win32_Registry.cpp">
|
||||
<Filter>beast_core\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_win32_SystemStats.cpp">
|
||||
<Filter>beast_core\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\native\beast_win32_Threads.cpp">
|
||||
<Filter>beast_core\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\network\beast_IPAddress.cpp">
|
||||
<Filter>beast_core\network</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\network\beast_MACAddress.cpp">
|
||||
<Filter>beast_core\network</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\network\beast_NamedPipe.cpp">
|
||||
<Filter>beast_core\network</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\network\beast_Socket.cpp">
|
||||
<Filter>beast_core\network</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\network\beast_URL.cpp">
|
||||
<Filter>beast_core\network</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\streams\beast_BufferedInputStream.cpp">
|
||||
<Filter>beast_core\streams</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\streams\beast_FileInputSource.cpp">
|
||||
<Filter>beast_core\streams</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\streams\beast_InputStream.cpp">
|
||||
<Filter>beast_core\streams</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\streams\beast_MemoryInputStream.cpp">
|
||||
<Filter>beast_core\streams</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\streams\beast_MemoryOutputStream.cpp">
|
||||
<Filter>beast_core\streams</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\streams\beast_OutputStream.cpp">
|
||||
<Filter>beast_core\streams</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\streams\beast_SubregionStream.cpp">
|
||||
<Filter>beast_core\streams</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\system\beast_SystemStats.cpp">
|
||||
<Filter>beast_core\system</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\text\beast_CharacterFunctions.cpp">
|
||||
<Filter>beast_core\text</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\text\beast_Identifier.cpp">
|
||||
<Filter>beast_core\text</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\text\beast_LocalisedStrings.cpp">
|
||||
<Filter>beast_core\text</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\text\beast_String.cpp">
|
||||
<Filter>beast_core\text</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\text\beast_StringArray.cpp">
|
||||
<Filter>beast_core\text</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\text\beast_StringPairArray.cpp">
|
||||
<Filter>beast_core\text</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\text\beast_StringPool.cpp">
|
||||
<Filter>beast_core\text</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\text\beast_TextDiff.cpp">
|
||||
<Filter>beast_core\text</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\threads\beast_ChildProcess.cpp">
|
||||
<Filter>beast_core\threads</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\threads\beast_HighResolutionTimer.cpp">
|
||||
<Filter>beast_core\threads</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\threads\beast_ReadWriteLock.cpp">
|
||||
<Filter>beast_core\threads</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\threads\beast_Thread.cpp">
|
||||
<Filter>beast_core\threads</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\threads\beast_ThreadPool.cpp">
|
||||
<Filter>beast_core\threads</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\threads\beast_TimeSliceThread.cpp">
|
||||
<Filter>beast_core\threads</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\time\beast_PerformanceCounter.cpp">
|
||||
<Filter>beast_core\time</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\time\beast_RelativeTime.cpp">
|
||||
<Filter>beast_core\time</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\time\beast_Time.cpp">
|
||||
<Filter>beast_core\time</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\unit_tests\beast_UnitTest.cpp">
|
||||
<Filter>beast_core\unit_tests</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\xml\beast_XmlDocument.cpp">
|
||||
<Filter>beast_core\xml</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\xml\beast_XmlElement.cpp">
|
||||
<Filter>beast_core\xml</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\beast_GZIPCompressorOutputStream.cpp">
|
||||
<Filter>beast_core\zip</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\beast_GZIPDecompressorInputStream.cpp">
|
||||
<Filter>beast_core\zip</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\beast_ZipFile.cpp">
|
||||
<Filter>beast_core\zip</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\zlib\adler32.c">
|
||||
<Filter>beast_core\zip\zlib</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\zlib\compress.c">
|
||||
<Filter>beast_core\zip\zlib</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\zlib\crc32.c">
|
||||
<Filter>beast_core\zip\zlib</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\zlib\deflate.c">
|
||||
<Filter>beast_core\zip\zlib</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\zlib\infback.c">
|
||||
<Filter>beast_core\zip\zlib</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\zlib\inffast.c">
|
||||
<Filter>beast_core\zip\zlib</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\zlib\inflate.c">
|
||||
<Filter>beast_core\zip\zlib</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\zlib\inftrees.c">
|
||||
<Filter>beast_core\zip\zlib</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\zlib\trees.c">
|
||||
<Filter>beast_core\zip\zlib</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\zlib\uncompr.c">
|
||||
<Filter>beast_core\zip\zlib</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\zlib\zutil.c">
|
||||
<Filter>beast_core\zip\zlib</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -6,3 +6,9 @@ No external dependencies, no complicated build steps.
|
||||
Things people need for building peer to peer, concurrent, cryptographic systems.
|
||||
|
||||
The hope is that this will replace the use of boost and other cumbersome jalopies.
|
||||
|
||||
## JUCE
|
||||
|
||||
Beast is based on the juce_core module which is provided under the ISC
|
||||
license. More information about JUCE is available at
|
||||
http://www.juce.com
|
||||
|
||||
@@ -1,2 +1,213 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#if defined (BEAST_CORE_BEASTHEADER) && ! BEAST_AMALGAMATED_INCLUDE
|
||||
/* When you add this cpp file to your project, you mustn't include it in a file where you've
|
||||
already included any other headers - just put it inside a file on its own, possibly with your config
|
||||
flags preceding it, but don't include anything else. That also includes avoiding any automatic prefix
|
||||
header files that the compiler may be using.
|
||||
*/
|
||||
#error "Incorrect use of BEAST cpp file"
|
||||
#endif
|
||||
|
||||
// Your project must contain a BeastConfig.h file with your project-specific settings in it,
|
||||
// and your header search path must make it accessible to the module's files.
|
||||
#include "BeastConfig.h"
|
||||
|
||||
//==============================================================================
|
||||
#include "native/beast_BasicNativeHeaders.h"
|
||||
#include "beast_core.h"
|
||||
|
||||
#include <locale>
|
||||
#include <cctype>
|
||||
#include <sys/timeb.h>
|
||||
|
||||
#if ! BEAST_ANDROID
|
||||
#include <cwctype>
|
||||
#endif
|
||||
|
||||
#if BEAST_WINDOWS
|
||||
#include <ctime>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
#if ! BEAST_MINGW
|
||||
#include <Dbghelp.h>
|
||||
|
||||
#if ! BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||
#pragma comment (lib, "DbgHelp.lib")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if BEAST_MINGW
|
||||
#include <ws2spi.h>
|
||||
#endif
|
||||
|
||||
#else
|
||||
#if BEAST_LINUX || BEAST_ANDROID
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/errno.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#if BEAST_LINUX
|
||||
#include <langinfo.h>
|
||||
#endif
|
||||
|
||||
#include <pwd.h>
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/time.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#if ! BEAST_ANDROID
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if BEAST_MAC || BEAST_IOS
|
||||
#include <xlocale.h>
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
|
||||
#if BEAST_ANDROID
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
|
||||
//==============================================================================
|
||||
namespace beast
|
||||
{
|
||||
|
||||
#include "containers/beast_AbstractFifo.cpp"
|
||||
#include "containers/beast_DynamicObject.cpp"
|
||||
#include "containers/beast_NamedValueSet.cpp"
|
||||
#include "containers/beast_PropertySet.cpp"
|
||||
#include "containers/beast_Variant.cpp"
|
||||
#include "files/beast_DirectoryIterator.cpp"
|
||||
#include "files/beast_File.cpp"
|
||||
#include "files/beast_FileInputStream.cpp"
|
||||
#include "files/beast_FileOutputStream.cpp"
|
||||
#include "files/beast_FileSearchPath.cpp"
|
||||
#include "files/beast_TemporaryFile.cpp"
|
||||
#include "json/beast_JSON.cpp"
|
||||
#include "logging/beast_FileLogger.cpp"
|
||||
#include "logging/beast_Logger.cpp"
|
||||
#include "maths/beast_BigInteger.cpp"
|
||||
#include "maths/beast_Expression.cpp"
|
||||
#include "maths/beast_Random.cpp"
|
||||
#include "memory/beast_MemoryBlock.cpp"
|
||||
#include "misc/beast_Result.cpp"
|
||||
#include "misc/beast_Uuid.cpp"
|
||||
#include "network/beast_MACAddress.cpp"
|
||||
#include "network/beast_NamedPipe.cpp"
|
||||
#include "network/beast_Socket.cpp"
|
||||
#include "network/beast_URL.cpp"
|
||||
#include "network/beast_IPAddress.cpp"
|
||||
#include "streams/beast_BufferedInputStream.cpp"
|
||||
#include "streams/beast_FileInputSource.cpp"
|
||||
#include "streams/beast_InputStream.cpp"
|
||||
#include "streams/beast_MemoryInputStream.cpp"
|
||||
#include "streams/beast_MemoryOutputStream.cpp"
|
||||
#include "streams/beast_OutputStream.cpp"
|
||||
#include "streams/beast_SubregionStream.cpp"
|
||||
#include "system/beast_SystemStats.cpp"
|
||||
#include "text/beast_CharacterFunctions.cpp"
|
||||
#include "text/beast_Identifier.cpp"
|
||||
#include "text/beast_LocalisedStrings.cpp"
|
||||
#include "text/beast_String.cpp"
|
||||
#include "text/beast_StringArray.cpp"
|
||||
#include "text/beast_StringPairArray.cpp"
|
||||
#include "text/beast_StringPool.cpp"
|
||||
#include "text/beast_TextDiff.cpp"
|
||||
#include "threads/beast_ChildProcess.cpp"
|
||||
#include "threads/beast_ReadWriteLock.cpp"
|
||||
#include "threads/beast_Thread.cpp"
|
||||
#include "threads/beast_ThreadPool.cpp"
|
||||
#include "threads/beast_TimeSliceThread.cpp"
|
||||
#include "time/beast_PerformanceCounter.cpp"
|
||||
#include "time/beast_RelativeTime.cpp"
|
||||
#include "time/beast_Time.cpp"
|
||||
#include "unit_tests/beast_UnitTest.cpp"
|
||||
#include "xml/beast_XmlDocument.cpp"
|
||||
#include "xml/beast_XmlElement.cpp"
|
||||
#include "zip/beast_GZIPDecompressorInputStream.cpp"
|
||||
#include "zip/beast_GZIPCompressorOutputStream.cpp"
|
||||
#include "zip/beast_ZipFile.cpp"
|
||||
|
||||
//==============================================================================
|
||||
#if BEAST_MAC || BEAST_IOS
|
||||
#include "native/beast_osx_ObjCHelpers.h"
|
||||
#endif
|
||||
|
||||
#if BEAST_ANDROID
|
||||
#include "native/beast_android_JNIHelpers.h"
|
||||
#endif
|
||||
|
||||
#if ! BEAST_WINDOWS
|
||||
#include "native/beast_posix_SharedCode.h"
|
||||
#include "native/beast_posix_NamedPipe.cpp"
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#if BEAST_MAC || BEAST_IOS
|
||||
#include "native/beast_mac_Files.mm"
|
||||
#include "native/beast_mac_Network.mm"
|
||||
#include "native/beast_mac_Strings.mm"
|
||||
#include "native/beast_mac_SystemStats.mm"
|
||||
#include "native/beast_mac_Threads.mm"
|
||||
|
||||
//==============================================================================
|
||||
#elif BEAST_WINDOWS
|
||||
#include "native/beast_win32_ComSmartPtr.h"
|
||||
#include "native/beast_win32_Files.cpp"
|
||||
#include "native/beast_win32_Network.cpp"
|
||||
#include "native/beast_win32_Registry.cpp"
|
||||
#include "native/beast_win32_SystemStats.cpp"
|
||||
#include "native/beast_win32_Threads.cpp"
|
||||
|
||||
//==============================================================================
|
||||
#elif BEAST_LINUX
|
||||
#include "native/beast_linux_Files.cpp"
|
||||
#include "native/beast_linux_Network.cpp"
|
||||
#include "native/beast_linux_SystemStats.cpp"
|
||||
#include "native/beast_linux_Threads.cpp"
|
||||
|
||||
//==============================================================================
|
||||
#elif BEAST_ANDROID
|
||||
#include "native/beast_android_Files.cpp"
|
||||
#include "native/beast_android_Misc.cpp"
|
||||
#include "native/beast_android_Network.cpp"
|
||||
#include "native/beast_android_SystemStats.cpp"
|
||||
#include "native/beast_android_Threads.cpp"
|
||||
|
||||
#endif
|
||||
|
||||
#include "threads/beast_HighResolutionTimer.cpp"
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,440 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_CORE_BEASTHEADER
|
||||
#define BEAST_CORE_BEASTHEADER
|
||||
|
||||
#ifndef BEAST_BEASTCONFIG_HEADER
|
||||
/* If you fail to make sure that all your compile units are building Beast with the same set of
|
||||
option flags, then there's a risk that different compile units will treat the classes as having
|
||||
different memory layouts, leading to very nasty memory corruption errors when they all get
|
||||
linked together. That's why it's best to always include the BeastConfig.h file before any beast headers.
|
||||
*/
|
||||
#ifdef _MSC_VER
|
||||
#pragma message ("Have you included your BeastConfig.h file before including the Beast headers?")
|
||||
#else
|
||||
#warning "Have you included your BeastConfig.h file before including the Beast headers?"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#include "system/beast_TargetPlatform.h"
|
||||
|
||||
//=============================================================================
|
||||
/** Config: BEAST_FORCE_DEBUG
|
||||
|
||||
Normally, BEAST_DEBUG is set to 1 or 0 based on compiler and project settings,
|
||||
but if you define this value, you can override this to force it to be true or false.
|
||||
*/
|
||||
#ifndef BEAST_FORCE_DEBUG
|
||||
//#define BEAST_FORCE_DEBUG 0
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
/** Config: BEAST_LOG_ASSERTIONS
|
||||
|
||||
If this flag is enabled, the the bassert and jassertfalse macros will always use Logger::writeToLog()
|
||||
to write a message when an assertion happens.
|
||||
|
||||
Enabling it will also leave this turned on in release builds. When it's disabled,
|
||||
however, the bassert and jassertfalse macros will not be compiled in a
|
||||
release build.
|
||||
|
||||
@see bassert, jassertfalse, Logger
|
||||
*/
|
||||
#ifndef BEAST_LOG_ASSERTIONS
|
||||
#if BEAST_ANDROID
|
||||
#define BEAST_LOG_ASSERTIONS 1
|
||||
#else
|
||||
#define BEAST_LOG_ASSERTIONS 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
/** Config: BEAST_CHECK_MEMORY_LEAKS
|
||||
|
||||
Enables a memory-leak check for certain objects when the app terminates. See the LeakedObjectDetector
|
||||
class and the BEAST_LEAK_DETECTOR macro for more details about enabling leak checking for specific classes.
|
||||
*/
|
||||
#if BEAST_DEBUG && ! defined (BEAST_CHECK_MEMORY_LEAKS)
|
||||
#define BEAST_CHECK_MEMORY_LEAKS 1
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
/** Config: BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||
|
||||
In a Visual C++ build, this can be used to stop the required system libs being
|
||||
automatically added to the link stage.
|
||||
*/
|
||||
#ifndef BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||
#define BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES 0
|
||||
#endif
|
||||
|
||||
/* Config: BEAST_INCLUDE_ZLIB_CODE
|
||||
This can be used to disable Beast's embedded 3rd-party zlib code.
|
||||
You might need to tweak this if you're linking to an external zlib library in your app,
|
||||
but for normal apps, this option should be left alone.
|
||||
|
||||
If you disable this, you might also want to set a value for BEAST_ZLIB_INCLUDE_PATH, to
|
||||
specify the path where your zlib headers live.
|
||||
*/
|
||||
#ifndef BEAST_INCLUDE_ZLIB_CODE
|
||||
#define BEAST_INCLUDE_ZLIB_CODE 1
|
||||
#endif
|
||||
|
||||
#ifndef BEAST_ZLIB_INCLUDE_PATH
|
||||
#define BEAST_ZLIB_INCLUDE_PATH <zlib.h>
|
||||
#endif
|
||||
|
||||
/* Config: BEAST_CATCH_UNHANDLED_EXCEPTIONS
|
||||
If enabled, this will add some exception-catching code to forward unhandled exceptions
|
||||
to your BEASTApplication::unhandledException() callback.
|
||||
*/
|
||||
#ifndef BEAST_CATCH_UNHANDLED_EXCEPTIONS
|
||||
//#define BEAST_CATCH_UNHANDLED_EXCEPTIONS 1
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
#if BEAST_MSVC
|
||||
#pragma warning (disable: 4251) // (DLL build warning, must be disabled before pushing the warning state)
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4786) // (long class name warning)
|
||||
#ifdef __INTEL_COMPILER
|
||||
#pragma warning (disable: 1125)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "system/beast_StandardHeader.h"
|
||||
|
||||
namespace beast
|
||||
{
|
||||
|
||||
#include "memory/beast_ScopedPointer.h"
|
||||
// START_AUTOINCLUDE containers, files, json, logging, maths, memory, misc, network,
|
||||
// streams, system, text, threads, time, unit_tests, xml, zip
|
||||
#ifndef BEAST_ABSTRACTFIFO_BEASTHEADER
|
||||
#include "containers/beast_AbstractFifo.h"
|
||||
#endif
|
||||
#ifndef BEAST_ARRAY_BEASTHEADER
|
||||
#include "containers/beast_Array.h"
|
||||
#endif
|
||||
#ifndef BEAST_ARRAYALLOCATIONBASE_BEASTHEADER
|
||||
#include "containers/beast_ArrayAllocationBase.h"
|
||||
#endif
|
||||
#ifndef BEAST_DYNAMICOBJECT_BEASTHEADER
|
||||
#include "containers/beast_DynamicObject.h"
|
||||
#endif
|
||||
#ifndef BEAST_ELEMENTCOMPARATOR_BEASTHEADER
|
||||
#include "containers/beast_ElementComparator.h"
|
||||
#endif
|
||||
#ifndef BEAST_HASHMAP_BEASTHEADER
|
||||
#include "containers/beast_HashMap.h"
|
||||
#endif
|
||||
#ifndef BEAST_LINKEDLISTPOINTER_BEASTHEADER
|
||||
#include "containers/beast_LinkedListPointer.h"
|
||||
#endif
|
||||
#ifndef BEAST_NAMEDVALUESET_BEASTHEADER
|
||||
#include "containers/beast_NamedValueSet.h"
|
||||
#endif
|
||||
#ifndef BEAST_OWNEDARRAY_BEASTHEADER
|
||||
#include "containers/beast_OwnedArray.h"
|
||||
#endif
|
||||
#ifndef BEAST_PROPERTYSET_BEASTHEADER
|
||||
#include "containers/beast_PropertySet.h"
|
||||
#endif
|
||||
#ifndef BEAST_REFERENCECOUNTEDARRAY_BEASTHEADER
|
||||
#include "containers/beast_ReferenceCountedArray.h"
|
||||
#endif
|
||||
#ifndef BEAST_SCOPEDVALUESETTER_BEASTHEADER
|
||||
#include "containers/beast_ScopedValueSetter.h"
|
||||
#endif
|
||||
#ifndef BEAST_SORTEDSET_BEASTHEADER
|
||||
#include "containers/beast_SortedSet.h"
|
||||
#endif
|
||||
#ifndef BEAST_SPARSESET_BEASTHEADER
|
||||
#include "containers/beast_SparseSet.h"
|
||||
#endif
|
||||
#ifndef BEAST_VARIANT_BEASTHEADER
|
||||
#include "containers/beast_Variant.h"
|
||||
#endif
|
||||
#ifndef BEAST_DIRECTORYITERATOR_BEASTHEADER
|
||||
#include "files/beast_DirectoryIterator.h"
|
||||
#endif
|
||||
#ifndef BEAST_FILE_BEASTHEADER
|
||||
#include "files/beast_File.h"
|
||||
#endif
|
||||
#ifndef BEAST_FILEINPUTSTREAM_BEASTHEADER
|
||||
#include "files/beast_FileInputStream.h"
|
||||
#endif
|
||||
#ifndef BEAST_FILEOUTPUTSTREAM_BEASTHEADER
|
||||
#include "files/beast_FileOutputStream.h"
|
||||
#endif
|
||||
#ifndef BEAST_FILESEARCHPATH_BEASTHEADER
|
||||
#include "files/beast_FileSearchPath.h"
|
||||
#endif
|
||||
#ifndef BEAST_MEMORYMAPPEDFILE_BEASTHEADER
|
||||
#include "files/beast_MemoryMappedFile.h"
|
||||
#endif
|
||||
#ifndef BEAST_TEMPORARYFILE_BEASTHEADER
|
||||
#include "files/beast_TemporaryFile.h"
|
||||
#endif
|
||||
#ifndef BEAST_JSON_BEASTHEADER
|
||||
#include "json/beast_JSON.h"
|
||||
#endif
|
||||
#ifndef BEAST_FILELOGGER_BEASTHEADER
|
||||
#include "logging/beast_FileLogger.h"
|
||||
#endif
|
||||
#ifndef BEAST_LOGGER_BEASTHEADER
|
||||
#include "logging/beast_Logger.h"
|
||||
#endif
|
||||
#ifndef BEAST_BIGINTEGER_BEASTHEADER
|
||||
#include "maths/beast_BigInteger.h"
|
||||
#endif
|
||||
#ifndef BEAST_EXPRESSION_BEASTHEADER
|
||||
#include "maths/beast_Expression.h"
|
||||
#endif
|
||||
#ifndef BEAST_MATHSFUNCTIONS_BEASTHEADER
|
||||
#include "maths/beast_MathsFunctions.h"
|
||||
#endif
|
||||
#ifndef BEAST_RANDOM_BEASTHEADER
|
||||
#include "maths/beast_Random.h"
|
||||
#endif
|
||||
#ifndef BEAST_RANGE_BEASTHEADER
|
||||
#include "maths/beast_Range.h"
|
||||
#endif
|
||||
#ifndef BEAST_ATOMIC_BEASTHEADER
|
||||
#include "memory/beast_Atomic.h"
|
||||
#endif
|
||||
#ifndef BEAST_BYTEORDER_BEASTHEADER
|
||||
#include "memory/beast_ByteOrder.h"
|
||||
#endif
|
||||
#ifndef BEAST_HEAPBLOCK_BEASTHEADER
|
||||
#include "memory/beast_HeapBlock.h"
|
||||
#endif
|
||||
#ifndef BEAST_LEAKEDOBJECTDETECTOR_BEASTHEADER
|
||||
#include "memory/beast_LeakedObjectDetector.h"
|
||||
#endif
|
||||
#ifndef BEAST_MEMORY_BEASTHEADER
|
||||
#include "memory/beast_Memory.h"
|
||||
#endif
|
||||
#ifndef BEAST_MEMORYBLOCK_BEASTHEADER
|
||||
#include "memory/beast_MemoryBlock.h"
|
||||
#endif
|
||||
#ifndef BEAST_OPTIONALSCOPEDPOINTER_BEASTHEADER
|
||||
#include "memory/beast_OptionalScopedPointer.h"
|
||||
#endif
|
||||
#ifndef BEAST_REFERENCECOUNTEDOBJECT_BEASTHEADER
|
||||
#include "memory/beast_ReferenceCountedObject.h"
|
||||
#endif
|
||||
#ifndef BEAST_SCOPEDPOINTER_BEASTHEADER
|
||||
#include "memory/beast_ScopedPointer.h"
|
||||
#endif
|
||||
#ifndef BEAST_SINGLETON_BEASTHEADER
|
||||
#include "memory/beast_Singleton.h"
|
||||
#endif
|
||||
#ifndef BEAST_WEAKREFERENCE_BEASTHEADER
|
||||
#include "memory/beast_WeakReference.h"
|
||||
#endif
|
||||
#ifndef BEAST_RESULT_BEASTHEADER
|
||||
#include "misc/beast_Result.h"
|
||||
#endif
|
||||
#ifndef BEAST_UUID_BEASTHEADER
|
||||
#include "misc/beast_Uuid.h"
|
||||
#endif
|
||||
#ifndef BEAST_WINDOWSREGISTRY_BEASTHEADER
|
||||
#include "misc/beast_WindowsRegistry.h"
|
||||
#endif
|
||||
#ifndef BEAST_IPADDRESS_BEASTHEADER
|
||||
#include "network/beast_IPAddress.h"
|
||||
#endif
|
||||
#ifndef BEAST_MACADDRESS_BEASTHEADER
|
||||
#include "network/beast_MACAddress.h"
|
||||
#endif
|
||||
#ifndef BEAST_NAMEDPIPE_BEASTHEADER
|
||||
#include "network/beast_NamedPipe.h"
|
||||
#endif
|
||||
#ifndef BEAST_SOCKET_BEASTHEADER
|
||||
#include "network/beast_Socket.h"
|
||||
#endif
|
||||
#ifndef BEAST_URL_BEASTHEADER
|
||||
#include "network/beast_URL.h"
|
||||
#endif
|
||||
#ifndef BEAST_BUFFEREDINPUTSTREAM_BEASTHEADER
|
||||
#include "streams/beast_BufferedInputStream.h"
|
||||
#endif
|
||||
#ifndef BEAST_FILEINPUTSOURCE_BEASTHEADER
|
||||
#include "streams/beast_FileInputSource.h"
|
||||
#endif
|
||||
#ifndef BEAST_INPUTSOURCE_BEASTHEADER
|
||||
#include "streams/beast_InputSource.h"
|
||||
#endif
|
||||
#ifndef BEAST_INPUTSTREAM_BEASTHEADER
|
||||
#include "streams/beast_InputStream.h"
|
||||
#endif
|
||||
#ifndef BEAST_MEMORYINPUTSTREAM_BEASTHEADER
|
||||
#include "streams/beast_MemoryInputStream.h"
|
||||
#endif
|
||||
#ifndef BEAST_MEMORYOUTPUTSTREAM_BEASTHEADER
|
||||
#include "streams/beast_MemoryOutputStream.h"
|
||||
#endif
|
||||
#ifndef BEAST_OUTPUTSTREAM_BEASTHEADER
|
||||
#include "streams/beast_OutputStream.h"
|
||||
#endif
|
||||
#ifndef BEAST_SUBREGIONSTREAM_BEASTHEADER
|
||||
#include "streams/beast_SubregionStream.h"
|
||||
#endif
|
||||
#ifndef BEAST_PLATFORMDEFS_BEASTHEADER
|
||||
#include "system/beast_PlatformDefs.h"
|
||||
#endif
|
||||
#ifndef BEAST_STANDARDHEADER_BEASTHEADER
|
||||
#include "system/beast_StandardHeader.h"
|
||||
#endif
|
||||
#ifndef BEAST_SYSTEMSTATS_BEASTHEADER
|
||||
#include "system/beast_SystemStats.h"
|
||||
#endif
|
||||
#ifndef BEAST_TARGETPLATFORM_BEASTHEADER
|
||||
#include "system/beast_TargetPlatform.h"
|
||||
#endif
|
||||
#ifndef BEAST_CHARACTERFUNCTIONS_BEASTHEADER
|
||||
#include "text/beast_CharacterFunctions.h"
|
||||
#endif
|
||||
#ifndef BEAST_CHARPOINTER_ASCII_BEASTHEADER
|
||||
#include "text/beast_CharPointer_ASCII.h"
|
||||
#endif
|
||||
#ifndef BEAST_CHARPOINTER_UTF16_BEASTHEADER
|
||||
#include "text/beast_CharPointer_UTF16.h"
|
||||
#endif
|
||||
#ifndef BEAST_CHARPOINTER_UTF32_BEASTHEADER
|
||||
#include "text/beast_CharPointer_UTF32.h"
|
||||
#endif
|
||||
#ifndef BEAST_CHARPOINTER_UTF8_BEASTHEADER
|
||||
#include "text/beast_CharPointer_UTF8.h"
|
||||
#endif
|
||||
#ifndef BEAST_IDENTIFIER_BEASTHEADER
|
||||
#include "text/beast_Identifier.h"
|
||||
#endif
|
||||
#ifndef BEAST_LOCALISEDSTRINGS_BEASTHEADER
|
||||
#include "text/beast_LocalisedStrings.h"
|
||||
#endif
|
||||
#ifndef BEAST_NEWLINE_BEASTHEADER
|
||||
#include "text/beast_NewLine.h"
|
||||
#endif
|
||||
#ifndef BEAST_STRING_BEASTHEADER
|
||||
#include "text/beast_String.h"
|
||||
#endif
|
||||
#ifndef BEAST_STRINGARRAY_BEASTHEADER
|
||||
#include "text/beast_StringArray.h"
|
||||
#endif
|
||||
#ifndef BEAST_STRINGPAIRARRAY_BEASTHEADER
|
||||
#include "text/beast_StringPairArray.h"
|
||||
#endif
|
||||
#ifndef BEAST_STRINGPOOL_BEASTHEADER
|
||||
#include "text/beast_StringPool.h"
|
||||
#endif
|
||||
#ifndef BEAST_TEXTDIFF_BEASTHEADER
|
||||
#include "text/beast_TextDiff.h"
|
||||
#endif
|
||||
#ifndef BEAST_CHILDPROCESS_BEASTHEADER
|
||||
#include "threads/beast_ChildProcess.h"
|
||||
#endif
|
||||
#ifndef BEAST_CRITICALSECTION_BEASTHEADER
|
||||
#include "threads/beast_CriticalSection.h"
|
||||
#endif
|
||||
#ifndef BEAST_DYNAMICLIBRARY_BEASTHEADER
|
||||
#include "threads/beast_DynamicLibrary.h"
|
||||
#endif
|
||||
#ifndef BEAST_HIGHRESOLUTIONTIMER_BEASTHEADER
|
||||
#include "threads/beast_HighResolutionTimer.h"
|
||||
#endif
|
||||
#ifndef BEAST_INTERPROCESSLOCK_BEASTHEADER
|
||||
#include "threads/beast_InterProcessLock.h"
|
||||
#endif
|
||||
#ifndef BEAST_PROCESS_BEASTHEADER
|
||||
#include "threads/beast_Process.h"
|
||||
#endif
|
||||
#ifndef BEAST_READWRITELOCK_BEASTHEADER
|
||||
#include "threads/beast_ReadWriteLock.h"
|
||||
#endif
|
||||
#ifndef BEAST_SCOPEDLOCK_BEASTHEADER
|
||||
#include "threads/beast_ScopedLock.h"
|
||||
#endif
|
||||
#ifndef BEAST_SCOPEDREADLOCK_BEASTHEADER
|
||||
#include "threads/beast_ScopedReadLock.h"
|
||||
#endif
|
||||
#ifndef BEAST_SCOPEDWRITELOCK_BEASTHEADER
|
||||
#include "threads/beast_ScopedWriteLock.h"
|
||||
#endif
|
||||
#ifndef BEAST_SPINLOCK_BEASTHEADER
|
||||
#include "threads/beast_SpinLock.h"
|
||||
#endif
|
||||
#ifndef BEAST_THREAD_BEASTHEADER
|
||||
#include "threads/beast_Thread.h"
|
||||
#endif
|
||||
#ifndef BEAST_THREADLOCALVALUE_BEASTHEADER
|
||||
#include "threads/beast_ThreadLocalValue.h"
|
||||
#endif
|
||||
#ifndef BEAST_THREADPOOL_BEASTHEADER
|
||||
#include "threads/beast_ThreadPool.h"
|
||||
#endif
|
||||
#ifndef BEAST_TIMESLICETHREAD_BEASTHEADER
|
||||
#include "threads/beast_TimeSliceThread.h"
|
||||
#endif
|
||||
#ifndef BEAST_WAITABLEEVENT_BEASTHEADER
|
||||
#include "threads/beast_WaitableEvent.h"
|
||||
#endif
|
||||
#ifndef BEAST_PERFORMANCECOUNTER_BEASTHEADER
|
||||
#include "time/beast_PerformanceCounter.h"
|
||||
#endif
|
||||
#ifndef BEAST_RELATIVETIME_BEASTHEADER
|
||||
#include "time/beast_RelativeTime.h"
|
||||
#endif
|
||||
#ifndef BEAST_TIME_BEASTHEADER
|
||||
#include "time/beast_Time.h"
|
||||
#endif
|
||||
#ifndef BEAST_UNITTEST_BEASTHEADER
|
||||
#include "unit_tests/beast_UnitTest.h"
|
||||
#endif
|
||||
#ifndef BEAST_XMLDOCUMENT_BEASTHEADER
|
||||
#include "xml/beast_XmlDocument.h"
|
||||
#endif
|
||||
#ifndef BEAST_XMLELEMENT_BEASTHEADER
|
||||
#include "xml/beast_XmlElement.h"
|
||||
#endif
|
||||
#ifndef BEAST_GZIPCOMPRESSOROUTPUTSTREAM_BEASTHEADER
|
||||
#include "zip/beast_GZIPCompressorOutputStream.h"
|
||||
#endif
|
||||
#ifndef BEAST_GZIPDECOMPRESSORINPUTSTREAM_BEASTHEADER
|
||||
#include "zip/beast_GZIPDecompressorInputStream.h"
|
||||
#endif
|
||||
#ifndef BEAST_ZIPFILE_BEASTHEADER
|
||||
#include "zip/beast_ZipFile.h"
|
||||
#endif
|
||||
// END_AUTOINCLUDE
|
||||
|
||||
}
|
||||
|
||||
#if BEAST_MSVC
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif // BEAST_CORE_BEASTHEADER
|
||||
|
||||
@@ -1 +1,24 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include "beast_core.cpp"
|
||||
|
||||
229
modules/beast_core/containers/beast_AbstractFifo.cpp
Normal file
229
modules/beast_core/containers/beast_AbstractFifo.cpp
Normal file
@@ -0,0 +1,229 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
AbstractFifo::AbstractFifo (const int capacity) noexcept
|
||||
: bufferSize (capacity)
|
||||
{
|
||||
bassert (bufferSize > 0);
|
||||
}
|
||||
|
||||
AbstractFifo::~AbstractFifo() {}
|
||||
|
||||
int AbstractFifo::getTotalSize() const noexcept { return bufferSize; }
|
||||
int AbstractFifo::getFreeSpace() const noexcept { return bufferSize - getNumReady(); }
|
||||
|
||||
int AbstractFifo::getNumReady() const noexcept
|
||||
{
|
||||
const int vs = validStart.get();
|
||||
const int ve = validEnd.get();
|
||||
return ve >= vs ? (ve - vs) : (bufferSize - (vs - ve));
|
||||
}
|
||||
|
||||
void AbstractFifo::reset() noexcept
|
||||
{
|
||||
validEnd = 0;
|
||||
validStart = 0;
|
||||
}
|
||||
|
||||
void AbstractFifo::setTotalSize (int newSize) noexcept
|
||||
{
|
||||
bassert (newSize > 0);
|
||||
reset();
|
||||
bufferSize = newSize;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void AbstractFifo::prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept
|
||||
{
|
||||
const int vs = validStart.get();
|
||||
const int ve = validEnd.value;
|
||||
|
||||
const int freeSpace = ve >= vs ? (bufferSize - (ve - vs)) : (vs - ve);
|
||||
numToWrite = bmin (numToWrite, freeSpace - 1);
|
||||
|
||||
if (numToWrite <= 0)
|
||||
{
|
||||
startIndex1 = 0;
|
||||
startIndex2 = 0;
|
||||
blockSize1 = 0;
|
||||
blockSize2 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
startIndex1 = ve;
|
||||
startIndex2 = 0;
|
||||
blockSize1 = bmin (bufferSize - ve, numToWrite);
|
||||
numToWrite -= blockSize1;
|
||||
blockSize2 = numToWrite <= 0 ? 0 : bmin (numToWrite, vs);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractFifo::finishedWrite (int numWritten) noexcept
|
||||
{
|
||||
bassert (numWritten >= 0 && numWritten < bufferSize);
|
||||
int newEnd = validEnd.value + numWritten;
|
||||
if (newEnd >= bufferSize)
|
||||
newEnd -= bufferSize;
|
||||
|
||||
validEnd = newEnd;
|
||||
}
|
||||
|
||||
void AbstractFifo::prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept
|
||||
{
|
||||
const int vs = validStart.value;
|
||||
const int ve = validEnd.get();
|
||||
|
||||
const int numReady = ve >= vs ? (ve - vs) : (bufferSize - (vs - ve));
|
||||
numWanted = bmin (numWanted, numReady);
|
||||
|
||||
if (numWanted <= 0)
|
||||
{
|
||||
startIndex1 = 0;
|
||||
startIndex2 = 0;
|
||||
blockSize1 = 0;
|
||||
blockSize2 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
startIndex1 = vs;
|
||||
startIndex2 = 0;
|
||||
blockSize1 = bmin (bufferSize - vs, numWanted);
|
||||
numWanted -= blockSize1;
|
||||
blockSize2 = numWanted <= 0 ? 0 : bmin (numWanted, ve);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractFifo::finishedRead (int numRead) noexcept
|
||||
{
|
||||
bassert (numRead >= 0 && numRead <= bufferSize);
|
||||
|
||||
int newStart = validStart.value + numRead;
|
||||
if (newStart >= bufferSize)
|
||||
newStart -= bufferSize;
|
||||
|
||||
validStart = newStart;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
//==============================================================================
|
||||
#if BEAST_UNIT_TESTS
|
||||
|
||||
class AbstractFifoTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
AbstractFifoTests() : UnitTest ("Abstract Fifo") {}
|
||||
|
||||
class WriteThread : public Thread
|
||||
{
|
||||
public:
|
||||
WriteThread (AbstractFifo& fifo_, int* buffer_)
|
||||
: Thread ("fifo writer"), fifo (fifo_), buffer (buffer_)
|
||||
{
|
||||
startThread();
|
||||
}
|
||||
|
||||
~WriteThread()
|
||||
{
|
||||
stopThread (5000);
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
int n = 0;
|
||||
Random r;
|
||||
|
||||
while (! threadShouldExit())
|
||||
{
|
||||
int num = r.nextInt (2000) + 1;
|
||||
|
||||
int start1, size1, start2, size2;
|
||||
fifo.prepareToWrite (num, start1, size1, start2, size2);
|
||||
|
||||
bassert (size1 >= 0 && size2 >= 0);
|
||||
bassert (size1 == 0 || (start1 >= 0 && start1 < fifo.getTotalSize()));
|
||||
bassert (size2 == 0 || (start2 >= 0 && start2 < fifo.getTotalSize()));
|
||||
|
||||
for (int i = 0; i < size1; ++i)
|
||||
buffer [start1 + i] = n++;
|
||||
|
||||
for (int i = 0; i < size2; ++i)
|
||||
buffer [start2 + i] = n++;
|
||||
|
||||
fifo.finishedWrite (size1 + size2);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
AbstractFifo& fifo;
|
||||
int* buffer;
|
||||
};
|
||||
|
||||
void runTest()
|
||||
{
|
||||
beginTest ("AbstractFifo");
|
||||
|
||||
int buffer [5000];
|
||||
AbstractFifo fifo (numElementsInArray (buffer));
|
||||
|
||||
WriteThread writer (fifo, buffer);
|
||||
|
||||
int n = 0;
|
||||
Random r;
|
||||
|
||||
for (int count = 100000; --count >= 0;)
|
||||
{
|
||||
int num = r.nextInt (6000) + 1;
|
||||
|
||||
int start1, size1, start2, size2;
|
||||
fifo.prepareToRead (num, start1, size1, start2, size2);
|
||||
|
||||
if (! (size1 >= 0 && size2 >= 0)
|
||||
&& (size1 == 0 || (start1 >= 0 && start1 < fifo.getTotalSize()))
|
||||
&& (size2 == 0 || (start2 >= 0 && start2 < fifo.getTotalSize())))
|
||||
{
|
||||
expect (false, "prepareToRead returned -ve values");
|
||||
break;
|
||||
}
|
||||
|
||||
bool failed = false;
|
||||
|
||||
for (int i = 0; i < size1; ++i)
|
||||
failed = (buffer [start1 + i] != n++) || failed;
|
||||
|
||||
for (int i = 0; i < size2; ++i)
|
||||
failed = (buffer [start2 + i] != n++) || failed;
|
||||
|
||||
if (failed)
|
||||
{
|
||||
expect (false, "read values were incorrect");
|
||||
break;
|
||||
}
|
||||
|
||||
fifo.finishedRead (size1 + size2);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static AbstractFifoTests fifoUnitTests;
|
||||
|
||||
#endif
|
||||
217
modules/beast_core/containers/beast_AbstractFifo.h
Normal file
217
modules/beast_core/containers/beast_AbstractFifo.h
Normal file
@@ -0,0 +1,217 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_ABSTRACTFIFO_BEASTHEADER
|
||||
#define BEAST_ABSTRACTFIFO_BEASTHEADER
|
||||
|
||||
#include "../memory/beast_Atomic.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Encapsulates the logic required to implement a lock-free FIFO.
|
||||
|
||||
This class handles the logic needed when building a single-reader, single-writer FIFO.
|
||||
|
||||
It doesn't actually hold any data itself, but your FIFO class can use one of these to manage
|
||||
its position and status when reading or writing to it.
|
||||
|
||||
To use it, you can call prepareToWrite() to determine the position within your own buffer that
|
||||
an incoming block of data should be stored, and prepareToRead() to find out when the next
|
||||
outgoing block should be read from.
|
||||
|
||||
e.g.
|
||||
@code
|
||||
class MyFifo
|
||||
{
|
||||
public:
|
||||
MyFifo() : abstractFifo (1024)
|
||||
{
|
||||
}
|
||||
|
||||
void addToFifo (const int* someData, int numItems)
|
||||
{
|
||||
int start1, size1, start2, size2;
|
||||
abstractFifo.prepareToWrite (numItems, start1, size1, start2, size2);
|
||||
|
||||
if (size1 > 0)
|
||||
copySomeData (myBuffer + start1, someData, size1);
|
||||
|
||||
if (size2 > 0)
|
||||
copySomeData (myBuffer + start2, someData + size1, size2);
|
||||
|
||||
abstractFifo.finishedWrite (size1 + size2);
|
||||
}
|
||||
|
||||
void readFromFifo (int* someData, int numItems)
|
||||
{
|
||||
int start1, size1, start2, size2;
|
||||
abstractFifo.prepareToRead (numSamples, start1, size1, start2, size2);
|
||||
|
||||
if (size1 > 0)
|
||||
copySomeData (someData, myBuffer + start1, size1);
|
||||
|
||||
if (size2 > 0)
|
||||
copySomeData (someData + size1, myBuffer + start2, size2);
|
||||
|
||||
abstractFifo.finishedRead (size1 + size2);
|
||||
}
|
||||
|
||||
private:
|
||||
AbstractFifo abstractFifo;
|
||||
int myBuffer [1024];
|
||||
};
|
||||
@endcode
|
||||
*/
|
||||
class BEAST_API AbstractFifo
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a FIFO to manage a buffer with the specified capacity. */
|
||||
AbstractFifo (int capacity) noexcept;
|
||||
|
||||
/** Destructor */
|
||||
~AbstractFifo();
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the total size of the buffer being managed. */
|
||||
int getTotalSize() const noexcept;
|
||||
|
||||
/** Returns the number of items that can currently be added to the buffer without it overflowing. */
|
||||
int getFreeSpace() const noexcept;
|
||||
|
||||
/** Returns the number of items that can currently be read from the buffer. */
|
||||
int getNumReady() const noexcept;
|
||||
|
||||
/** Clears the buffer positions, so that it appears empty. */
|
||||
void reset() noexcept;
|
||||
|
||||
/** Changes the buffer's total size.
|
||||
Note that this isn't thread-safe, so don't call it if there's any danger that it
|
||||
might overlap with a call to any other method in this class!
|
||||
*/
|
||||
void setTotalSize (int newSize) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the location within the buffer at which an incoming block of data should be written.
|
||||
|
||||
Because the section of data that you want to add to the buffer may overlap the end
|
||||
and wrap around to the start, two blocks within your buffer are returned, and you
|
||||
should copy your data into the first one, with any remaining data spilling over into
|
||||
the second.
|
||||
|
||||
If the number of items you ask for is too large to fit within the buffer's free space, then
|
||||
blockSize1 + blockSize2 may add up to a lower value than numToWrite. If this happens, you
|
||||
may decide to keep waiting and re-trying the method until there's enough space available.
|
||||
|
||||
After calling this method, if you choose to write your data into the blocks returned, you
|
||||
must call finishedWrite() to tell the FIFO how much data you actually added.
|
||||
|
||||
e.g.
|
||||
@code
|
||||
void addToFifo (const int* someData, int numItems)
|
||||
{
|
||||
int start1, size1, start2, size2;
|
||||
prepareToWrite (numItems, start1, size1, start2, size2);
|
||||
|
||||
if (size1 > 0)
|
||||
copySomeData (myBuffer + start1, someData, size1);
|
||||
|
||||
if (size2 > 0)
|
||||
copySomeData (myBuffer + start2, someData + size1, size2);
|
||||
|
||||
finishedWrite (size1 + size2);
|
||||
}
|
||||
@endcode
|
||||
|
||||
@param numToWrite indicates how many items you'd like to add to the buffer
|
||||
@param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written
|
||||
@param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1
|
||||
@param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into
|
||||
the first block should be written
|
||||
@param blockSize2 on exit, this indicates how many items can be written to the block starting at startIndex2
|
||||
@see finishedWrite
|
||||
*/
|
||||
void prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept;
|
||||
|
||||
/** Called after writing from the FIFO, to indicate that this many items have been added.
|
||||
@see prepareToWrite
|
||||
*/
|
||||
void finishedWrite (int numWritten) noexcept;
|
||||
|
||||
/** Returns the location within the buffer from which the next block of data should be read.
|
||||
|
||||
Because the section of data that you want to read from the buffer may overlap the end
|
||||
and wrap around to the start, two blocks within your buffer are returned, and you
|
||||
should read from both of them.
|
||||
|
||||
If the number of items you ask for is greater than the amount of data available, then
|
||||
blockSize1 + blockSize2 may add up to a lower value than numWanted. If this happens, you
|
||||
may decide to keep waiting and re-trying the method until there's enough data available.
|
||||
|
||||
After calling this method, if you choose to read the data, you must call finishedRead() to
|
||||
tell the FIFO how much data you have consumed.
|
||||
|
||||
e.g.
|
||||
@code
|
||||
void readFromFifo (int* someData, int numItems)
|
||||
{
|
||||
int start1, size1, start2, size2;
|
||||
prepareToRead (numSamples, start1, size1, start2, size2);
|
||||
|
||||
if (size1 > 0)
|
||||
copySomeData (someData, myBuffer + start1, size1);
|
||||
|
||||
if (size2 > 0)
|
||||
copySomeData (someData + size1, myBuffer + start2, size2);
|
||||
|
||||
finishedRead (size1 + size2);
|
||||
}
|
||||
@endcode
|
||||
|
||||
@param numWanted indicates how many items you'd like to add to the buffer
|
||||
@param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written
|
||||
@param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1
|
||||
@param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into
|
||||
the first block should be written
|
||||
@param blockSize2 on exit, this indicates how many items can be written to the block starting at startIndex2
|
||||
@see finishedRead
|
||||
*/
|
||||
void prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept;
|
||||
|
||||
/** Called after reading from the FIFO, to indicate that this many items have now been consumed.
|
||||
@see prepareToRead
|
||||
*/
|
||||
void finishedRead (int numRead) noexcept;
|
||||
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
int bufferSize;
|
||||
Atomic <int> validStart, validEnd;
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AbstractFifo)
|
||||
};
|
||||
|
||||
|
||||
#endif // BEAST_ABSTRACTFIFO_BEASTHEADER
|
||||
1047
modules/beast_core/containers/beast_Array.h
Normal file
1047
modules/beast_core/containers/beast_Array.h
Normal file
File diff suppressed because it is too large
Load Diff
133
modules/beast_core/containers/beast_ArrayAllocationBase.h
Normal file
133
modules/beast_core/containers/beast_ArrayAllocationBase.h
Normal file
@@ -0,0 +1,133 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_ARRAYALLOCATIONBASE_BEASTHEADER
|
||||
#define BEAST_ARRAYALLOCATIONBASE_BEASTHEADER
|
||||
|
||||
#include "../memory/beast_HeapBlock.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Implements some basic array storage allocation functions.
|
||||
|
||||
This class isn't really for public use - it's used by the other
|
||||
array classes, but might come in handy for some purposes.
|
||||
|
||||
It inherits from a critical section class to allow the arrays to use
|
||||
the "empty base class optimisation" pattern to reduce their footprint.
|
||||
|
||||
@see Array, OwnedArray, ReferenceCountedArray
|
||||
*/
|
||||
template <class ElementType, class TypeOfCriticalSectionToUse>
|
||||
class ArrayAllocationBase : public TypeOfCriticalSectionToUse
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an empty array. */
|
||||
ArrayAllocationBase() noexcept
|
||||
: numAllocated (0)
|
||||
{
|
||||
}
|
||||
|
||||
/** Destructor. */
|
||||
~ArrayAllocationBase() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
ArrayAllocationBase (ArrayAllocationBase<ElementType, TypeOfCriticalSectionToUse>&& other) noexcept
|
||||
: elements (static_cast <HeapBlock <ElementType>&&> (other.elements)),
|
||||
numAllocated (other.numAllocated)
|
||||
{
|
||||
}
|
||||
|
||||
ArrayAllocationBase& operator= (ArrayAllocationBase<ElementType, TypeOfCriticalSectionToUse>&& other) noexcept
|
||||
{
|
||||
elements = static_cast <HeapBlock <ElementType>&&> (other.elements);
|
||||
numAllocated = other.numAllocated;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
/** Changes the amount of storage allocated.
|
||||
|
||||
This will retain any data currently held in the array, and either add or
|
||||
remove extra space at the end.
|
||||
|
||||
@param numElements the number of elements that are needed
|
||||
*/
|
||||
void setAllocatedSize (const int numElements)
|
||||
{
|
||||
if (numAllocated != numElements)
|
||||
{
|
||||
if (numElements > 0)
|
||||
elements.realloc ((size_t) numElements);
|
||||
else
|
||||
elements.free();
|
||||
|
||||
numAllocated = numElements;
|
||||
}
|
||||
}
|
||||
|
||||
/** Increases the amount of storage allocated if it is less than a given amount.
|
||||
|
||||
This will retain any data currently held in the array, but will add
|
||||
extra space at the end to make sure there it's at least as big as the size
|
||||
passed in. If it's already bigger, no action is taken.
|
||||
|
||||
@param minNumElements the minimum number of elements that are needed
|
||||
*/
|
||||
void ensureAllocatedSize (const int minNumElements)
|
||||
{
|
||||
if (minNumElements > numAllocated)
|
||||
setAllocatedSize ((minNumElements + minNumElements / 2 + 8) & ~7);
|
||||
}
|
||||
|
||||
/** Minimises the amount of storage allocated so that it's no more than
|
||||
the given number of elements.
|
||||
*/
|
||||
void shrinkToNoMoreThan (const int maxNumElements)
|
||||
{
|
||||
if (maxNumElements < numAllocated)
|
||||
setAllocatedSize (maxNumElements);
|
||||
}
|
||||
|
||||
/** Swap the contents of two objects. */
|
||||
void swapWith (ArrayAllocationBase <ElementType, TypeOfCriticalSectionToUse>& other) noexcept
|
||||
{
|
||||
elements.swapWith (other.elements);
|
||||
std::swap (numAllocated, other.numAllocated);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
HeapBlock <ElementType> elements;
|
||||
int numAllocated;
|
||||
|
||||
private:
|
||||
BEAST_DECLARE_NON_COPYABLE (ArrayAllocationBase)
|
||||
};
|
||||
|
||||
|
||||
#endif // BEAST_ARRAYALLOCATIONBASE_BEASTHEADER
|
||||
74
modules/beast_core/containers/beast_DynamicObject.cpp
Normal file
74
modules/beast_core/containers/beast_DynamicObject.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
DynamicObject::DynamicObject()
|
||||
{
|
||||
}
|
||||
|
||||
DynamicObject::~DynamicObject()
|
||||
{
|
||||
}
|
||||
|
||||
bool DynamicObject::hasProperty (const Identifier& propertyName) const
|
||||
{
|
||||
const var* const v = properties.getVarPointer (propertyName);
|
||||
return v != nullptr && ! v->isMethod();
|
||||
}
|
||||
|
||||
var DynamicObject::getProperty (const Identifier& propertyName) const
|
||||
{
|
||||
return properties [propertyName];
|
||||
}
|
||||
|
||||
void DynamicObject::setProperty (const Identifier& propertyName, const var& newValue)
|
||||
{
|
||||
properties.set (propertyName, newValue);
|
||||
}
|
||||
|
||||
void DynamicObject::removeProperty (const Identifier& propertyName)
|
||||
{
|
||||
properties.remove (propertyName);
|
||||
}
|
||||
|
||||
bool DynamicObject::hasMethod (const Identifier& methodName) const
|
||||
{
|
||||
return getProperty (methodName).isMethod();
|
||||
}
|
||||
|
||||
var DynamicObject::invokeMethod (const Identifier& methodName,
|
||||
const var* parameters,
|
||||
int numParameters)
|
||||
{
|
||||
return properties [methodName].invokeMethod (this, parameters, numParameters);
|
||||
}
|
||||
|
||||
void DynamicObject::setMethod (const Identifier& name,
|
||||
var::MethodFunction methodFunction)
|
||||
{
|
||||
properties.set (name, var (methodFunction));
|
||||
}
|
||||
|
||||
void DynamicObject::clear()
|
||||
{
|
||||
properties.clear();
|
||||
}
|
||||
121
modules/beast_core/containers/beast_DynamicObject.h
Normal file
121
modules/beast_core/containers/beast_DynamicObject.h
Normal file
@@ -0,0 +1,121 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_DYNAMICOBJECT_BEASTHEADER
|
||||
#define BEAST_DYNAMICOBJECT_BEASTHEADER
|
||||
|
||||
#include "beast_NamedValueSet.h"
|
||||
#include "../memory/beast_ReferenceCountedObject.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Represents a dynamically implemented object.
|
||||
|
||||
This class is primarily intended for wrapping scripting language objects,
|
||||
but could be used for other purposes.
|
||||
|
||||
An instance of a DynamicObject can be used to store named properties, and
|
||||
by subclassing hasMethod() and invokeMethod(), you can give your object
|
||||
methods.
|
||||
*/
|
||||
class BEAST_API DynamicObject : public ReferenceCountedObject
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
DynamicObject();
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~DynamicObject();
|
||||
|
||||
typedef ReferenceCountedObjectPtr<DynamicObject> Ptr;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if the object has a property with this name.
|
||||
Note that if the property is actually a method, this will return false.
|
||||
*/
|
||||
virtual bool hasProperty (const Identifier& propertyName) const;
|
||||
|
||||
/** Returns a named property.
|
||||
This returns a void if no such property exists.
|
||||
*/
|
||||
virtual var getProperty (const Identifier& propertyName) const;
|
||||
|
||||
/** Sets a named property. */
|
||||
virtual void setProperty (const Identifier& propertyName, const var& newValue);
|
||||
|
||||
/** Removes a named property. */
|
||||
virtual void removeProperty (const Identifier& propertyName);
|
||||
|
||||
//==============================================================================
|
||||
/** Checks whether this object has the specified method.
|
||||
|
||||
The default implementation of this just checks whether there's a property
|
||||
with this name that's actually a method, but this can be overridden for
|
||||
building objects with dynamic invocation.
|
||||
*/
|
||||
virtual bool hasMethod (const Identifier& methodName) const;
|
||||
|
||||
/** Invokes a named method on this object.
|
||||
|
||||
The default implementation looks up the named property, and if it's a method
|
||||
call, then it invokes it.
|
||||
|
||||
This method is virtual to allow more dynamic invocation to used for objects
|
||||
where the methods may not already be set as properies.
|
||||
*/
|
||||
virtual var invokeMethod (const Identifier& methodName,
|
||||
const var* parameters,
|
||||
int numParameters);
|
||||
|
||||
/** Sets up a method.
|
||||
|
||||
This is basically the same as calling setProperty (methodName, (var::MethodFunction) myFunction), but
|
||||
helps to avoid accidentally invoking the wrong type of var constructor. It also makes
|
||||
the code easier to read,
|
||||
|
||||
The compiler will probably force you to use an explicit cast your method to a (var::MethodFunction), e.g.
|
||||
@code
|
||||
setMethod ("doSomething", (var::MethodFunction) &MyClass::doSomething);
|
||||
@endcode
|
||||
*/
|
||||
void setMethod (const Identifier& methodName,
|
||||
var::MethodFunction methodFunction);
|
||||
|
||||
//==============================================================================
|
||||
/** Removes all properties and methods from the object. */
|
||||
void clear();
|
||||
|
||||
/** Returns the NamedValueSet that holds the object's properties. */
|
||||
NamedValueSet& getProperties() noexcept { return properties; }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
NamedValueSet properties;
|
||||
|
||||
BEAST_LEAK_DETECTOR (DynamicObject)
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // BEAST_DYNAMICOBJECT_BEASTHEADER
|
||||
274
modules/beast_core/containers/beast_ElementComparator.h
Normal file
274
modules/beast_core/containers/beast_ElementComparator.h
Normal file
@@ -0,0 +1,274 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_ELEMENTCOMPARATOR_BEASTHEADER
|
||||
#define BEAST_ELEMENTCOMPARATOR_BEASTHEADER
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Sorts a range of elements in an array.
|
||||
|
||||
The comparator object that is passed-in must define a public method with the following
|
||||
signature:
|
||||
@code
|
||||
int compareElements (ElementType first, ElementType second);
|
||||
@endcode
|
||||
|
||||
..and this method must return:
|
||||
- a value of < 0 if the first comes before the second
|
||||
- a value of 0 if the two objects are equivalent
|
||||
- a value of > 0 if the second comes before the first
|
||||
|
||||
To improve performance, the compareElements() method can be declared as static or const.
|
||||
|
||||
@param comparator an object which defines a compareElements() method
|
||||
@param array the array to sort
|
||||
@param firstElement the index of the first element of the range to be sorted
|
||||
@param lastElement the index of the last element in the range that needs
|
||||
sorting (this is inclusive)
|
||||
@param retainOrderOfEquivalentItems if true, the order of items that the
|
||||
comparator deems the same will be maintained - this will be
|
||||
a slower algorithm than if they are allowed to be moved around.
|
||||
|
||||
@see sortArrayRetainingOrder
|
||||
*/
|
||||
template <class ElementType, class ElementComparator>
|
||||
static void sortArray (ElementComparator& comparator,
|
||||
ElementType* const array,
|
||||
int firstElement,
|
||||
int lastElement,
|
||||
const bool retainOrderOfEquivalentItems)
|
||||
{
|
||||
(void) comparator; // if you pass in an object with a static compareElements() method, this
|
||||
// avoids getting warning messages about the parameter being unused
|
||||
|
||||
if (lastElement > firstElement)
|
||||
{
|
||||
if (retainOrderOfEquivalentItems)
|
||||
{
|
||||
for (int i = firstElement; i < lastElement; ++i)
|
||||
{
|
||||
if (comparator.compareElements (array[i], array [i + 1]) > 0)
|
||||
{
|
||||
std::swap (array[i], array[i + 1]);
|
||||
|
||||
if (i > firstElement)
|
||||
i -= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int fromStack[30], toStack[30];
|
||||
int stackIndex = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
const int size = (lastElement - firstElement) + 1;
|
||||
|
||||
if (size <= 8)
|
||||
{
|
||||
int j = lastElement;
|
||||
int maxIndex;
|
||||
|
||||
while (j > firstElement)
|
||||
{
|
||||
maxIndex = firstElement;
|
||||
for (int k = firstElement + 1; k <= j; ++k)
|
||||
if (comparator.compareElements (array[k], array [maxIndex]) > 0)
|
||||
maxIndex = k;
|
||||
|
||||
std::swap (array[j], array[maxIndex]);
|
||||
--j;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const int mid = firstElement + (size >> 1);
|
||||
std::swap (array[mid], array[firstElement]);
|
||||
|
||||
int i = firstElement;
|
||||
int j = lastElement + 1;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
while (++i <= lastElement
|
||||
&& comparator.compareElements (array[i], array [firstElement]) <= 0)
|
||||
{}
|
||||
|
||||
while (--j > firstElement
|
||||
&& comparator.compareElements (array[j], array [firstElement]) >= 0)
|
||||
{}
|
||||
|
||||
if (j < i)
|
||||
break;
|
||||
|
||||
std::swap (array[i], array[j]);
|
||||
}
|
||||
|
||||
std::swap (array[j], array[firstElement]);
|
||||
|
||||
if (j - 1 - firstElement >= lastElement - i)
|
||||
{
|
||||
if (firstElement + 1 < j)
|
||||
{
|
||||
fromStack [stackIndex] = firstElement;
|
||||
toStack [stackIndex] = j - 1;
|
||||
++stackIndex;
|
||||
}
|
||||
|
||||
if (i < lastElement)
|
||||
{
|
||||
firstElement = i;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i < lastElement)
|
||||
{
|
||||
fromStack [stackIndex] = i;
|
||||
toStack [stackIndex] = lastElement;
|
||||
++stackIndex;
|
||||
}
|
||||
|
||||
if (firstElement + 1 < j)
|
||||
{
|
||||
lastElement = j - 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (--stackIndex < 0)
|
||||
break;
|
||||
|
||||
bassert (stackIndex < numElementsInArray (fromStack));
|
||||
|
||||
firstElement = fromStack [stackIndex];
|
||||
lastElement = toStack [stackIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Searches a sorted array of elements, looking for the index at which a specified value
|
||||
should be inserted for it to be in the correct order.
|
||||
|
||||
The comparator object that is passed-in must define a public method with the following
|
||||
signature:
|
||||
@code
|
||||
int compareElements (ElementType first, ElementType second);
|
||||
@endcode
|
||||
|
||||
..and this method must return:
|
||||
- a value of < 0 if the first comes before the second
|
||||
- a value of 0 if the two objects are equivalent
|
||||
- a value of > 0 if the second comes before the first
|
||||
|
||||
To improve performance, the compareElements() method can be declared as static or const.
|
||||
|
||||
@param comparator an object which defines a compareElements() method
|
||||
@param array the array to search
|
||||
@param newElement the value that is going to be inserted
|
||||
@param firstElement the index of the first element to search
|
||||
@param lastElement the index of the last element in the range (this is non-inclusive)
|
||||
*/
|
||||
template <class ElementType, class ElementComparator>
|
||||
static int findInsertIndexInSortedArray (ElementComparator& comparator,
|
||||
ElementType* const array,
|
||||
const ElementType newElement,
|
||||
int firstElement,
|
||||
int lastElement)
|
||||
{
|
||||
bassert (firstElement <= lastElement);
|
||||
|
||||
(void) comparator; // if you pass in an object with a static compareElements() method, this
|
||||
// avoids getting warning messages about the parameter being unused
|
||||
|
||||
while (firstElement < lastElement)
|
||||
{
|
||||
if (comparator.compareElements (newElement, array [firstElement]) == 0)
|
||||
{
|
||||
++firstElement;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
const int halfway = (firstElement + lastElement) >> 1;
|
||||
|
||||
if (halfway == firstElement)
|
||||
{
|
||||
if (comparator.compareElements (newElement, array [halfway]) >= 0)
|
||||
++firstElement;
|
||||
|
||||
break;
|
||||
}
|
||||
else if (comparator.compareElements (newElement, array [halfway]) >= 0)
|
||||
{
|
||||
firstElement = halfway;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastElement = halfway;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return firstElement;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A simple ElementComparator class that can be used to sort an array of
|
||||
objects that support the '<' operator.
|
||||
|
||||
This will work for primitive types and objects that implement operator<().
|
||||
|
||||
Example: @code
|
||||
Array <int> myArray;
|
||||
DefaultElementComparator<int> sorter;
|
||||
myArray.sort (sorter);
|
||||
@endcode
|
||||
|
||||
@see ElementComparator
|
||||
*/
|
||||
template <class ElementType>
|
||||
class DefaultElementComparator
|
||||
{
|
||||
private:
|
||||
typedef PARAMETER_TYPE (ElementType) ParameterType;
|
||||
|
||||
public:
|
||||
static int compareElements (ParameterType first, ParameterType second)
|
||||
{
|
||||
return (first < second) ? -1 : ((second < first) ? 1 : 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif // BEAST_ELEMENTCOMPARATOR_BEASTHEADER
|
||||
447
modules/beast_core/containers/beast_HashMap.h
Normal file
447
modules/beast_core/containers/beast_HashMap.h
Normal file
@@ -0,0 +1,447 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_HASHMAP_BEASTHEADER
|
||||
#define BEAST_HASHMAP_BEASTHEADER
|
||||
|
||||
#include "beast_OwnedArray.h"
|
||||
#include "beast_LinkedListPointer.h"
|
||||
#include "../memory/beast_ScopedPointer.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A simple class to generate hash functions for some primitive types, intended for
|
||||
use with the HashMap class.
|
||||
@see HashMap
|
||||
*/
|
||||
class DefaultHashFunctions
|
||||
{
|
||||
public:
|
||||
/** Generates a simple hash from an integer. */
|
||||
static int generateHash (const int key, const int upperLimit) noexcept { return std::abs (key) % upperLimit; }
|
||||
/** Generates a simple hash from an int64. */
|
||||
static int generateHash (const int64 key, const int upperLimit) noexcept { return std::abs ((int) key) % upperLimit; }
|
||||
/** Generates a simple hash from a string. */
|
||||
static int generateHash (const String& key, const int upperLimit) noexcept { return (int) (((uint32) key.hashCode()) % (uint32) upperLimit); }
|
||||
/** Generates a simple hash from a variant. */
|
||||
static int generateHash (const var& key, const int upperLimit) noexcept { return generateHash (key.toString(), upperLimit); }
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Holds a set of mappings between some key/value pairs.
|
||||
|
||||
The types of the key and value objects are set as template parameters.
|
||||
You can also specify a class to supply a hash function that converts a key value
|
||||
into an hashed integer. This class must have the form:
|
||||
|
||||
@code
|
||||
struct MyHashGenerator
|
||||
{
|
||||
static int generateHash (MyKeyType key, int upperLimit)
|
||||
{
|
||||
// The function must return a value 0 <= x < upperLimit
|
||||
return someFunctionOfMyKeyType (key) % upperLimit;
|
||||
}
|
||||
};
|
||||
@endcode
|
||||
|
||||
Like the Array class, the key and value types are expected to be copy-by-value types, so
|
||||
if you define them to be pointer types, this class won't delete the objects that they
|
||||
point to.
|
||||
|
||||
If you don't supply a class for the HashFunctionToUse template parameter, the
|
||||
default one provides some simple mappings for strings and ints.
|
||||
|
||||
@code
|
||||
HashMap<int, String> hash;
|
||||
hash.set (1, "item1");
|
||||
hash.set (2, "item2");
|
||||
|
||||
DBG (hash [1]); // prints "item1"
|
||||
DBG (hash [2]); // prints "item2"
|
||||
|
||||
// This iterates the map, printing all of its key -> value pairs..
|
||||
for (HashMap<int, String>::Iterator i (hash); i.next();)
|
||||
DBG (i.getKey() << " -> " << i.getValue());
|
||||
@endcode
|
||||
|
||||
@see CriticalSection, DefaultHashFunctions, NamedValueSet, SortedSet
|
||||
*/
|
||||
template <typename KeyType,
|
||||
typename ValueType,
|
||||
class HashFunctionToUse = DefaultHashFunctions,
|
||||
class TypeOfCriticalSectionToUse = DummyCriticalSection>
|
||||
class HashMap
|
||||
{
|
||||
private:
|
||||
typedef PARAMETER_TYPE (KeyType) KeyTypeParameter;
|
||||
typedef PARAMETER_TYPE (ValueType) ValueTypeParameter;
|
||||
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an empty hash-map.
|
||||
|
||||
The numberOfSlots parameter specifies the number of hash entries the map will use. This
|
||||
will be the "upperLimit" parameter that is passed to your generateHash() function. The number
|
||||
of hash slots will grow automatically if necessary, or it can be remapped manually using remapTable().
|
||||
*/
|
||||
explicit HashMap (const int numberOfSlots = defaultHashTableSize)
|
||||
: totalNumItems (0)
|
||||
{
|
||||
slots.insertMultiple (0, nullptr, numberOfSlots);
|
||||
}
|
||||
|
||||
/** Destructor. */
|
||||
~HashMap()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Removes all values from the map.
|
||||
Note that this will clear the content, but won't affect the number of slots (see
|
||||
remapTable and getNumSlots).
|
||||
*/
|
||||
void clear()
|
||||
{
|
||||
const ScopedLockType sl (getLock());
|
||||
|
||||
for (int i = slots.size(); --i >= 0;)
|
||||
{
|
||||
HashEntry* h = slots.getUnchecked(i);
|
||||
|
||||
while (h != nullptr)
|
||||
{
|
||||
const ScopedPointer<HashEntry> deleter (h);
|
||||
h = h->nextEntry;
|
||||
}
|
||||
|
||||
slots.set (i, nullptr);
|
||||
}
|
||||
|
||||
totalNumItems = 0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the current number of items in the map. */
|
||||
inline int size() const noexcept
|
||||
{
|
||||
return totalNumItems;
|
||||
}
|
||||
|
||||
/** Returns the value corresponding to a given key.
|
||||
If the map doesn't contain the key, a default instance of the value type is returned.
|
||||
@param keyToLookFor the key of the item being requested
|
||||
*/
|
||||
inline ValueType operator[] (KeyTypeParameter keyToLookFor) const
|
||||
{
|
||||
const ScopedLockType sl (getLock());
|
||||
|
||||
for (const HashEntry* entry = slots.getUnchecked (generateHashFor (keyToLookFor)); entry != nullptr; entry = entry->nextEntry)
|
||||
if (entry->key == keyToLookFor)
|
||||
return entry->value;
|
||||
|
||||
return ValueType();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if the map contains an item with the specied key. */
|
||||
bool contains (KeyTypeParameter keyToLookFor) const
|
||||
{
|
||||
const ScopedLockType sl (getLock());
|
||||
|
||||
for (const HashEntry* entry = slots.getUnchecked (generateHashFor (keyToLookFor)); entry != nullptr; entry = entry->nextEntry)
|
||||
if (entry->key == keyToLookFor)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Returns true if the hash contains at least one occurrence of a given value. */
|
||||
bool containsValue (ValueTypeParameter valueToLookFor) const
|
||||
{
|
||||
const ScopedLockType sl (getLock());
|
||||
|
||||
for (int i = getNumSlots(); --i >= 0;)
|
||||
for (const HashEntry* entry = slots.getUnchecked(i); entry != nullptr; entry = entry->nextEntry)
|
||||
if (entry->value == valueToLookFor)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Adds or replaces an element in the hash-map.
|
||||
If there's already an item with the given key, this will replace its value. Otherwise, a new item
|
||||
will be added to the map.
|
||||
*/
|
||||
void set (KeyTypeParameter newKey, ValueTypeParameter newValue)
|
||||
{
|
||||
const ScopedLockType sl (getLock());
|
||||
const int hashIndex = generateHashFor (newKey);
|
||||
|
||||
HashEntry* const firstEntry = slots.getUnchecked (hashIndex);
|
||||
|
||||
for (HashEntry* entry = firstEntry; entry != nullptr; entry = entry->nextEntry)
|
||||
{
|
||||
if (entry->key == newKey)
|
||||
{
|
||||
entry->value = newValue;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
slots.set (hashIndex, new HashEntry (newKey, newValue, firstEntry));
|
||||
++totalNumItems;
|
||||
|
||||
if (totalNumItems > (getNumSlots() * 3) / 2)
|
||||
remapTable (getNumSlots() * 2);
|
||||
}
|
||||
|
||||
/** Removes an item with the given key. */
|
||||
void remove (KeyTypeParameter keyToRemove)
|
||||
{
|
||||
const ScopedLockType sl (getLock());
|
||||
const int hashIndex = generateHashFor (keyToRemove);
|
||||
HashEntry* entry = slots.getUnchecked (hashIndex);
|
||||
HashEntry* previous = nullptr;
|
||||
|
||||
while (entry != nullptr)
|
||||
{
|
||||
if (entry->key == keyToRemove)
|
||||
{
|
||||
const ScopedPointer<HashEntry> deleter (entry);
|
||||
|
||||
entry = entry->nextEntry;
|
||||
|
||||
if (previous != nullptr)
|
||||
previous->nextEntry = entry;
|
||||
else
|
||||
slots.set (hashIndex, entry);
|
||||
|
||||
--totalNumItems;
|
||||
}
|
||||
else
|
||||
{
|
||||
previous = entry;
|
||||
entry = entry->nextEntry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes all items with the given value. */
|
||||
void removeValue (ValueTypeParameter valueToRemove)
|
||||
{
|
||||
const ScopedLockType sl (getLock());
|
||||
|
||||
for (int i = getNumSlots(); --i >= 0;)
|
||||
{
|
||||
HashEntry* entry = slots.getUnchecked(i);
|
||||
HashEntry* previous = nullptr;
|
||||
|
||||
while (entry != nullptr)
|
||||
{
|
||||
if (entry->value == valueToRemove)
|
||||
{
|
||||
const ScopedPointer<HashEntry> deleter (entry);
|
||||
|
||||
entry = entry->nextEntry;
|
||||
|
||||
if (previous != nullptr)
|
||||
previous->nextEntry = entry;
|
||||
else
|
||||
slots.set (i, entry);
|
||||
|
||||
--totalNumItems;
|
||||
}
|
||||
else
|
||||
{
|
||||
previous = entry;
|
||||
entry = entry->nextEntry;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Remaps the hash-map to use a different number of slots for its hash function.
|
||||
Each slot corresponds to a single hash-code, and each one can contain multiple items.
|
||||
@see getNumSlots()
|
||||
*/
|
||||
void remapTable (int newNumberOfSlots)
|
||||
{
|
||||
HashMap newTable (newNumberOfSlots);
|
||||
|
||||
for (int i = getNumSlots(); --i >= 0;)
|
||||
for (const HashEntry* entry = slots.getUnchecked(i); entry != nullptr; entry = entry->nextEntry)
|
||||
newTable.set (entry->key, entry->value);
|
||||
|
||||
swapWith (newTable);
|
||||
}
|
||||
|
||||
/** Returns the number of slots which are available for hashing.
|
||||
Each slot corresponds to a single hash-code, and each one can contain multiple items.
|
||||
@see getNumSlots()
|
||||
*/
|
||||
inline int getNumSlots() const noexcept
|
||||
{
|
||||
return slots.size();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Efficiently swaps the contents of two hash-maps. */
|
||||
void swapWith (HashMap& otherHashMap) noexcept
|
||||
{
|
||||
const ScopedLockType lock1 (getLock());
|
||||
const ScopedLockType lock2 (otherHashMap.getLock());
|
||||
|
||||
slots.swapWithArray (otherHashMap.slots);
|
||||
std::swap (totalNumItems, otherHashMap.totalNumItems);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the CriticalSection that locks this structure.
|
||||
To lock, you can call getLock().enter() and getLock().exit(), or preferably use
|
||||
an object of ScopedLockType as an RAII lock for it.
|
||||
*/
|
||||
inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return lock; }
|
||||
|
||||
/** Returns the type of scoped lock to use for locking this array */
|
||||
typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class HashEntry
|
||||
{
|
||||
public:
|
||||
HashEntry (KeyTypeParameter k, ValueTypeParameter val, HashEntry* const next)
|
||||
: key (k), value (val), nextEntry (next)
|
||||
{}
|
||||
|
||||
const KeyType key;
|
||||
ValueType value;
|
||||
HashEntry* nextEntry;
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE (HashEntry)
|
||||
};
|
||||
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Iterates over the items in a HashMap.
|
||||
|
||||
To use it, repeatedly call next() until it returns false, e.g.
|
||||
@code
|
||||
HashMap <String, String> myMap;
|
||||
|
||||
HashMap<String, String>::Iterator i (myMap);
|
||||
|
||||
while (i.next())
|
||||
{
|
||||
DBG (i.getKey() << " -> " << i.getValue());
|
||||
}
|
||||
@endcode
|
||||
|
||||
The order in which items are iterated bears no resemblence to the order in which
|
||||
they were originally added!
|
||||
|
||||
Obviously as soon as you call any non-const methods on the original hash-map, any
|
||||
iterators that were created beforehand will cease to be valid, and should not be used.
|
||||
|
||||
@see HashMap
|
||||
*/
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
Iterator (const HashMap& hashMapToIterate)
|
||||
: hashMap (hashMapToIterate), entry (nullptr), index (0)
|
||||
{}
|
||||
|
||||
/** Moves to the next item, if one is available.
|
||||
When this returns true, you can get the item's key and value using getKey() and
|
||||
getValue(). If it returns false, the iteration has finished and you should stop.
|
||||
*/
|
||||
bool next()
|
||||
{
|
||||
if (entry != nullptr)
|
||||
entry = entry->nextEntry;
|
||||
|
||||
while (entry == nullptr)
|
||||
{
|
||||
if (index >= hashMap.getNumSlots())
|
||||
return false;
|
||||
|
||||
entry = hashMap.slots.getUnchecked (index++);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Returns the current item's key.
|
||||
This should only be called when a call to next() has just returned true.
|
||||
*/
|
||||
KeyType getKey() const
|
||||
{
|
||||
return entry != nullptr ? entry->key : KeyType();
|
||||
}
|
||||
|
||||
/** Returns the current item's value.
|
||||
This should only be called when a call to next() has just returned true.
|
||||
*/
|
||||
ValueType getValue() const
|
||||
{
|
||||
return entry != nullptr ? entry->value : ValueType();
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
const HashMap& hashMap;
|
||||
HashEntry* entry;
|
||||
int index;
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Iterator)
|
||||
};
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
enum { defaultHashTableSize = 101 };
|
||||
friend class Iterator;
|
||||
|
||||
Array <HashEntry*> slots;
|
||||
int totalNumItems;
|
||||
TypeOfCriticalSectionToUse lock;
|
||||
|
||||
int generateHashFor (KeyTypeParameter key) const
|
||||
{
|
||||
const int hash = HashFunctionToUse::generateHash (key, getNumSlots());
|
||||
bassert (isPositiveAndBelow (hash, getNumSlots())); // your hash function is generating out-of-range numbers!
|
||||
return hash;
|
||||
}
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HashMap)
|
||||
};
|
||||
|
||||
|
||||
#endif // BEAST_HASHMAP_BEASTHEADER
|
||||
366
modules/beast_core/containers/beast_LinkedListPointer.h
Normal file
366
modules/beast_core/containers/beast_LinkedListPointer.h
Normal file
@@ -0,0 +1,366 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_LINKEDLISTPOINTER_BEASTHEADER
|
||||
#define BEAST_LINKEDLISTPOINTER_BEASTHEADER
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Helps to manipulate singly-linked lists of objects.
|
||||
|
||||
For objects that are designed to contain a pointer to the subsequent item in the
|
||||
list, this class contains methods to deal with the list. To use it, the ObjectType
|
||||
class that it points to must contain a LinkedListPointer called nextListItem, e.g.
|
||||
|
||||
@code
|
||||
struct MyObject
|
||||
{
|
||||
int x, y, z;
|
||||
|
||||
// A linkable object must contain a member with this name and type, which must be
|
||||
// accessible by the LinkedListPointer class. (This doesn't mean it has to be public -
|
||||
// you could make your class a friend of a LinkedListPointer<MyObject> instead).
|
||||
LinkedListPointer<MyObject> nextListItem;
|
||||
};
|
||||
|
||||
LinkedListPointer<MyObject> myList;
|
||||
myList.append (new MyObject());
|
||||
myList.append (new MyObject());
|
||||
|
||||
int numItems = myList.size(); // returns 2
|
||||
MyObject* lastInList = myList.getLast();
|
||||
@endcode
|
||||
*/
|
||||
template <class ObjectType>
|
||||
class LinkedListPointer
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a null pointer to an empty list. */
|
||||
LinkedListPointer() noexcept
|
||||
: item (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
/** Creates a pointer to a list whose head is the item provided. */
|
||||
explicit LinkedListPointer (ObjectType* const headItem) noexcept
|
||||
: item (headItem)
|
||||
{
|
||||
}
|
||||
|
||||
/** Sets this pointer to point to a new list. */
|
||||
LinkedListPointer& operator= (ObjectType* const newItem) noexcept
|
||||
{
|
||||
item = newItem;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
LinkedListPointer (LinkedListPointer&& other) noexcept
|
||||
: item (other.item)
|
||||
{
|
||||
other.item = nullptr;
|
||||
}
|
||||
|
||||
LinkedListPointer& operator= (LinkedListPointer&& other) noexcept
|
||||
{
|
||||
bassert (this != &other); // hopefully the compiler should make this situation impossible!
|
||||
|
||||
item = other.item;
|
||||
other.item = nullptr;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the item which this pointer points to. */
|
||||
inline operator ObjectType*() const noexcept
|
||||
{
|
||||
return item;
|
||||
}
|
||||
|
||||
/** Returns the item which this pointer points to. */
|
||||
inline ObjectType* get() const noexcept
|
||||
{
|
||||
return item;
|
||||
}
|
||||
|
||||
/** Returns the last item in the list which this pointer points to.
|
||||
This will iterate the list and return the last item found. Obviously the speed
|
||||
of this operation will be proportional to the size of the list. If the list is
|
||||
empty the return value will be this object.
|
||||
If you're planning on appending a number of items to your list, it's much more
|
||||
efficient to use the Appender class than to repeatedly call getLast() to find the end.
|
||||
*/
|
||||
LinkedListPointer& getLast() noexcept
|
||||
{
|
||||
LinkedListPointer* l = this;
|
||||
|
||||
while (l->item != nullptr)
|
||||
l = &(l->item->nextListItem);
|
||||
|
||||
return *l;
|
||||
}
|
||||
|
||||
/** Returns the number of items in the list.
|
||||
Obviously with a simple linked list, getting the size involves iterating the list, so
|
||||
this can be a lengthy operation - be careful when using this method in your code.
|
||||
*/
|
||||
int size() const noexcept
|
||||
{
|
||||
int total = 0;
|
||||
|
||||
for (ObjectType* i = item; i != nullptr; i = i->nextListItem)
|
||||
++total;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/** Returns the item at a given index in the list.
|
||||
Since the only way to find an item is to iterate the list, this operation can obviously
|
||||
be slow, depending on its size, so you should be careful when using this in algorithms.
|
||||
*/
|
||||
LinkedListPointer& operator[] (int index) noexcept
|
||||
{
|
||||
LinkedListPointer* l = this;
|
||||
|
||||
while (--index >= 0 && l->item != nullptr)
|
||||
l = &(l->item->nextListItem);
|
||||
|
||||
return *l;
|
||||
}
|
||||
|
||||
/** Returns the item at a given index in the list.
|
||||
Since the only way to find an item is to iterate the list, this operation can obviously
|
||||
be slow, depending on its size, so you should be careful when using this in algorithms.
|
||||
*/
|
||||
const LinkedListPointer& operator[] (int index) const noexcept
|
||||
{
|
||||
const LinkedListPointer* l = this;
|
||||
|
||||
while (--index >= 0 && l->item != nullptr)
|
||||
l = &(l->item->nextListItem);
|
||||
|
||||
return *l;
|
||||
}
|
||||
|
||||
/** Returns true if the list contains the given item. */
|
||||
bool contains (const ObjectType* const itemToLookFor) const noexcept
|
||||
{
|
||||
for (ObjectType* i = item; i != nullptr; i = i->nextListItem)
|
||||
if (itemToLookFor == i)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Inserts an item into the list, placing it before the item that this pointer
|
||||
currently points to.
|
||||
*/
|
||||
void insertNext (ObjectType* const newItem)
|
||||
{
|
||||
bassert (newItem != nullptr);
|
||||
bassert (newItem->nextListItem == nullptr);
|
||||
newItem->nextListItem = item;
|
||||
item = newItem;
|
||||
}
|
||||
|
||||
/** Inserts an item at a numeric index in the list.
|
||||
Obviously this will involve iterating the list to find the item at the given index,
|
||||
so be careful about the impact this may have on execution time.
|
||||
*/
|
||||
void insertAtIndex (int index, ObjectType* newItem)
|
||||
{
|
||||
bassert (newItem != nullptr);
|
||||
LinkedListPointer* l = this;
|
||||
|
||||
while (index != 0 && l->item != nullptr)
|
||||
{
|
||||
l = &(l->item->nextListItem);
|
||||
--index;
|
||||
}
|
||||
|
||||
l->insertNext (newItem);
|
||||
}
|
||||
|
||||
/** Replaces the object that this pointer points to, appending the rest of the list to
|
||||
the new object, and returning the old one.
|
||||
*/
|
||||
ObjectType* replaceNext (ObjectType* const newItem) noexcept
|
||||
{
|
||||
bassert (newItem != nullptr);
|
||||
bassert (newItem->nextListItem == nullptr);
|
||||
|
||||
ObjectType* const oldItem = item;
|
||||
item = newItem;
|
||||
item->nextListItem = oldItem->nextListItem.item;
|
||||
oldItem->nextListItem.item = nullptr;
|
||||
return oldItem;
|
||||
}
|
||||
|
||||
/** Adds an item to the end of the list.
|
||||
|
||||
This operation involves iterating the whole list, so can be slow - if you need to
|
||||
append a number of items to your list, it's much more efficient to use the Appender
|
||||
class than to repeatedly call append().
|
||||
*/
|
||||
void append (ObjectType* const newItem)
|
||||
{
|
||||
getLast().item = newItem;
|
||||
}
|
||||
|
||||
/** Creates copies of all the items in another list and adds them to this one.
|
||||
This will use the ObjectType's copy constructor to try to create copies of each
|
||||
item in the other list, and appends them to this list.
|
||||
*/
|
||||
void addCopyOfList (const LinkedListPointer& other)
|
||||
{
|
||||
LinkedListPointer* insertPoint = this;
|
||||
|
||||
for (ObjectType* i = other.item; i != nullptr; i = i->nextListItem)
|
||||
{
|
||||
insertPoint->insertNext (new ObjectType (*i));
|
||||
insertPoint = &(insertPoint->item->nextListItem);
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes the head item from the list.
|
||||
This won't delete the object that is removed, but returns it, so the caller can
|
||||
delete it if necessary.
|
||||
*/
|
||||
ObjectType* removeNext() noexcept
|
||||
{
|
||||
ObjectType* const oldItem = item;
|
||||
|
||||
if (oldItem != nullptr)
|
||||
{
|
||||
item = oldItem->nextListItem;
|
||||
oldItem->nextListItem.item = nullptr;
|
||||
}
|
||||
|
||||
return oldItem;
|
||||
}
|
||||
|
||||
/** Removes a specific item from the list.
|
||||
Note that this will not delete the item, it simply unlinks it from the list.
|
||||
*/
|
||||
void remove (ObjectType* const itemToRemove)
|
||||
{
|
||||
if (LinkedListPointer* const l = findPointerTo (itemToRemove))
|
||||
l->removeNext();
|
||||
}
|
||||
|
||||
/** Iterates the list, calling the delete operator on all of its elements and
|
||||
leaving this pointer empty.
|
||||
*/
|
||||
void deleteAll()
|
||||
{
|
||||
while (item != nullptr)
|
||||
{
|
||||
ObjectType* const oldItem = item;
|
||||
item = oldItem->nextListItem;
|
||||
delete oldItem;
|
||||
}
|
||||
}
|
||||
|
||||
/** Finds a pointer to a given item.
|
||||
If the item is found in the list, this returns the pointer that points to it. If
|
||||
the item isn't found, this returns null.
|
||||
*/
|
||||
LinkedListPointer* findPointerTo (ObjectType* const itemToLookFor) noexcept
|
||||
{
|
||||
LinkedListPointer* l = this;
|
||||
|
||||
while (l->item != nullptr)
|
||||
{
|
||||
if (l->item == itemToLookFor)
|
||||
return l;
|
||||
|
||||
l = &(l->item->nextListItem);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/** Copies the items in the list to an array.
|
||||
The destArray must contain enough elements to hold the entire list - no checks are
|
||||
made for this!
|
||||
*/
|
||||
void copyToArray (ObjectType** destArray) const noexcept
|
||||
{
|
||||
bassert (destArray != nullptr);
|
||||
|
||||
for (ObjectType* i = item; i != nullptr; i = i->nextListItem)
|
||||
*destArray++ = i;
|
||||
}
|
||||
|
||||
/** Swaps this pointer with another one */
|
||||
void swapWith (LinkedListPointer& other) noexcept
|
||||
{
|
||||
std::swap (item, other.item);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Allows efficient repeated insertions into a list.
|
||||
|
||||
You can create an Appender object which points to the last element in your
|
||||
list, and then repeatedly call Appender::append() to add items to the end
|
||||
of the list in O(1) time.
|
||||
*/
|
||||
class Appender
|
||||
{
|
||||
public:
|
||||
/** Creates an appender which will add items to the given list.
|
||||
*/
|
||||
Appender (LinkedListPointer& endOfListPointer) noexcept
|
||||
: endOfList (&endOfListPointer)
|
||||
{
|
||||
// This can only be used to add to the end of a list.
|
||||
bassert (endOfListPointer.item == nullptr);
|
||||
}
|
||||
|
||||
/** Appends an item to the list. */
|
||||
void append (ObjectType* const newItem) noexcept
|
||||
{
|
||||
*endOfList = newItem;
|
||||
endOfList = &(newItem->nextListItem);
|
||||
}
|
||||
|
||||
private:
|
||||
LinkedListPointer* endOfList;
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE (Appender)
|
||||
};
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
ObjectType* item;
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE (LinkedListPointer)
|
||||
};
|
||||
|
||||
|
||||
#endif // BEAST_LINKEDLISTPOINTER_BEASTHEADER
|
||||
304
modules/beast_core/containers/beast_NamedValueSet.cpp
Normal file
304
modules/beast_core/containers/beast_NamedValueSet.cpp
Normal file
@@ -0,0 +1,304 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
NamedValueSet::NamedValue::NamedValue() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
inline NamedValueSet::NamedValue::NamedValue (const Identifier n, const var& v)
|
||||
: name (n), value (v)
|
||||
{
|
||||
}
|
||||
|
||||
NamedValueSet::NamedValue::NamedValue (const NamedValue& other)
|
||||
: name (other.name), value (other.value)
|
||||
{
|
||||
}
|
||||
|
||||
NamedValueSet::NamedValue& NamedValueSet::NamedValue::operator= (const NamedValueSet::NamedValue& other)
|
||||
{
|
||||
name = other.name;
|
||||
value = other.value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
NamedValueSet::NamedValue::NamedValue (NamedValue&& other) noexcept
|
||||
: nextListItem (static_cast <LinkedListPointer<NamedValue>&&> (other.nextListItem)),
|
||||
name (static_cast <Identifier&&> (other.name)),
|
||||
value (static_cast <var&&> (other.value))
|
||||
{
|
||||
}
|
||||
|
||||
inline NamedValueSet::NamedValue::NamedValue (const Identifier n, var&& v)
|
||||
: name (n), value (static_cast <var&&> (v))
|
||||
{
|
||||
}
|
||||
|
||||
NamedValueSet::NamedValue& NamedValueSet::NamedValue::operator= (NamedValue&& other) noexcept
|
||||
{
|
||||
nextListItem = static_cast <LinkedListPointer<NamedValue>&&> (other.nextListItem);
|
||||
name = static_cast <Identifier&&> (other.name);
|
||||
value = static_cast <var&&> (other.value);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool NamedValueSet::NamedValue::operator== (const NamedValueSet::NamedValue& other) const noexcept
|
||||
{
|
||||
return name == other.name && value == other.value;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
NamedValueSet::NamedValueSet() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
NamedValueSet::NamedValueSet (const NamedValueSet& other)
|
||||
{
|
||||
values.addCopyOfList (other.values);
|
||||
}
|
||||
|
||||
NamedValueSet& NamedValueSet::operator= (const NamedValueSet& other)
|
||||
{
|
||||
clear();
|
||||
values.addCopyOfList (other.values);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
NamedValueSet::NamedValueSet (NamedValueSet&& other) noexcept
|
||||
: values (static_cast <LinkedListPointer<NamedValue>&&> (other.values))
|
||||
{
|
||||
}
|
||||
|
||||
NamedValueSet& NamedValueSet::operator= (NamedValueSet&& other) noexcept
|
||||
{
|
||||
other.values.swapWith (values);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
NamedValueSet::~NamedValueSet()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void NamedValueSet::clear()
|
||||
{
|
||||
values.deleteAll();
|
||||
}
|
||||
|
||||
bool NamedValueSet::operator== (const NamedValueSet& other) const
|
||||
{
|
||||
const NamedValue* i1 = values;
|
||||
const NamedValue* i2 = other.values;
|
||||
|
||||
while (i1 != nullptr && i2 != nullptr)
|
||||
{
|
||||
if (! (*i1 == *i2))
|
||||
return false;
|
||||
|
||||
i1 = i1->nextListItem;
|
||||
i2 = i2->nextListItem;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NamedValueSet::operator!= (const NamedValueSet& other) const
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
int NamedValueSet::size() const noexcept
|
||||
{
|
||||
return values.size();
|
||||
}
|
||||
|
||||
const var& NamedValueSet::operator[] (const Identifier name) const
|
||||
{
|
||||
for (NamedValue* i = values; i != nullptr; i = i->nextListItem)
|
||||
if (i->name == name)
|
||||
return i->value;
|
||||
|
||||
return var::null;
|
||||
}
|
||||
|
||||
var NamedValueSet::getWithDefault (const Identifier name, const var& defaultReturnValue) const
|
||||
{
|
||||
if (const var* const v = getVarPointer (name))
|
||||
return *v;
|
||||
|
||||
return defaultReturnValue;
|
||||
}
|
||||
|
||||
var* NamedValueSet::getVarPointer (const Identifier name) const noexcept
|
||||
{
|
||||
for (NamedValue* i = values; i != nullptr; i = i->nextListItem)
|
||||
if (i->name == name)
|
||||
return &(i->value);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
bool NamedValueSet::set (const Identifier name, var&& newValue)
|
||||
{
|
||||
LinkedListPointer<NamedValue>* i = &values;
|
||||
|
||||
while (i->get() != nullptr)
|
||||
{
|
||||
NamedValue* const v = i->get();
|
||||
|
||||
if (v->name == name)
|
||||
{
|
||||
if (v->value.equalsWithSameType (newValue))
|
||||
return false;
|
||||
|
||||
v->value = static_cast <var&&> (newValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
i = &(v->nextListItem);
|
||||
}
|
||||
|
||||
i->insertNext (new NamedValue (name, static_cast <var&&> (newValue)));
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool NamedValueSet::set (const Identifier name, const var& newValue)
|
||||
{
|
||||
LinkedListPointer<NamedValue>* i = &values;
|
||||
|
||||
while (i->get() != nullptr)
|
||||
{
|
||||
NamedValue* const v = i->get();
|
||||
|
||||
if (v->name == name)
|
||||
{
|
||||
if (v->value.equalsWithSameType (newValue))
|
||||
return false;
|
||||
|
||||
v->value = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
i = &(v->nextListItem);
|
||||
}
|
||||
|
||||
i->insertNext (new NamedValue (name, newValue));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NamedValueSet::contains (const Identifier name) const
|
||||
{
|
||||
return getVarPointer (name) != nullptr;
|
||||
}
|
||||
|
||||
bool NamedValueSet::remove (const Identifier name)
|
||||
{
|
||||
LinkedListPointer<NamedValue>* i = &values;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
NamedValue* const v = i->get();
|
||||
|
||||
if (v == nullptr)
|
||||
break;
|
||||
|
||||
if (v->name == name)
|
||||
{
|
||||
delete i->removeNext();
|
||||
return true;
|
||||
}
|
||||
|
||||
i = &(v->nextListItem);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const Identifier NamedValueSet::getName (const int index) const
|
||||
{
|
||||
const NamedValue* const v = values[index];
|
||||
bassert (v != nullptr);
|
||||
return v->name;
|
||||
}
|
||||
|
||||
const var& NamedValueSet::getValueAt (const int index) const
|
||||
{
|
||||
const NamedValue* const v = values[index];
|
||||
bassert (v != nullptr);
|
||||
return v->value;
|
||||
}
|
||||
|
||||
void NamedValueSet::setFromXmlAttributes (const XmlElement& xml)
|
||||
{
|
||||
clear();
|
||||
LinkedListPointer<NamedValue>::Appender appender (values);
|
||||
|
||||
const int numAtts = xml.getNumAttributes(); // xxx inefficient - should write an att iterator..
|
||||
|
||||
for (int i = 0; i < numAtts; ++i)
|
||||
{
|
||||
const String& name = xml.getAttributeName (i);
|
||||
const String& value = xml.getAttributeValue (i);
|
||||
|
||||
if (name.startsWith ("base64:"))
|
||||
{
|
||||
MemoryBlock mb;
|
||||
|
||||
if (mb.fromBase64Encoding (value))
|
||||
{
|
||||
appender.append (new NamedValue (name.substring (7), var (mb)));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
appender.append (new NamedValue (name, var (value)));
|
||||
}
|
||||
}
|
||||
|
||||
void NamedValueSet::copyToXmlAttributes (XmlElement& xml) const
|
||||
{
|
||||
for (NamedValue* i = values; i != nullptr; i = i->nextListItem)
|
||||
{
|
||||
if (const MemoryBlock* mb = i->value.getBinaryData())
|
||||
{
|
||||
xml.setAttribute ("base64:" + i->name.toString(),
|
||||
mb->toBase64Encoding());
|
||||
}
|
||||
else
|
||||
{
|
||||
// These types can't be stored as XML!
|
||||
bassert (! i->value.isObject());
|
||||
bassert (! i->value.isMethod());
|
||||
bassert (! i->value.isArray());
|
||||
|
||||
xml.setAttribute (i->name.toString(),
|
||||
i->value.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
164
modules/beast_core/containers/beast_NamedValueSet.h
Normal file
164
modules/beast_core/containers/beast_NamedValueSet.h
Normal file
@@ -0,0 +1,164 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_NAMEDVALUESET_BEASTHEADER
|
||||
#define BEAST_NAMEDVALUESET_BEASTHEADER
|
||||
|
||||
#include "beast_Variant.h"
|
||||
#include "../containers/beast_LinkedListPointer.h"
|
||||
class XmlElement;
|
||||
#ifndef DOXYGEN
|
||||
class JSONFormatter;
|
||||
#endif
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** Holds a set of named var objects.
|
||||
|
||||
This can be used as a basic structure to hold a set of var object, which can
|
||||
be retrieved by using their identifier.
|
||||
*/
|
||||
class BEAST_API NamedValueSet
|
||||
{
|
||||
public:
|
||||
/** Creates an empty set. */
|
||||
NamedValueSet() noexcept;
|
||||
|
||||
/** Creates a copy of another set. */
|
||||
NamedValueSet (const NamedValueSet& other);
|
||||
|
||||
/** Replaces this set with a copy of another set. */
|
||||
NamedValueSet& operator= (const NamedValueSet& other);
|
||||
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
NamedValueSet (NamedValueSet&& other) noexcept;
|
||||
NamedValueSet& operator= (NamedValueSet&& other) noexcept;
|
||||
#endif
|
||||
|
||||
/** Destructor. */
|
||||
~NamedValueSet();
|
||||
|
||||
bool operator== (const NamedValueSet& other) const;
|
||||
bool operator!= (const NamedValueSet& other) const;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the total number of values that the set contains. */
|
||||
int size() const noexcept;
|
||||
|
||||
/** Returns the value of a named item.
|
||||
If the name isn't found, this will return a void variant.
|
||||
@see getProperty
|
||||
*/
|
||||
const var& operator[] (const Identifier name) const;
|
||||
|
||||
/** Tries to return the named value, but if no such value is found, this will
|
||||
instead return the supplied default value.
|
||||
*/
|
||||
var getWithDefault (const Identifier name, const var& defaultReturnValue) const;
|
||||
|
||||
/** Changes or adds a named value.
|
||||
@returns true if a value was changed or added; false if the
|
||||
value was already set the the value passed-in.
|
||||
*/
|
||||
bool set (const Identifier name, const var& newValue);
|
||||
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
/** Changes or adds a named value.
|
||||
@returns true if a value was changed or added; false if the
|
||||
value was already set the the value passed-in.
|
||||
*/
|
||||
bool set (const Identifier name, var&& newValue);
|
||||
#endif
|
||||
|
||||
/** Returns true if the set contains an item with the specified name. */
|
||||
bool contains (const Identifier name) const;
|
||||
|
||||
/** Removes a value from the set.
|
||||
@returns true if a value was removed; false if there was no value
|
||||
with the name that was given.
|
||||
*/
|
||||
bool remove (const Identifier name);
|
||||
|
||||
/** Returns the name of the value at a given index.
|
||||
The index must be between 0 and size() - 1.
|
||||
*/
|
||||
const Identifier getName (int index) const;
|
||||
|
||||
/** Returns the value of the item at a given index.
|
||||
The index must be between 0 and size() - 1.
|
||||
*/
|
||||
const var& getValueAt (int index) const;
|
||||
|
||||
/** Removes all values. */
|
||||
void clear();
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a pointer to the var that holds a named value, or null if there is
|
||||
no value with this name.
|
||||
|
||||
Do not use this method unless you really need access to the internal var object
|
||||
for some reason - for normal reading and writing always prefer operator[]() and set().
|
||||
*/
|
||||
var* getVarPointer (const Identifier name) const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Sets properties to the values of all of an XML element's attributes. */
|
||||
void setFromXmlAttributes (const XmlElement& xml);
|
||||
|
||||
/** Sets attributes in an XML element corresponding to each of this object's
|
||||
properties.
|
||||
*/
|
||||
void copyToXmlAttributes (XmlElement& xml) const;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class NamedValue
|
||||
{
|
||||
public:
|
||||
NamedValue() noexcept;
|
||||
NamedValue (const NamedValue&);
|
||||
NamedValue (const Identifier name, const var& value);
|
||||
NamedValue& operator= (const NamedValue&);
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
NamedValue (NamedValue&&) noexcept;
|
||||
NamedValue (const Identifier name, var&& value);
|
||||
NamedValue& operator= (NamedValue&&) noexcept;
|
||||
#endif
|
||||
bool operator== (const NamedValue& other) const noexcept;
|
||||
|
||||
LinkedListPointer<NamedValue> nextListItem;
|
||||
Identifier name;
|
||||
var value;
|
||||
|
||||
private:
|
||||
BEAST_LEAK_DETECTOR (NamedValue)
|
||||
};
|
||||
|
||||
friend class LinkedListPointer<NamedValue>;
|
||||
LinkedListPointer<NamedValue> values;
|
||||
|
||||
friend class JSONFormatter;
|
||||
};
|
||||
|
||||
|
||||
#endif // BEAST_NAMEDVALUESET_BEASTHEADER
|
||||
865
modules/beast_core/containers/beast_OwnedArray.h
Normal file
865
modules/beast_core/containers/beast_OwnedArray.h
Normal file
@@ -0,0 +1,865 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_OWNEDARRAY_BEASTHEADER
|
||||
#define BEAST_OWNEDARRAY_BEASTHEADER
|
||||
|
||||
#include "beast_ArrayAllocationBase.h"
|
||||
#include "beast_ElementComparator.h"
|
||||
#include "../threads/beast_CriticalSection.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** An array designed for holding objects.
|
||||
|
||||
This holds a list of pointers to objects, and will automatically
|
||||
delete the objects when they are removed from the array, or when the
|
||||
array is itself deleted.
|
||||
|
||||
Declare it in the form: OwnedArray<MyObjectClass>
|
||||
|
||||
..and then add new objects, e.g. myOwnedArray.add (new MyObjectClass());
|
||||
|
||||
After adding objects, they are 'owned' by the array and will be deleted when
|
||||
removed or replaced.
|
||||
|
||||
To make all the array's methods thread-safe, pass in "CriticalSection" as the templated
|
||||
TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection.
|
||||
|
||||
@see Array, ReferenceCountedArray, StringArray, CriticalSection
|
||||
*/
|
||||
template <class ObjectClass,
|
||||
class TypeOfCriticalSectionToUse = DummyCriticalSection>
|
||||
|
||||
class OwnedArray
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an empty array. */
|
||||
OwnedArray() noexcept
|
||||
: numUsed (0)
|
||||
{
|
||||
}
|
||||
|
||||
/** Deletes the array and also deletes any objects inside it.
|
||||
|
||||
To get rid of the array without deleting its objects, use its
|
||||
clear (false) method before deleting it.
|
||||
*/
|
||||
~OwnedArray()
|
||||
{
|
||||
deleteAllObjects();
|
||||
}
|
||||
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
OwnedArray (OwnedArray&& other) noexcept
|
||||
: data (static_cast <ArrayAllocationBase <ObjectClass*, TypeOfCriticalSectionToUse>&&> (other.data)),
|
||||
numUsed (other.numUsed)
|
||||
{
|
||||
other.numUsed = 0;
|
||||
}
|
||||
|
||||
OwnedArray& operator= (OwnedArray&& other) noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
deleteAllObjects();
|
||||
|
||||
data = static_cast <ArrayAllocationBase <ObjectClass*, TypeOfCriticalSectionToUse>&&> (other.data);
|
||||
numUsed = other.numUsed;
|
||||
other.numUsed = 0;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
/** Clears the array, optionally deleting the objects inside it first. */
|
||||
void clear (const bool deleteObjects = true)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (deleteObjects)
|
||||
deleteAllObjects();
|
||||
|
||||
data.setAllocatedSize (0);
|
||||
numUsed = 0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the number of items currently in the array.
|
||||
@see operator[]
|
||||
*/
|
||||
inline int size() const noexcept
|
||||
{
|
||||
return numUsed;
|
||||
}
|
||||
|
||||
/** Returns a pointer to the object at this index in the array.
|
||||
|
||||
If the index is out-of-range, this will return a null pointer, (and
|
||||
it could be null anyway, because it's ok for the array to hold null
|
||||
pointers as well as objects).
|
||||
|
||||
@see getUnchecked
|
||||
*/
|
||||
inline ObjectClass* operator[] (const int index) const noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
return isPositiveAndBelow (index, numUsed) ? data.elements [index]
|
||||
: static_cast <ObjectClass*> (nullptr);
|
||||
}
|
||||
|
||||
/** Returns a pointer to the object at this index in the array, without checking whether the index is in-range.
|
||||
|
||||
This is a faster and less safe version of operator[] which doesn't check the index passed in, so
|
||||
it can be used when you're sure the index is always going to be legal.
|
||||
*/
|
||||
inline ObjectClass* getUnchecked (const int index) const noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
bassert (isPositiveAndBelow (index, numUsed));
|
||||
return data.elements [index];
|
||||
}
|
||||
|
||||
/** Returns a pointer to the first object in the array.
|
||||
|
||||
This will return a null pointer if the array's empty.
|
||||
@see getLast
|
||||
*/
|
||||
inline ObjectClass* getFirst() const noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
return numUsed > 0 ? data.elements [0]
|
||||
: static_cast <ObjectClass*> (nullptr);
|
||||
}
|
||||
|
||||
/** Returns a pointer to the last object in the array.
|
||||
|
||||
This will return a null pointer if the array's empty.
|
||||
@see getFirst
|
||||
*/
|
||||
inline ObjectClass* getLast() const noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
return numUsed > 0 ? data.elements [numUsed - 1]
|
||||
: static_cast <ObjectClass*> (nullptr);
|
||||
}
|
||||
|
||||
/** Returns a pointer to the actual array data.
|
||||
This pointer will only be valid until the next time a non-const method
|
||||
is called on the array.
|
||||
*/
|
||||
inline ObjectClass** getRawDataPointer() noexcept
|
||||
{
|
||||
return data.elements;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a pointer to the first element in the array.
|
||||
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||
*/
|
||||
inline ObjectClass** begin() const noexcept
|
||||
{
|
||||
return data.elements;
|
||||
}
|
||||
|
||||
/** Returns a pointer to the element which follows the last element in the array.
|
||||
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||
*/
|
||||
inline ObjectClass** end() const noexcept
|
||||
{
|
||||
return data.elements + numUsed;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Finds the index of an object which might be in the array.
|
||||
|
||||
@param objectToLookFor the object to look for
|
||||
@returns the index at which the object was found, or -1 if it's not found
|
||||
*/
|
||||
int indexOf (const ObjectClass* const objectToLookFor) const noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
ObjectClass* const* e = data.elements.getData();
|
||||
ObjectClass* const* const end_ = e + numUsed;
|
||||
|
||||
for (; e != end_; ++e)
|
||||
if (objectToLookFor == *e)
|
||||
return static_cast <int> (e - data.elements.getData());
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Returns true if the array contains a specified object.
|
||||
|
||||
@param objectToLookFor the object to look for
|
||||
@returns true if the object is in the array
|
||||
*/
|
||||
bool contains (const ObjectClass* const objectToLookFor) const noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
ObjectClass* const* e = data.elements.getData();
|
||||
ObjectClass* const* const end_ = e + numUsed;
|
||||
|
||||
for (; e != end_; ++e)
|
||||
if (objectToLookFor == *e)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Appends a new object to the end of the array.
|
||||
|
||||
Note that the this object will be deleted by the OwnedArray when it
|
||||
is removed, so be careful not to delete it somewhere else.
|
||||
|
||||
Also be careful not to add the same object to the array more than once,
|
||||
as this will obviously cause deletion of dangling pointers.
|
||||
|
||||
@param newObject the new object to add to the array
|
||||
@see set, insert, addIfNotAlreadyThere, addSorted
|
||||
*/
|
||||
void add (const ObjectClass* const newObject) noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
data.ensureAllocatedSize (numUsed + 1);
|
||||
data.elements [numUsed++] = const_cast <ObjectClass*> (newObject);
|
||||
}
|
||||
|
||||
/** Inserts a new object into the array at the given index.
|
||||
|
||||
Note that the this object will be deleted by the OwnedArray when it
|
||||
is removed, so be careful not to delete it somewhere else.
|
||||
|
||||
If the index is less than 0 or greater than the size of the array, the
|
||||
element will be added to the end of the array.
|
||||
Otherwise, it will be inserted into the array, moving all the later elements
|
||||
along to make room.
|
||||
|
||||
Be careful not to add the same object to the array more than once,
|
||||
as this will obviously cause deletion of dangling pointers.
|
||||
|
||||
@param indexToInsertAt the index at which the new element should be inserted
|
||||
@param newObject the new object to add to the array
|
||||
@see add, addSorted, addIfNotAlreadyThere, set
|
||||
*/
|
||||
void insert (int indexToInsertAt,
|
||||
const ObjectClass* const newObject) noexcept
|
||||
{
|
||||
if (indexToInsertAt >= 0)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (indexToInsertAt > numUsed)
|
||||
indexToInsertAt = numUsed;
|
||||
|
||||
data.ensureAllocatedSize (numUsed + 1);
|
||||
|
||||
ObjectClass** const e = data.elements + indexToInsertAt;
|
||||
const int numToMove = numUsed - indexToInsertAt;
|
||||
|
||||
if (numToMove > 0)
|
||||
memmove (e + 1, e, sizeof (ObjectClass*) * (size_t) numToMove);
|
||||
|
||||
*e = const_cast <ObjectClass*> (newObject);
|
||||
++numUsed;
|
||||
}
|
||||
else
|
||||
{
|
||||
add (newObject);
|
||||
}
|
||||
}
|
||||
|
||||
/** Inserts an array of values into this array at a given position.
|
||||
|
||||
If the index is less than 0 or greater than the size of the array, the
|
||||
new elements will be added to the end of the array.
|
||||
Otherwise, they will be inserted into the array, moving all the later elements
|
||||
along to make room.
|
||||
|
||||
@param indexToInsertAt the index at which the first new element should be inserted
|
||||
@param newObjects the new values to add to the array
|
||||
@param numberOfElements how many items are in the array
|
||||
@see insert, add, addSorted, set
|
||||
*/
|
||||
void insertArray (int indexToInsertAt,
|
||||
ObjectClass* const* newObjects,
|
||||
int numberOfElements)
|
||||
{
|
||||
if (numberOfElements > 0)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
data.ensureAllocatedSize (numUsed + numberOfElements);
|
||||
ObjectClass** insertPos = data.elements;
|
||||
|
||||
if (isPositiveAndBelow (indexToInsertAt, numUsed))
|
||||
{
|
||||
insertPos += indexToInsertAt;
|
||||
const size_t numberToMove = (size_t) (numUsed - indexToInsertAt);
|
||||
memmove (insertPos + numberOfElements, insertPos, numberToMove * sizeof (ObjectClass*));
|
||||
}
|
||||
else
|
||||
{
|
||||
insertPos += numUsed;
|
||||
}
|
||||
|
||||
numUsed += numberOfElements;
|
||||
|
||||
while (--numberOfElements >= 0)
|
||||
*insertPos++ = *newObjects++;
|
||||
}
|
||||
}
|
||||
|
||||
/** Appends a new object at the end of the array as long as the array doesn't
|
||||
already contain it.
|
||||
|
||||
If the array already contains a matching object, nothing will be done.
|
||||
|
||||
@param newObject the new object to add to the array
|
||||
*/
|
||||
void addIfNotAlreadyThere (const ObjectClass* const newObject) noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (! contains (newObject))
|
||||
add (newObject);
|
||||
}
|
||||
|
||||
/** Replaces an object in the array with a different one.
|
||||
|
||||
If the index is less than zero, this method does nothing.
|
||||
If the index is beyond the end of the array, the new object is added to the end of the array.
|
||||
|
||||
Be careful not to add the same object to the array more than once,
|
||||
as this will obviously cause deletion of dangling pointers.
|
||||
|
||||
@param indexToChange the index whose value you want to change
|
||||
@param newObject the new value to set for this index.
|
||||
@param deleteOldElement whether to delete the object that's being replaced with the new one
|
||||
@see add, insert, remove
|
||||
*/
|
||||
void set (const int indexToChange,
|
||||
const ObjectClass* const newObject,
|
||||
const bool deleteOldElement = true)
|
||||
{
|
||||
if (indexToChange >= 0)
|
||||
{
|
||||
ObjectClass* toDelete = nullptr;
|
||||
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (indexToChange < numUsed)
|
||||
{
|
||||
if (deleteOldElement)
|
||||
{
|
||||
toDelete = data.elements [indexToChange];
|
||||
|
||||
if (toDelete == newObject)
|
||||
toDelete = nullptr;
|
||||
}
|
||||
|
||||
data.elements [indexToChange] = const_cast <ObjectClass*> (newObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
data.ensureAllocatedSize (numUsed + 1);
|
||||
data.elements [numUsed++] = const_cast <ObjectClass*> (newObject);
|
||||
}
|
||||
}
|
||||
|
||||
delete toDelete; // don't want to use a ScopedPointer here because if the
|
||||
// object has a private destructor, both OwnedArray and
|
||||
// ScopedPointer would need to be friend classes..
|
||||
}
|
||||
else
|
||||
{
|
||||
jassertfalse; // you're trying to set an object at a negative index, which doesn't have
|
||||
// any effect - but since the object is not being added, it may be leaking..
|
||||
}
|
||||
}
|
||||
|
||||
/** Adds elements from another array to the end of this array.
|
||||
|
||||
@param arrayToAddFrom the array from which to copy the elements
|
||||
@param startIndex the first element of the other array to start copying from
|
||||
@param numElementsToAdd how many elements to add from the other array. If this
|
||||
value is negative or greater than the number of available elements,
|
||||
all available elements will be copied.
|
||||
@see add
|
||||
*/
|
||||
template <class OtherArrayType>
|
||||
void addArray (const OtherArrayType& arrayToAddFrom,
|
||||
int startIndex = 0,
|
||||
int numElementsToAdd = -1)
|
||||
{
|
||||
const typename OtherArrayType::ScopedLockType lock1 (arrayToAddFrom.getLock());
|
||||
const ScopedLockType lock2 (getLock());
|
||||
|
||||
if (startIndex < 0)
|
||||
{
|
||||
jassertfalse;
|
||||
startIndex = 0;
|
||||
}
|
||||
|
||||
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size())
|
||||
numElementsToAdd = arrayToAddFrom.size() - startIndex;
|
||||
|
||||
data.ensureAllocatedSize (numUsed + numElementsToAdd);
|
||||
|
||||
while (--numElementsToAdd >= 0)
|
||||
{
|
||||
data.elements [numUsed] = arrayToAddFrom.getUnchecked (startIndex++);
|
||||
++numUsed;
|
||||
}
|
||||
}
|
||||
|
||||
/** Adds copies of the elements in another array to the end of this array.
|
||||
|
||||
The other array must be either an OwnedArray of a compatible type of object, or an Array
|
||||
containing pointers to the same kind of object. The objects involved must provide
|
||||
a copy constructor, and this will be used to create new copies of each element, and
|
||||
add them to this array.
|
||||
|
||||
@param arrayToAddFrom the array from which to copy the elements
|
||||
@param startIndex the first element of the other array to start copying from
|
||||
@param numElementsToAdd how many elements to add from the other array. If this
|
||||
value is negative or greater than the number of available elements,
|
||||
all available elements will be copied.
|
||||
@see add
|
||||
*/
|
||||
template <class OtherArrayType>
|
||||
void addCopiesOf (const OtherArrayType& arrayToAddFrom,
|
||||
int startIndex = 0,
|
||||
int numElementsToAdd = -1)
|
||||
{
|
||||
const typename OtherArrayType::ScopedLockType lock1 (arrayToAddFrom.getLock());
|
||||
const ScopedLockType lock2 (getLock());
|
||||
|
||||
if (startIndex < 0)
|
||||
{
|
||||
jassertfalse;
|
||||
startIndex = 0;
|
||||
}
|
||||
|
||||
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size())
|
||||
numElementsToAdd = arrayToAddFrom.size() - startIndex;
|
||||
|
||||
data.ensureAllocatedSize (numUsed + numElementsToAdd);
|
||||
|
||||
while (--numElementsToAdd >= 0)
|
||||
{
|
||||
data.elements [numUsed] = new ObjectClass (*arrayToAddFrom.getUnchecked (startIndex++));
|
||||
++numUsed;
|
||||
}
|
||||
}
|
||||
|
||||
/** Inserts a new object into the array assuming that the array is sorted.
|
||||
|
||||
This will use a comparator to find the position at which the new object
|
||||
should go. If the array isn't sorted, the behaviour of this
|
||||
method will be unpredictable.
|
||||
|
||||
@param comparator the comparator to use to compare the elements - see the sort method
|
||||
for details about this object's structure
|
||||
@param newObject the new object to insert to the array
|
||||
@returns the index at which the new object was added
|
||||
@see add, sort, indexOfSorted
|
||||
*/
|
||||
template <class ElementComparator>
|
||||
int addSorted (ElementComparator& comparator, ObjectClass* const newObject) noexcept
|
||||
{
|
||||
(void) comparator; // if you pass in an object with a static compareElements() method, this
|
||||
// avoids getting warning messages about the parameter being unused
|
||||
const ScopedLockType lock (getLock());
|
||||
const int index = findInsertIndexInSortedArray (comparator, data.elements.getData(), newObject, 0, numUsed);
|
||||
insert (index, newObject);
|
||||
return index;
|
||||
}
|
||||
|
||||
/** Finds the index of an object in the array, assuming that the array is sorted.
|
||||
|
||||
This will use a comparator to do a binary-chop to find the index of the given
|
||||
element, if it exists. If the array isn't sorted, the behaviour of this
|
||||
method will be unpredictable.
|
||||
|
||||
@param comparator the comparator to use to compare the elements - see the sort()
|
||||
method for details about the form this object should take
|
||||
@param objectToLookFor the object to search for
|
||||
@returns the index of the element, or -1 if it's not found
|
||||
@see addSorted, sort
|
||||
*/
|
||||
template <typename ElementComparator>
|
||||
int indexOfSorted (ElementComparator& comparator, const ObjectClass* const objectToLookFor) const noexcept
|
||||
{
|
||||
(void) comparator;
|
||||
const ScopedLockType lock (getLock());
|
||||
int s = 0, e = numUsed;
|
||||
|
||||
while (s < e)
|
||||
{
|
||||
if (comparator.compareElements (objectToLookFor, data.elements [s]) == 0)
|
||||
return s;
|
||||
|
||||
const int halfway = (s + e) / 2;
|
||||
if (halfway == s)
|
||||
break;
|
||||
|
||||
if (comparator.compareElements (objectToLookFor, data.elements [halfway]) >= 0)
|
||||
s = halfway;
|
||||
else
|
||||
e = halfway;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Removes an object from the array.
|
||||
|
||||
This will remove the object at a given index (optionally also
|
||||
deleting it) and move back all the subsequent objects to close the gap.
|
||||
If the index passed in is out-of-range, nothing will happen.
|
||||
|
||||
@param indexToRemove the index of the element to remove
|
||||
@param deleteObject whether to delete the object that is removed
|
||||
@see removeObject, removeRange
|
||||
*/
|
||||
void remove (const int indexToRemove,
|
||||
const bool deleteObject = true)
|
||||
{
|
||||
ObjectClass* toDelete = nullptr;
|
||||
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (isPositiveAndBelow (indexToRemove, numUsed))
|
||||
{
|
||||
ObjectClass** const e = data.elements + indexToRemove;
|
||||
|
||||
if (deleteObject)
|
||||
toDelete = *e;
|
||||
|
||||
--numUsed;
|
||||
const int numToShift = numUsed - indexToRemove;
|
||||
|
||||
if (numToShift > 0)
|
||||
memmove (e, e + 1, sizeof (ObjectClass*) * (size_t) numToShift);
|
||||
}
|
||||
}
|
||||
|
||||
delete toDelete; // don't want to use a ScopedPointer here because if the
|
||||
// object has a private destructor, both OwnedArray and
|
||||
// ScopedPointer would need to be friend classes..
|
||||
|
||||
if ((numUsed << 1) < data.numAllocated)
|
||||
minimiseStorageOverheads();
|
||||
}
|
||||
|
||||
/** Removes and returns an object from the array without deleting it.
|
||||
|
||||
This will remove the object at a given index and return it, moving back all
|
||||
the subsequent objects to close the gap. If the index passed in is out-of-range,
|
||||
nothing will happen.
|
||||
|
||||
@param indexToRemove the index of the element to remove
|
||||
@see remove, removeObject, removeRange
|
||||
*/
|
||||
ObjectClass* removeAndReturn (const int indexToRemove)
|
||||
{
|
||||
ObjectClass* removedItem = nullptr;
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (isPositiveAndBelow (indexToRemove, numUsed))
|
||||
{
|
||||
ObjectClass** const e = data.elements + indexToRemove;
|
||||
removedItem = *e;
|
||||
|
||||
--numUsed;
|
||||
const int numToShift = numUsed - indexToRemove;
|
||||
|
||||
if (numToShift > 0)
|
||||
memmove (e, e + 1, sizeof (ObjectClass*) * (size_t) numToShift);
|
||||
|
||||
if ((numUsed << 1) < data.numAllocated)
|
||||
minimiseStorageOverheads();
|
||||
}
|
||||
|
||||
return removedItem;
|
||||
}
|
||||
|
||||
/** Removes a specified object from the array.
|
||||
|
||||
If the item isn't found, no action is taken.
|
||||
|
||||
@param objectToRemove the object to try to remove
|
||||
@param deleteObject whether to delete the object (if it's found)
|
||||
@see remove, removeRange
|
||||
*/
|
||||
void removeObject (const ObjectClass* const objectToRemove,
|
||||
const bool deleteObject = true)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
ObjectClass** const e = data.elements.getData();
|
||||
|
||||
for (int i = 0; i < numUsed; ++i)
|
||||
{
|
||||
if (objectToRemove == e[i])
|
||||
{
|
||||
remove (i, deleteObject);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes a range of objects from the array.
|
||||
|
||||
This will remove a set of objects, starting from the given index,
|
||||
and move any subsequent elements down to close the gap.
|
||||
|
||||
If the range extends beyond the bounds of the array, it will
|
||||
be safely clipped to the size of the array.
|
||||
|
||||
@param startIndex the index of the first object to remove
|
||||
@param numberToRemove how many objects should be removed
|
||||
@param deleteObjects whether to delete the objects that get removed
|
||||
@see remove, removeObject
|
||||
*/
|
||||
void removeRange (int startIndex,
|
||||
const int numberToRemove,
|
||||
const bool deleteObjects = true)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
const int endIndex = blimit (0, numUsed, startIndex + numberToRemove);
|
||||
startIndex = blimit (0, numUsed, startIndex);
|
||||
|
||||
if (endIndex > startIndex)
|
||||
{
|
||||
if (deleteObjects)
|
||||
{
|
||||
for (int i = startIndex; i < endIndex; ++i)
|
||||
{
|
||||
delete data.elements [i];
|
||||
data.elements [i] = nullptr; // (in case one of the destructors accesses this array and hits a dangling pointer)
|
||||
}
|
||||
}
|
||||
|
||||
const int rangeSize = endIndex - startIndex;
|
||||
ObjectClass** e = data.elements + startIndex;
|
||||
int numToShift = numUsed - endIndex;
|
||||
numUsed -= rangeSize;
|
||||
|
||||
while (--numToShift >= 0)
|
||||
{
|
||||
*e = e [rangeSize];
|
||||
++e;
|
||||
}
|
||||
|
||||
if ((numUsed << 1) < data.numAllocated)
|
||||
minimiseStorageOverheads();
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes the last n objects from the array.
|
||||
|
||||
@param howManyToRemove how many objects to remove from the end of the array
|
||||
@param deleteObjects whether to also delete the objects that are removed
|
||||
@see remove, removeObject, removeRange
|
||||
*/
|
||||
void removeLast (int howManyToRemove = 1,
|
||||
const bool deleteObjects = true)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (howManyToRemove >= numUsed)
|
||||
clear (deleteObjects);
|
||||
else
|
||||
removeRange (numUsed - howManyToRemove, howManyToRemove, deleteObjects);
|
||||
}
|
||||
|
||||
/** Swaps a pair of objects in the array.
|
||||
|
||||
If either of the indexes passed in is out-of-range, nothing will happen,
|
||||
otherwise the two objects at these positions will be exchanged.
|
||||
*/
|
||||
void swap (const int index1,
|
||||
const int index2) noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (isPositiveAndBelow (index1, numUsed)
|
||||
&& isPositiveAndBelow (index2, numUsed))
|
||||
{
|
||||
std::swap (data.elements [index1],
|
||||
data.elements [index2]);
|
||||
}
|
||||
}
|
||||
|
||||
/** Moves one of the objects to a different position.
|
||||
|
||||
This will move the object to a specified index, shuffling along
|
||||
any intervening elements as required.
|
||||
|
||||
So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling
|
||||
move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }.
|
||||
|
||||
@param currentIndex the index of the object to be moved. If this isn't a
|
||||
valid index, then nothing will be done
|
||||
@param newIndex the index at which you'd like this object to end up. If this
|
||||
is less than zero, it will be moved to the end of the array
|
||||
*/
|
||||
void move (const int currentIndex,
|
||||
int newIndex) noexcept
|
||||
{
|
||||
if (currentIndex != newIndex)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (isPositiveAndBelow (currentIndex, numUsed))
|
||||
{
|
||||
if (! isPositiveAndBelow (newIndex, numUsed))
|
||||
newIndex = numUsed - 1;
|
||||
|
||||
ObjectClass* const value = data.elements [currentIndex];
|
||||
|
||||
if (newIndex > currentIndex)
|
||||
{
|
||||
memmove (data.elements + currentIndex,
|
||||
data.elements + currentIndex + 1,
|
||||
sizeof (ObjectClass*) * (size_t) (newIndex - currentIndex));
|
||||
}
|
||||
else
|
||||
{
|
||||
memmove (data.elements + newIndex + 1,
|
||||
data.elements + newIndex,
|
||||
sizeof (ObjectClass*) * (size_t) (currentIndex - newIndex));
|
||||
}
|
||||
|
||||
data.elements [newIndex] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** This swaps the contents of this array with those of another array.
|
||||
|
||||
If you need to exchange two arrays, this is vastly quicker than using copy-by-value
|
||||
because it just swaps their internal pointers.
|
||||
*/
|
||||
void swapWithArray (OwnedArray& otherArray) noexcept
|
||||
{
|
||||
const ScopedLockType lock1 (getLock());
|
||||
const ScopedLockType lock2 (otherArray.getLock());
|
||||
|
||||
data.swapWith (otherArray.data);
|
||||
std::swap (numUsed, otherArray.numUsed);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Reduces the amount of storage being used by the array.
|
||||
|
||||
Arrays typically allocate slightly more storage than they need, and after
|
||||
removing elements, they may have quite a lot of unused space allocated.
|
||||
This method will reduce the amount of allocated storage to a minimum.
|
||||
*/
|
||||
void minimiseStorageOverheads() noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
data.shrinkToNoMoreThan (numUsed);
|
||||
}
|
||||
|
||||
/** Increases the array's internal storage to hold a minimum number of elements.
|
||||
|
||||
Calling this before adding a large known number of elements means that
|
||||
the array won't have to keep dynamically resizing itself as the elements
|
||||
are added, and it'll therefore be more efficient.
|
||||
*/
|
||||
void ensureStorageAllocated (const int minNumElements) noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
data.ensureAllocatedSize (minNumElements);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Sorts the elements in the array.
|
||||
|
||||
This will use a comparator object to sort the elements into order. The object
|
||||
passed must have a method of the form:
|
||||
@code
|
||||
int compareElements (ElementType first, ElementType second);
|
||||
@endcode
|
||||
|
||||
..and this method must return:
|
||||
- a value of < 0 if the first comes before the second
|
||||
- a value of 0 if the two objects are equivalent
|
||||
- a value of > 0 if the second comes before the first
|
||||
|
||||
To improve performance, the compareElements() method can be declared as static or const.
|
||||
|
||||
@param comparator the comparator to use for comparing elements.
|
||||
@param retainOrderOfEquivalentItems if this is true, then items
|
||||
which the comparator says are equivalent will be
|
||||
kept in the order in which they currently appear
|
||||
in the array. This is slower to perform, but may
|
||||
be important in some cases. If it's false, a faster
|
||||
algorithm is used, but equivalent elements may be
|
||||
rearranged.
|
||||
@see sortArray, indexOfSorted
|
||||
*/
|
||||
template <class ElementComparator>
|
||||
void sort (ElementComparator& comparator,
|
||||
const bool retainOrderOfEquivalentItems = false) const noexcept
|
||||
{
|
||||
(void) comparator; // if you pass in an object with a static compareElements() method, this
|
||||
// avoids getting warning messages about the parameter being unused
|
||||
|
||||
const ScopedLockType lock (getLock());
|
||||
sortArray (comparator, data.elements.getData(), 0, size() - 1, retainOrderOfEquivalentItems);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the CriticalSection that locks this array.
|
||||
To lock, you can call getLock().enter() and getLock().exit(), or preferably use
|
||||
an object of ScopedLockType as an RAII lock for it.
|
||||
*/
|
||||
inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return data; }
|
||||
|
||||
/** Returns the type of scoped lock to use for locking this array */
|
||||
typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
|
||||
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
ArrayAllocationBase <ObjectClass*, TypeOfCriticalSectionToUse> data;
|
||||
int numUsed;
|
||||
|
||||
void deleteAllObjects()
|
||||
{
|
||||
while (numUsed > 0)
|
||||
delete data.elements [--numUsed];
|
||||
}
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OwnedArray)
|
||||
};
|
||||
|
||||
|
||||
#endif // BEAST_OWNEDARRAY_BEASTHEADER
|
||||
218
modules/beast_core/containers/beast_PropertySet.cpp
Normal file
218
modules/beast_core/containers/beast_PropertySet.cpp
Normal file
@@ -0,0 +1,218 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
PropertySet::PropertySet (const bool ignoreCaseOfKeyNames)
|
||||
: properties (ignoreCaseOfKeyNames),
|
||||
fallbackProperties (nullptr),
|
||||
ignoreCaseOfKeys (ignoreCaseOfKeyNames)
|
||||
{
|
||||
}
|
||||
|
||||
PropertySet::PropertySet (const PropertySet& other)
|
||||
: properties (other.properties),
|
||||
fallbackProperties (other.fallbackProperties),
|
||||
ignoreCaseOfKeys (other.ignoreCaseOfKeys)
|
||||
{
|
||||
}
|
||||
|
||||
PropertySet& PropertySet::operator= (const PropertySet& other)
|
||||
{
|
||||
properties = other.properties;
|
||||
fallbackProperties = other.fallbackProperties;
|
||||
ignoreCaseOfKeys = other.ignoreCaseOfKeys;
|
||||
|
||||
propertyChanged();
|
||||
return *this;
|
||||
}
|
||||
|
||||
PropertySet::~PropertySet()
|
||||
{
|
||||
}
|
||||
|
||||
void PropertySet::clear()
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
|
||||
if (properties.size() > 0)
|
||||
{
|
||||
properties.clear();
|
||||
propertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
String PropertySet::getValue (const String& keyName,
|
||||
const String& defaultValue) const noexcept
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
|
||||
const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
|
||||
|
||||
if (index >= 0)
|
||||
return properties.getAllValues() [index];
|
||||
|
||||
return fallbackProperties != nullptr ? fallbackProperties->getValue (keyName, defaultValue)
|
||||
: defaultValue;
|
||||
}
|
||||
|
||||
int PropertySet::getIntValue (const String& keyName,
|
||||
const int defaultValue) const noexcept
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
|
||||
|
||||
if (index >= 0)
|
||||
return properties.getAllValues() [index].getIntValue();
|
||||
|
||||
return fallbackProperties != nullptr ? fallbackProperties->getIntValue (keyName, defaultValue)
|
||||
: defaultValue;
|
||||
}
|
||||
|
||||
double PropertySet::getDoubleValue (const String& keyName,
|
||||
const double defaultValue) const noexcept
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
|
||||
|
||||
if (index >= 0)
|
||||
return properties.getAllValues()[index].getDoubleValue();
|
||||
|
||||
return fallbackProperties != nullptr ? fallbackProperties->getDoubleValue (keyName, defaultValue)
|
||||
: defaultValue;
|
||||
}
|
||||
|
||||
bool PropertySet::getBoolValue (const String& keyName,
|
||||
const bool defaultValue) const noexcept
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
|
||||
|
||||
if (index >= 0)
|
||||
return properties.getAllValues() [index].getIntValue() != 0;
|
||||
|
||||
return fallbackProperties != nullptr ? fallbackProperties->getBoolValue (keyName, defaultValue)
|
||||
: defaultValue;
|
||||
}
|
||||
|
||||
XmlElement* PropertySet::getXmlValue (const String& keyName) const
|
||||
{
|
||||
return XmlDocument::parse (getValue (keyName));
|
||||
}
|
||||
|
||||
void PropertySet::setValue (const String& keyName, const var& v)
|
||||
{
|
||||
bassert (keyName.isNotEmpty()); // shouldn't use an empty key name!
|
||||
|
||||
if (keyName.isNotEmpty())
|
||||
{
|
||||
const String value (v.toString());
|
||||
const ScopedLock sl (lock);
|
||||
|
||||
const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
|
||||
|
||||
if (index < 0 || properties.getAllValues() [index] != value)
|
||||
{
|
||||
properties.set (keyName, value);
|
||||
propertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PropertySet::removeValue (const String& keyName)
|
||||
{
|
||||
if (keyName.isNotEmpty())
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
properties.remove (keyName);
|
||||
propertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PropertySet::setValue (const String& keyName, const XmlElement* const xml)
|
||||
{
|
||||
setValue (keyName, xml == nullptr ? var::null
|
||||
: var (xml->createDocument (String::empty, true)));
|
||||
}
|
||||
|
||||
bool PropertySet::containsKey (const String& keyName) const noexcept
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
return properties.getAllKeys().contains (keyName, ignoreCaseOfKeys);
|
||||
}
|
||||
|
||||
void PropertySet::addAllPropertiesFrom (const PropertySet& source)
|
||||
{
|
||||
const ScopedLock sl (source.getLock());
|
||||
|
||||
for (int i = 0; i < source.properties.size(); ++i)
|
||||
setValue (source.properties.getAllKeys() [i],
|
||||
source.properties.getAllValues() [i]);
|
||||
}
|
||||
|
||||
void PropertySet::setFallbackPropertySet (PropertySet* fallbackProperties_) noexcept
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
fallbackProperties = fallbackProperties_;
|
||||
}
|
||||
|
||||
XmlElement* PropertySet::createXml (const String& nodeName) const
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
XmlElement* const xml = new XmlElement (nodeName);
|
||||
|
||||
for (int i = 0; i < properties.getAllKeys().size(); ++i)
|
||||
{
|
||||
XmlElement* const e = xml->createNewChildElement ("VALUE");
|
||||
e->setAttribute ("name", properties.getAllKeys()[i]);
|
||||
e->setAttribute ("val", properties.getAllValues()[i]);
|
||||
}
|
||||
|
||||
return xml;
|
||||
}
|
||||
|
||||
void PropertySet::restoreFromXml (const XmlElement& xml)
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
clear();
|
||||
|
||||
forEachXmlChildElementWithTagName (xml, e, "VALUE")
|
||||
{
|
||||
if (e->hasAttribute ("name")
|
||||
&& e->hasAttribute ("val"))
|
||||
{
|
||||
properties.set (e->getStringAttribute ("name"),
|
||||
e->getStringAttribute ("val"));
|
||||
}
|
||||
}
|
||||
|
||||
if (properties.size() > 0)
|
||||
propertyChanged();
|
||||
}
|
||||
|
||||
void PropertySet::propertyChanged()
|
||||
{
|
||||
}
|
||||
214
modules/beast_core/containers/beast_PropertySet.h
Normal file
214
modules/beast_core/containers/beast_PropertySet.h
Normal file
@@ -0,0 +1,214 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_PROPERTYSET_BEASTHEADER
|
||||
#define BEAST_PROPERTYSET_BEASTHEADER
|
||||
|
||||
#include "../text/beast_StringPairArray.h"
|
||||
#include "../xml/beast_XmlElement.h"
|
||||
#include "../containers/beast_Variant.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A set of named property values, which can be strings, integers, floating point, etc.
|
||||
|
||||
Effectively, this just wraps a StringPairArray in an interface that makes it easier
|
||||
to load and save types other than strings.
|
||||
|
||||
See the PropertiesFile class for a subclass of this, which automatically broadcasts change
|
||||
messages and saves/loads the list from a file.
|
||||
*/
|
||||
class BEAST_API PropertySet
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an empty PropertySet.
|
||||
@param ignoreCaseOfKeyNames if true, the names of properties are compared in a
|
||||
case-insensitive way
|
||||
*/
|
||||
PropertySet (bool ignoreCaseOfKeyNames = false);
|
||||
|
||||
/** Creates a copy of another PropertySet. */
|
||||
PropertySet (const PropertySet& other);
|
||||
|
||||
/** Copies another PropertySet over this one. */
|
||||
PropertySet& operator= (const PropertySet& other);
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~PropertySet();
|
||||
|
||||
//==============================================================================
|
||||
/** Returns one of the properties as a string.
|
||||
|
||||
If the value isn't found in this set, then this will look for it in a fallback
|
||||
property set (if you've specified one with the setFallbackPropertySet() method),
|
||||
and if it can't find one there, it'll return the default value passed-in.
|
||||
|
||||
@param keyName the name of the property to retrieve
|
||||
@param defaultReturnValue a value to return if the named property doesn't actually exist
|
||||
*/
|
||||
String getValue (const String& keyName,
|
||||
const String& defaultReturnValue = String::empty) const noexcept;
|
||||
|
||||
/** Returns one of the properties as an integer.
|
||||
|
||||
If the value isn't found in this set, then this will look for it in a fallback
|
||||
property set (if you've specified one with the setFallbackPropertySet() method),
|
||||
and if it can't find one there, it'll return the default value passed-in.
|
||||
|
||||
@param keyName the name of the property to retrieve
|
||||
@param defaultReturnValue a value to return if the named property doesn't actually exist
|
||||
*/
|
||||
int getIntValue (const String& keyName,
|
||||
const int defaultReturnValue = 0) const noexcept;
|
||||
|
||||
/** Returns one of the properties as an double.
|
||||
|
||||
If the value isn't found in this set, then this will look for it in a fallback
|
||||
property set (if you've specified one with the setFallbackPropertySet() method),
|
||||
and if it can't find one there, it'll return the default value passed-in.
|
||||
|
||||
@param keyName the name of the property to retrieve
|
||||
@param defaultReturnValue a value to return if the named property doesn't actually exist
|
||||
*/
|
||||
double getDoubleValue (const String& keyName,
|
||||
const double defaultReturnValue = 0.0) const noexcept;
|
||||
|
||||
/** Returns one of the properties as an boolean.
|
||||
|
||||
The result will be true if the string found for this key name can be parsed as a non-zero
|
||||
integer.
|
||||
|
||||
If the value isn't found in this set, then this will look for it in a fallback
|
||||
property set (if you've specified one with the setFallbackPropertySet() method),
|
||||
and if it can't find one there, it'll return the default value passed-in.
|
||||
|
||||
@param keyName the name of the property to retrieve
|
||||
@param defaultReturnValue a value to return if the named property doesn't actually exist
|
||||
*/
|
||||
bool getBoolValue (const String& keyName,
|
||||
const bool defaultReturnValue = false) const noexcept;
|
||||
|
||||
/** Returns one of the properties as an XML element.
|
||||
|
||||
The result will a new XMLElement object that the caller must delete. If may return 0 if the
|
||||
key isn't found, or if the entry contains an string that isn't valid XML.
|
||||
|
||||
If the value isn't found in this set, then this will look for it in a fallback
|
||||
property set (if you've specified one with the setFallbackPropertySet() method),
|
||||
and if it can't find one there, it'll return the default value passed-in.
|
||||
|
||||
@param keyName the name of the property to retrieve
|
||||
*/
|
||||
XmlElement* getXmlValue (const String& keyName) const;
|
||||
|
||||
//==============================================================================
|
||||
/** Sets a named property.
|
||||
|
||||
@param keyName the name of the property to set. (This mustn't be an empty string)
|
||||
@param value the new value to set it to
|
||||
*/
|
||||
void setValue (const String& keyName, const var& value);
|
||||
|
||||
/** Sets a named property to an XML element.
|
||||
|
||||
@param keyName the name of the property to set. (This mustn't be an empty string)
|
||||
@param xml the new element to set it to. If this is zero, the value will be set to
|
||||
an empty string
|
||||
@see getXmlValue
|
||||
*/
|
||||
void setValue (const String& keyName, const XmlElement* xml);
|
||||
|
||||
/** This copies all the values from a source PropertySet to this one.
|
||||
This won't remove any existing settings, it just adds any that it finds in the source set.
|
||||
*/
|
||||
void addAllPropertiesFrom (const PropertySet& source);
|
||||
|
||||
//==============================================================================
|
||||
/** Deletes a property.
|
||||
@param keyName the name of the property to delete. (This mustn't be an empty string)
|
||||
*/
|
||||
void removeValue (const String& keyName);
|
||||
|
||||
/** Returns true if the properies include the given key. */
|
||||
bool containsKey (const String& keyName) const noexcept;
|
||||
|
||||
/** Removes all values. */
|
||||
void clear();
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the keys/value pair array containing all the properties. */
|
||||
StringPairArray& getAllProperties() noexcept { return properties; }
|
||||
|
||||
/** Returns the lock used when reading or writing to this set */
|
||||
const CriticalSection& getLock() const noexcept { return lock; }
|
||||
|
||||
//==============================================================================
|
||||
/** Returns an XML element which encapsulates all the items in this property set.
|
||||
The string parameter is the tag name that should be used for the node.
|
||||
@see restoreFromXml
|
||||
*/
|
||||
XmlElement* createXml (const String& nodeName) const;
|
||||
|
||||
/** Reloads a set of properties that were previously stored as XML.
|
||||
The node passed in must have been created by the createXml() method.
|
||||
@see createXml
|
||||
*/
|
||||
void restoreFromXml (const XmlElement& xml);
|
||||
|
||||
//==============================================================================
|
||||
/** Sets up a second PopertySet that will be used to look up any values that aren't
|
||||
set in this one.
|
||||
|
||||
If you set this up to be a pointer to a second property set, then whenever one
|
||||
of the getValue() methods fails to find an entry in this set, it will look up that
|
||||
value in the fallback set, and if it finds it, it will return that.
|
||||
|
||||
Make sure that you don't delete the fallback set while it's still being used by
|
||||
another set! To remove the fallback set, just call this method with a null pointer.
|
||||
|
||||
@see getFallbackPropertySet
|
||||
*/
|
||||
void setFallbackPropertySet (PropertySet* fallbackProperties) noexcept;
|
||||
|
||||
/** Returns the fallback property set.
|
||||
@see setFallbackPropertySet
|
||||
*/
|
||||
PropertySet* getFallbackPropertySet() const noexcept { return fallbackProperties; }
|
||||
|
||||
protected:
|
||||
/** Subclasses can override this to be told when one of the properies has been changed. */
|
||||
virtual void propertyChanged();
|
||||
|
||||
private:
|
||||
StringPairArray properties;
|
||||
PropertySet* fallbackProperties;
|
||||
CriticalSection lock;
|
||||
bool ignoreCaseOfKeys;
|
||||
|
||||
BEAST_LEAK_DETECTOR (PropertySet)
|
||||
};
|
||||
|
||||
|
||||
#endif // BEAST_PROPERTYSET_BEASTHEADER
|
||||
855
modules/beast_core/containers/beast_ReferenceCountedArray.h
Normal file
855
modules/beast_core/containers/beast_ReferenceCountedArray.h
Normal file
@@ -0,0 +1,855 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_REFERENCECOUNTEDARRAY_BEASTHEADER
|
||||
#define BEAST_REFERENCECOUNTEDARRAY_BEASTHEADER
|
||||
|
||||
#include "../memory/beast_ReferenceCountedObject.h"
|
||||
#include "beast_ArrayAllocationBase.h"
|
||||
#include "beast_ElementComparator.h"
|
||||
#include "../threads/beast_CriticalSection.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Holds a list of objects derived from ReferenceCountedObject.
|
||||
|
||||
A ReferenceCountedArray holds objects derived from ReferenceCountedObject,
|
||||
and takes care of incrementing and decrementing their ref counts when they
|
||||
are added and removed from the array.
|
||||
|
||||
To make all the array's methods thread-safe, pass in "CriticalSection" as the templated
|
||||
TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection.
|
||||
|
||||
@see Array, OwnedArray, StringArray
|
||||
*/
|
||||
template <class ObjectClass, class TypeOfCriticalSectionToUse = DummyCriticalSection>
|
||||
class ReferenceCountedArray
|
||||
{
|
||||
public:
|
||||
typedef ReferenceCountedObjectPtr<ObjectClass> ObjectClassPtr;
|
||||
|
||||
//==============================================================================
|
||||
/** Creates an empty array.
|
||||
@see ReferenceCountedObject, Array, OwnedArray
|
||||
*/
|
||||
ReferenceCountedArray() noexcept
|
||||
: numUsed (0)
|
||||
{
|
||||
}
|
||||
|
||||
/** Creates a copy of another array */
|
||||
ReferenceCountedArray (const ReferenceCountedArray& other) noexcept
|
||||
{
|
||||
const ScopedLockType lock (other.getLock());
|
||||
numUsed = other.size();
|
||||
data.setAllocatedSize (numUsed);
|
||||
memcpy (data.elements, other.getRawDataPointer(), numUsed * sizeof (ObjectClass*));
|
||||
|
||||
for (int i = numUsed; --i >= 0;)
|
||||
if (ObjectClass* o = data.elements[i])
|
||||
o->incReferenceCount();
|
||||
}
|
||||
|
||||
/** Creates a copy of another array */
|
||||
template <class OtherObjectClass, class OtherCriticalSection>
|
||||
ReferenceCountedArray (const ReferenceCountedArray<OtherObjectClass, OtherCriticalSection>& other) noexcept
|
||||
{
|
||||
const typename ReferenceCountedArray<OtherObjectClass, OtherCriticalSection>::ScopedLockType lock (other.getLock());
|
||||
numUsed = other.size();
|
||||
data.setAllocatedSize (numUsed);
|
||||
memcpy (data.elements, other.getRawDataPointer(), numUsed * sizeof (ObjectClass*));
|
||||
|
||||
for (int i = numUsed; --i >= 0;)
|
||||
if (ObjectClass* o = data.elements[i])
|
||||
o->incReferenceCount();
|
||||
}
|
||||
|
||||
/** Copies another array into this one.
|
||||
Any existing objects in this array will first be released.
|
||||
*/
|
||||
ReferenceCountedArray& operator= (const ReferenceCountedArray& other) noexcept
|
||||
{
|
||||
ReferenceCountedArray otherCopy (other);
|
||||
swapWithArray (otherCopy);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Copies another array into this one.
|
||||
Any existing objects in this array will first be released.
|
||||
*/
|
||||
template <class OtherObjectClass>
|
||||
ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& operator= (const ReferenceCountedArray<OtherObjectClass, TypeOfCriticalSectionToUse>& other) noexcept
|
||||
{
|
||||
ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse> otherCopy (other);
|
||||
swapWithArray (otherCopy);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Destructor.
|
||||
Any objects in the array will be released, and may be deleted if not referenced from elsewhere.
|
||||
*/
|
||||
~ReferenceCountedArray()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Removes all objects from the array.
|
||||
|
||||
Any objects in the array that are not referenced from elsewhere will be deleted.
|
||||
*/
|
||||
void clear()
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
while (numUsed > 0)
|
||||
if (ObjectClass* o = data.elements [--numUsed])
|
||||
o->decReferenceCount();
|
||||
|
||||
bassert (numUsed == 0);
|
||||
data.setAllocatedSize (0);
|
||||
}
|
||||
|
||||
/** Returns the current number of objects in the array. */
|
||||
inline int size() const noexcept
|
||||
{
|
||||
return numUsed;
|
||||
}
|
||||
|
||||
/** Returns a pointer to the object at this index in the array.
|
||||
|
||||
If the index is out-of-range, this will return a null pointer, (and
|
||||
it could be null anyway, because it's ok for the array to hold null
|
||||
pointers as well as objects).
|
||||
|
||||
@see getUnchecked
|
||||
*/
|
||||
inline ObjectClassPtr operator[] (const int index) const noexcept
|
||||
{
|
||||
return getObjectPointer (index);
|
||||
}
|
||||
|
||||
/** Returns a pointer to the object at this index in the array, without checking
|
||||
whether the index is in-range.
|
||||
|
||||
This is a faster and less safe version of operator[] which doesn't check the index passed in, so
|
||||
it can be used when you're sure the index is always going to be legal.
|
||||
*/
|
||||
inline ObjectClassPtr getUnchecked (const int index) const noexcept
|
||||
{
|
||||
return getObjectPointerUnchecked (index);
|
||||
}
|
||||
|
||||
/** Returns a raw pointer to the object at this index in the array.
|
||||
|
||||
If the index is out-of-range, this will return a null pointer, (and
|
||||
it could be null anyway, because it's ok for the array to hold null
|
||||
pointers as well as objects).
|
||||
|
||||
@see getUnchecked
|
||||
*/
|
||||
inline ObjectClass* getObjectPointer (const int index) const noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
return isPositiveAndBelow (index, numUsed) ? data.elements [index]
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
/** Returns a raw pointer to the object at this index in the array, without checking
|
||||
whether the index is in-range.
|
||||
*/
|
||||
inline ObjectClass* getObjectPointerUnchecked (const int index) const noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
bassert (isPositiveAndBelow (index, numUsed));
|
||||
return data.elements [index];
|
||||
}
|
||||
|
||||
/** Returns a pointer to the first object in the array.
|
||||
|
||||
This will return a null pointer if the array's empty.
|
||||
@see getLast
|
||||
*/
|
||||
inline ObjectClassPtr getFirst() const noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
return numUsed > 0 ? data.elements [0]
|
||||
: static_cast <ObjectClass*> (nullptr);
|
||||
}
|
||||
|
||||
/** Returns a pointer to the last object in the array.
|
||||
|
||||
This will return a null pointer if the array's empty.
|
||||
@see getFirst
|
||||
*/
|
||||
inline ObjectClassPtr getLast() const noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
return numUsed > 0 ? data.elements [numUsed - 1]
|
||||
: static_cast <ObjectClass*> (nullptr);
|
||||
}
|
||||
|
||||
/** Returns a pointer to the actual array data.
|
||||
This pointer will only be valid until the next time a non-const method
|
||||
is called on the array.
|
||||
*/
|
||||
inline ObjectClass** getRawDataPointer() const noexcept
|
||||
{
|
||||
return data.elements;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a pointer to the first element in the array.
|
||||
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||
*/
|
||||
inline ObjectClass** begin() const noexcept
|
||||
{
|
||||
return data.elements;
|
||||
}
|
||||
|
||||
/** Returns a pointer to the element which follows the last element in the array.
|
||||
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||
*/
|
||||
inline ObjectClass** end() const noexcept
|
||||
{
|
||||
return data.elements + numUsed;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Finds the index of the first occurrence of an object in the array.
|
||||
|
||||
@param objectToLookFor the object to look for
|
||||
@returns the index at which the object was found, or -1 if it's not found
|
||||
*/
|
||||
int indexOf (const ObjectClass* const objectToLookFor) const noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
ObjectClass** e = data.elements.getData();
|
||||
ObjectClass** const endPointer = e + numUsed;
|
||||
|
||||
while (e != endPointer)
|
||||
{
|
||||
if (objectToLookFor == *e)
|
||||
return static_cast <int> (e - data.elements.getData());
|
||||
|
||||
++e;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Returns true if the array contains a specified object.
|
||||
|
||||
@param objectToLookFor the object to look for
|
||||
@returns true if the object is in the array
|
||||
*/
|
||||
bool contains (const ObjectClass* const objectToLookFor) const noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
ObjectClass** e = data.elements.getData();
|
||||
ObjectClass** const endPointer = e + numUsed;
|
||||
|
||||
while (e != endPointer)
|
||||
{
|
||||
if (objectToLookFor == *e)
|
||||
return true;
|
||||
|
||||
++e;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Appends a new object to the end of the array.
|
||||
|
||||
This will increase the new object's reference count.
|
||||
|
||||
@param newObject the new object to add to the array
|
||||
@see set, insert, addIfNotAlreadyThere, addSorted, addArray
|
||||
*/
|
||||
void add (ObjectClass* const newObject) noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
data.ensureAllocatedSize (numUsed + 1);
|
||||
data.elements [numUsed++] = newObject;
|
||||
|
||||
if (newObject != nullptr)
|
||||
newObject->incReferenceCount();
|
||||
}
|
||||
|
||||
/** Inserts a new object into the array at the given index.
|
||||
|
||||
If the index is less than 0 or greater than the size of the array, the
|
||||
element will be added to the end of the array.
|
||||
Otherwise, it will be inserted into the array, moving all the later elements
|
||||
along to make room.
|
||||
|
||||
This will increase the new object's reference count.
|
||||
|
||||
@param indexToInsertAt the index at which the new element should be inserted
|
||||
@param newObject the new object to add to the array
|
||||
@see add, addSorted, addIfNotAlreadyThere, set
|
||||
*/
|
||||
void insert (int indexToInsertAt,
|
||||
ObjectClass* const newObject) noexcept
|
||||
{
|
||||
if (indexToInsertAt >= 0)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (indexToInsertAt > numUsed)
|
||||
indexToInsertAt = numUsed;
|
||||
|
||||
data.ensureAllocatedSize (numUsed + 1);
|
||||
|
||||
ObjectClass** const e = data.elements + indexToInsertAt;
|
||||
const int numToMove = numUsed - indexToInsertAt;
|
||||
|
||||
if (numToMove > 0)
|
||||
memmove (e + 1, e, sizeof (ObjectClass*) * (size_t) numToMove);
|
||||
|
||||
*e = newObject;
|
||||
|
||||
if (newObject != nullptr)
|
||||
newObject->incReferenceCount();
|
||||
|
||||
++numUsed;
|
||||
}
|
||||
else
|
||||
{
|
||||
add (newObject);
|
||||
}
|
||||
}
|
||||
|
||||
/** Appends a new object at the end of the array as long as the array doesn't
|
||||
already contain it.
|
||||
|
||||
If the array already contains a matching object, nothing will be done.
|
||||
|
||||
@param newObject the new object to add to the array
|
||||
*/
|
||||
void addIfNotAlreadyThere (ObjectClass* const newObject) noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
if (! contains (newObject))
|
||||
add (newObject);
|
||||
}
|
||||
|
||||
/** Replaces an object in the array with a different one.
|
||||
|
||||
If the index is less than zero, this method does nothing.
|
||||
If the index is beyond the end of the array, the new object is added to the end of the array.
|
||||
|
||||
The object being added has its reference count increased, and if it's replacing
|
||||
another object, then that one has its reference count decreased, and may be deleted.
|
||||
|
||||
@param indexToChange the index whose value you want to change
|
||||
@param newObject the new value to set for this index.
|
||||
@see add, insert, remove
|
||||
*/
|
||||
void set (const int indexToChange,
|
||||
ObjectClass* const newObject)
|
||||
{
|
||||
if (indexToChange >= 0)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (newObject != nullptr)
|
||||
newObject->incReferenceCount();
|
||||
|
||||
if (indexToChange < numUsed)
|
||||
{
|
||||
if (ObjectClass* o = data.elements [indexToChange])
|
||||
o->decReferenceCount();
|
||||
|
||||
data.elements [indexToChange] = newObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
data.ensureAllocatedSize (numUsed + 1);
|
||||
data.elements [numUsed++] = newObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Adds elements from another array to the end of this array.
|
||||
|
||||
@param arrayToAddFrom the array from which to copy the elements
|
||||
@param startIndex the first element of the other array to start copying from
|
||||
@param numElementsToAdd how many elements to add from the other array. If this
|
||||
value is negative or greater than the number of available elements,
|
||||
all available elements will be copied.
|
||||
@see add
|
||||
*/
|
||||
void addArray (const ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& arrayToAddFrom,
|
||||
int startIndex = 0,
|
||||
int numElementsToAdd = -1) noexcept
|
||||
{
|
||||
const ScopedLockType lock1 (arrayToAddFrom.getLock());
|
||||
|
||||
{
|
||||
const ScopedLockType lock2 (getLock());
|
||||
|
||||
if (startIndex < 0)
|
||||
{
|
||||
jassertfalse;
|
||||
startIndex = 0;
|
||||
}
|
||||
|
||||
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size())
|
||||
numElementsToAdd = arrayToAddFrom.size() - startIndex;
|
||||
|
||||
if (numElementsToAdd > 0)
|
||||
{
|
||||
data.ensureAllocatedSize (numUsed + numElementsToAdd);
|
||||
|
||||
while (--numElementsToAdd >= 0)
|
||||
add (arrayToAddFrom.getUnchecked (startIndex++));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Inserts a new object into the array assuming that the array is sorted.
|
||||
|
||||
This will use a comparator to find the position at which the new object
|
||||
should go. If the array isn't sorted, the behaviour of this
|
||||
method will be unpredictable.
|
||||
|
||||
@param comparator the comparator object to use to compare the elements - see the
|
||||
sort() method for details about this object's form
|
||||
@param newObject the new object to insert to the array
|
||||
@returns the index at which the new object was added
|
||||
@see add, sort
|
||||
*/
|
||||
template <class ElementComparator>
|
||||
int addSorted (ElementComparator& comparator, ObjectClass* newObject) noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
const int index = findInsertIndexInSortedArray (comparator, data.elements.getData(), newObject, 0, numUsed);
|
||||
insert (index, newObject);
|
||||
return index;
|
||||
}
|
||||
|
||||
/** Inserts or replaces an object in the array, assuming it is sorted.
|
||||
|
||||
This is similar to addSorted, but if a matching element already exists, then it will be
|
||||
replaced by the new one, rather than the new one being added as well.
|
||||
*/
|
||||
template <class ElementComparator>
|
||||
void addOrReplaceSorted (ElementComparator& comparator,
|
||||
ObjectClass* newObject) noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
const int index = findInsertIndexInSortedArray (comparator, data.elements.getData(), newObject, 0, numUsed);
|
||||
|
||||
if (index > 0 && comparator.compareElements (newObject, data.elements [index - 1]) == 0)
|
||||
set (index - 1, newObject); // replace an existing object that matches
|
||||
else
|
||||
insert (index, newObject); // no match, so insert the new one
|
||||
}
|
||||
|
||||
/** Finds the index of an object in the array, assuming that the array is sorted.
|
||||
|
||||
This will use a comparator to do a binary-chop to find the index of the given
|
||||
element, if it exists. If the array isn't sorted, the behaviour of this
|
||||
method will be unpredictable.
|
||||
|
||||
@param comparator the comparator to use to compare the elements - see the sort()
|
||||
method for details about the form this object should take
|
||||
@param objectToLookFor the object to search for
|
||||
@returns the index of the element, or -1 if it's not found
|
||||
@see addSorted, sort
|
||||
*/
|
||||
template <class ElementComparator>
|
||||
int indexOfSorted (ElementComparator& comparator,
|
||||
const ObjectClass* const objectToLookFor) const noexcept
|
||||
{
|
||||
(void) comparator;
|
||||
const ScopedLockType lock (getLock());
|
||||
int s = 0, e = numUsed;
|
||||
|
||||
while (s < e)
|
||||
{
|
||||
if (comparator.compareElements (objectToLookFor, data.elements [s]) == 0)
|
||||
return s;
|
||||
|
||||
const int halfway = (s + e) / 2;
|
||||
if (halfway == s)
|
||||
break;
|
||||
|
||||
if (comparator.compareElements (objectToLookFor, data.elements [halfway]) >= 0)
|
||||
s = halfway;
|
||||
else
|
||||
e = halfway;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Removes an object from the array.
|
||||
|
||||
This will remove the object at a given index and move back all the
|
||||
subsequent objects to close the gap.
|
||||
|
||||
If the index passed in is out-of-range, nothing will happen.
|
||||
|
||||
The object that is removed will have its reference count decreased,
|
||||
and may be deleted if not referenced from elsewhere.
|
||||
|
||||
@param indexToRemove the index of the element to remove
|
||||
@see removeObject, removeRange
|
||||
*/
|
||||
void remove (const int indexToRemove)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (isPositiveAndBelow (indexToRemove, numUsed))
|
||||
{
|
||||
ObjectClass** const e = data.elements + indexToRemove;
|
||||
|
||||
if (ObjectClass* o = *e)
|
||||
o->decReferenceCount();
|
||||
|
||||
--numUsed;
|
||||
const int numberToShift = numUsed - indexToRemove;
|
||||
|
||||
if (numberToShift > 0)
|
||||
memmove (e, e + 1, sizeof (ObjectClass*) * (size_t) numberToShift);
|
||||
|
||||
if ((numUsed << 1) < data.numAllocated)
|
||||
minimiseStorageOverheads();
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes and returns an object from the array.
|
||||
|
||||
This will remove the object at a given index and return it, moving back all
|
||||
the subsequent objects to close the gap. If the index passed in is out-of-range,
|
||||
nothing will happen and a null pointer will be returned.
|
||||
|
||||
@param indexToRemove the index of the element to remove
|
||||
@see remove, removeObject, removeRange
|
||||
*/
|
||||
ObjectClassPtr removeAndReturn (const int indexToRemove)
|
||||
{
|
||||
ObjectClassPtr removedItem;
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (isPositiveAndBelow (indexToRemove, numUsed))
|
||||
{
|
||||
ObjectClass** const e = data.elements + indexToRemove;
|
||||
|
||||
if (ObjectClass* o = *e)
|
||||
{
|
||||
removedItem = o;
|
||||
o->decReferenceCount();
|
||||
}
|
||||
|
||||
--numUsed;
|
||||
const int numberToShift = numUsed - indexToRemove;
|
||||
|
||||
if (numberToShift > 0)
|
||||
memmove (e, e + 1, sizeof (ObjectClass*) * (size_t) numberToShift);
|
||||
|
||||
if ((numUsed << 1) < data.numAllocated)
|
||||
minimiseStorageOverheads();
|
||||
}
|
||||
|
||||
return removedItem;
|
||||
}
|
||||
|
||||
/** Removes the first occurrence of a specified object from the array.
|
||||
|
||||
If the item isn't found, no action is taken. If it is found, it is
|
||||
removed and has its reference count decreased.
|
||||
|
||||
@param objectToRemove the object to try to remove
|
||||
@see remove, removeRange
|
||||
*/
|
||||
void removeObject (ObjectClass* const objectToRemove)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
remove (indexOf (objectToRemove));
|
||||
}
|
||||
|
||||
/** Removes a range of objects from the array.
|
||||
|
||||
This will remove a set of objects, starting from the given index,
|
||||
and move any subsequent elements down to close the gap.
|
||||
|
||||
If the range extends beyond the bounds of the array, it will
|
||||
be safely clipped to the size of the array.
|
||||
|
||||
The objects that are removed will have their reference counts decreased,
|
||||
and may be deleted if not referenced from elsewhere.
|
||||
|
||||
@param startIndex the index of the first object to remove
|
||||
@param numberToRemove how many objects should be removed
|
||||
@see remove, removeObject
|
||||
*/
|
||||
void removeRange (const int startIndex,
|
||||
const int numberToRemove)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
const int start = blimit (0, numUsed, startIndex);
|
||||
const int endIndex = blimit (0, numUsed, startIndex + numberToRemove);
|
||||
|
||||
if (endIndex > start)
|
||||
{
|
||||
int i;
|
||||
for (i = start; i < endIndex; ++i)
|
||||
{
|
||||
if (ObjectClass* o = data.elements[i])
|
||||
{
|
||||
o->decReferenceCount();
|
||||
data.elements[i] = nullptr; // (in case one of the destructors accesses this array and hits a dangling pointer)
|
||||
}
|
||||
}
|
||||
|
||||
const int rangeSize = endIndex - start;
|
||||
ObjectClass** e = data.elements + start;
|
||||
i = numUsed - endIndex;
|
||||
numUsed -= rangeSize;
|
||||
|
||||
while (--i >= 0)
|
||||
{
|
||||
*e = e [rangeSize];
|
||||
++e;
|
||||
}
|
||||
|
||||
if ((numUsed << 1) < data.numAllocated)
|
||||
minimiseStorageOverheads();
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes the last n objects from the array.
|
||||
|
||||
The objects that are removed will have their reference counts decreased,
|
||||
and may be deleted if not referenced from elsewhere.
|
||||
|
||||
@param howManyToRemove how many objects to remove from the end of the array
|
||||
@see remove, removeObject, removeRange
|
||||
*/
|
||||
void removeLast (int howManyToRemove = 1)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (howManyToRemove > numUsed)
|
||||
howManyToRemove = numUsed;
|
||||
|
||||
while (--howManyToRemove >= 0)
|
||||
remove (numUsed - 1);
|
||||
}
|
||||
|
||||
/** Swaps a pair of objects in the array.
|
||||
|
||||
If either of the indexes passed in is out-of-range, nothing will happen,
|
||||
otherwise the two objects at these positions will be exchanged.
|
||||
*/
|
||||
void swap (const int index1,
|
||||
const int index2) noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (isPositiveAndBelow (index1, numUsed)
|
||||
&& isPositiveAndBelow (index2, numUsed))
|
||||
{
|
||||
std::swap (data.elements [index1],
|
||||
data.elements [index2]);
|
||||
}
|
||||
}
|
||||
|
||||
/** Moves one of the objects to a different position.
|
||||
|
||||
This will move the object to a specified index, shuffling along
|
||||
any intervening elements as required.
|
||||
|
||||
So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling
|
||||
move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }.
|
||||
|
||||
@param currentIndex the index of the object to be moved. If this isn't a
|
||||
valid index, then nothing will be done
|
||||
@param newIndex the index at which you'd like this object to end up. If this
|
||||
is less than zero, it will be moved to the end of the array
|
||||
*/
|
||||
void move (const int currentIndex,
|
||||
int newIndex) noexcept
|
||||
{
|
||||
if (currentIndex != newIndex)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (isPositiveAndBelow (currentIndex, numUsed))
|
||||
{
|
||||
if (! isPositiveAndBelow (newIndex, numUsed))
|
||||
newIndex = numUsed - 1;
|
||||
|
||||
ObjectClass* const value = data.elements [currentIndex];
|
||||
|
||||
if (newIndex > currentIndex)
|
||||
{
|
||||
memmove (data.elements + currentIndex,
|
||||
data.elements + currentIndex + 1,
|
||||
sizeof (ObjectClass*) * (size_t) (newIndex - currentIndex));
|
||||
}
|
||||
else
|
||||
{
|
||||
memmove (data.elements + newIndex + 1,
|
||||
data.elements + newIndex,
|
||||
sizeof (ObjectClass*) * (size_t) (currentIndex - newIndex));
|
||||
}
|
||||
|
||||
data.elements [newIndex] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** This swaps the contents of this array with those of another array.
|
||||
|
||||
If you need to exchange two arrays, this is vastly quicker than using copy-by-value
|
||||
because it just swaps their internal pointers.
|
||||
*/
|
||||
void swapWithArray (ReferenceCountedArray& otherArray) noexcept
|
||||
{
|
||||
const ScopedLockType lock1 (getLock());
|
||||
const ScopedLockType lock2 (otherArray.getLock());
|
||||
|
||||
data.swapWith (otherArray.data);
|
||||
std::swap (numUsed, otherArray.numUsed);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Compares this array to another one.
|
||||
|
||||
@returns true only if the other array contains the same objects in the same order
|
||||
*/
|
||||
bool operator== (const ReferenceCountedArray& other) const noexcept
|
||||
{
|
||||
const ScopedLockType lock2 (other.getLock());
|
||||
const ScopedLockType lock1 (getLock());
|
||||
|
||||
if (numUsed != other.numUsed)
|
||||
return false;
|
||||
|
||||
for (int i = numUsed; --i >= 0;)
|
||||
if (data.elements [i] != other.data.elements [i])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Compares this array to another one.
|
||||
|
||||
@see operator==
|
||||
*/
|
||||
bool operator!= (const ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& other) const noexcept
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Sorts the elements in the array.
|
||||
|
||||
This will use a comparator object to sort the elements into order. The object
|
||||
passed must have a method of the form:
|
||||
@code
|
||||
int compareElements (ElementType first, ElementType second);
|
||||
@endcode
|
||||
|
||||
..and this method must return:
|
||||
- a value of < 0 if the first comes before the second
|
||||
- a value of 0 if the two objects are equivalent
|
||||
- a value of > 0 if the second comes before the first
|
||||
|
||||
To improve performance, the compareElements() method can be declared as static or const.
|
||||
|
||||
@param comparator the comparator to use for comparing elements.
|
||||
@param retainOrderOfEquivalentItems if this is true, then items
|
||||
which the comparator says are equivalent will be
|
||||
kept in the order in which they currently appear
|
||||
in the array. This is slower to perform, but may
|
||||
be important in some cases. If it's false, a faster
|
||||
algorithm is used, but equivalent elements may be
|
||||
rearranged.
|
||||
|
||||
@see sortArray
|
||||
*/
|
||||
template <class ElementComparator>
|
||||
void sort (ElementComparator& comparator,
|
||||
const bool retainOrderOfEquivalentItems = false) const noexcept
|
||||
{
|
||||
(void) comparator; // if you pass in an object with a static compareElements() method, this
|
||||
// avoids getting warning messages about the parameter being unused
|
||||
|
||||
const ScopedLockType lock (getLock());
|
||||
sortArray (comparator, data.elements.getData(), 0, size() - 1, retainOrderOfEquivalentItems);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Reduces the amount of storage being used by the array.
|
||||
|
||||
Arrays typically allocate slightly more storage than they need, and after
|
||||
removing elements, they may have quite a lot of unused space allocated.
|
||||
This method will reduce the amount of allocated storage to a minimum.
|
||||
*/
|
||||
void minimiseStorageOverheads() noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
data.shrinkToNoMoreThan (numUsed);
|
||||
}
|
||||
|
||||
/** Increases the array's internal storage to hold a minimum number of elements.
|
||||
|
||||
Calling this before adding a large known number of elements means that
|
||||
the array won't have to keep dynamically resizing itself as the elements
|
||||
are added, and it'll therefore be more efficient.
|
||||
*/
|
||||
void ensureStorageAllocated (const int minNumElements)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
data.ensureAllocatedSize (minNumElements);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the CriticalSection that locks this array.
|
||||
To lock, you can call getLock().enter() and getLock().exit(), or preferably use
|
||||
an object of ScopedLockType as an RAII lock for it.
|
||||
*/
|
||||
inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return data; }
|
||||
|
||||
/** Returns the type of scoped lock to use for locking this array */
|
||||
typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
|
||||
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
ArrayAllocationBase <ObjectClass*, TypeOfCriticalSectionToUse> data;
|
||||
int numUsed;
|
||||
};
|
||||
|
||||
|
||||
#endif // BEAST_REFERENCECOUNTEDARRAY_BEASTHEADER
|
||||
95
modules/beast_core/containers/beast_ScopedValueSetter.h
Normal file
95
modules/beast_core/containers/beast_ScopedValueSetter.h
Normal file
@@ -0,0 +1,95 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_SCOPEDVALUESETTER_BEASTHEADER
|
||||
#define BEAST_SCOPEDVALUESETTER_BEASTHEADER
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Helper class providing an RAII-based mechanism for temporarily setting and
|
||||
then re-setting a value.
|
||||
|
||||
E.g. @code
|
||||
int x = 1;
|
||||
|
||||
{
|
||||
ScopedValueSetter setter (x, 2);
|
||||
|
||||
// x is now 2
|
||||
}
|
||||
|
||||
// x is now 1 again
|
||||
|
||||
{
|
||||
ScopedValueSetter setter (x, 3, 4);
|
||||
|
||||
// x is now 3
|
||||
}
|
||||
|
||||
// x is now 4
|
||||
@endcode
|
||||
|
||||
*/
|
||||
template <typename ValueType>
|
||||
class ScopedValueSetter
|
||||
{
|
||||
public:
|
||||
/** Creates a ScopedValueSetter that will immediately change the specified value to the
|
||||
given new value, and will then reset it to its original value when this object is deleted.
|
||||
*/
|
||||
ScopedValueSetter (ValueType& valueToSet,
|
||||
ValueType newValue)
|
||||
: value (valueToSet),
|
||||
originalValue (valueToSet)
|
||||
{
|
||||
valueToSet = newValue;
|
||||
}
|
||||
|
||||
/** Creates a ScopedValueSetter that will immediately change the specified value to the
|
||||
given new value, and will then reset it to be valueWhenDeleted when this object is deleted.
|
||||
*/
|
||||
ScopedValueSetter (ValueType& valueToSet,
|
||||
ValueType newValue,
|
||||
ValueType valueWhenDeleted)
|
||||
: value (valueToSet),
|
||||
originalValue (valueWhenDeleted)
|
||||
{
|
||||
valueToSet = newValue;
|
||||
}
|
||||
|
||||
~ScopedValueSetter()
|
||||
{
|
||||
value = originalValue;
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
ValueType& value;
|
||||
const ValueType originalValue;
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE (ScopedValueSetter)
|
||||
};
|
||||
|
||||
|
||||
#endif // BEAST_SCOPEDVALUESETTER_BEASTHEADER
|
||||
494
modules/beast_core/containers/beast_SortedSet.h
Normal file
494
modules/beast_core/containers/beast_SortedSet.h
Normal file
@@ -0,0 +1,494 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_SORTEDSET_BEASTHEADER
|
||||
#define BEAST_SORTEDSET_BEASTHEADER
|
||||
|
||||
#include "beast_ArrayAllocationBase.h"
|
||||
#include "../threads/beast_CriticalSection.h"
|
||||
|
||||
#if BEAST_MSVC
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4512)
|
||||
#endif
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Holds a set of unique primitive objects, such as ints or doubles.
|
||||
|
||||
A set can only hold one item with a given value, so if for example it's a
|
||||
set of integers, attempting to add the same integer twice will do nothing
|
||||
the second time.
|
||||
|
||||
Internally, the list of items is kept sorted (which means that whatever
|
||||
kind of primitive type is used must support the ==, <, >, <= and >= operators
|
||||
to determine the order), and searching the set for known values is very fast
|
||||
because it uses a binary-chop method.
|
||||
|
||||
Note that if you're using a class or struct as the element type, it must be
|
||||
capable of being copied or moved with a straightforward memcpy, rather than
|
||||
needing construction and destruction code.
|
||||
|
||||
To make all the set's methods thread-safe, pass in "CriticalSection" as the templated
|
||||
TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection.
|
||||
|
||||
@see Array, OwnedArray, ReferenceCountedArray, StringArray, CriticalSection
|
||||
*/
|
||||
template <class ElementType, class TypeOfCriticalSectionToUse = DummyCriticalSection>
|
||||
class SortedSet
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an empty set. */
|
||||
SortedSet() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
/** Creates a copy of another set.
|
||||
@param other the set to copy
|
||||
*/
|
||||
SortedSet (const SortedSet& other)
|
||||
: data (other.data)
|
||||
{
|
||||
}
|
||||
|
||||
/** Destructor. */
|
||||
~SortedSet() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
/** Copies another set over this one.
|
||||
@param other the set to copy
|
||||
*/
|
||||
SortedSet& operator= (const SortedSet& other) noexcept
|
||||
{
|
||||
data = other.data;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Compares this set to another one.
|
||||
Two sets are considered equal if they both contain the same set of elements.
|
||||
@param other the other set to compare with
|
||||
*/
|
||||
bool operator== (const SortedSet<ElementType>& other) const noexcept
|
||||
{
|
||||
return data == other.data;
|
||||
}
|
||||
|
||||
/** Compares this set to another one.
|
||||
Two sets are considered equal if they both contain the same set of elements.
|
||||
@param other the other set to compare with
|
||||
*/
|
||||
bool operator!= (const SortedSet<ElementType>& other) const noexcept
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Removes all elements from the set.
|
||||
|
||||
This will remove all the elements, and free any storage that the set is
|
||||
using. To clear it without freeing the storage, use the clearQuick()
|
||||
method instead.
|
||||
|
||||
@see clearQuick
|
||||
*/
|
||||
void clear() noexcept
|
||||
{
|
||||
data.clear();
|
||||
}
|
||||
|
||||
/** Removes all elements from the set without freeing the array's allocated storage.
|
||||
|
||||
@see clear
|
||||
*/
|
||||
void clearQuick() noexcept
|
||||
{
|
||||
data.clearQuick();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the current number of elements in the set.
|
||||
*/
|
||||
inline int size() const noexcept
|
||||
{
|
||||
return data.size();
|
||||
}
|
||||
|
||||
/** Returns one of the elements in the set.
|
||||
|
||||
If the index passed in is beyond the range of valid elements, this
|
||||
will return zero.
|
||||
|
||||
If you're certain that the index will always be a valid element, you
|
||||
can call getUnchecked() instead, which is faster.
|
||||
|
||||
@param index the index of the element being requested (0 is the first element in the set)
|
||||
@see getUnchecked, getFirst, getLast
|
||||
*/
|
||||
inline ElementType operator[] (const int index) const noexcept
|
||||
{
|
||||
return data [index];
|
||||
}
|
||||
|
||||
/** Returns one of the elements in the set, without checking the index passed in.
|
||||
Unlike the operator[] method, this will try to return an element without
|
||||
checking that the index is within the bounds of the set, so should only
|
||||
be used when you're confident that it will always be a valid index.
|
||||
|
||||
@param index the index of the element being requested (0 is the first element in the set)
|
||||
@see operator[], getFirst, getLast
|
||||
*/
|
||||
inline ElementType getUnchecked (const int index) const noexcept
|
||||
{
|
||||
return data.getUnchecked (index);
|
||||
}
|
||||
|
||||
/** Returns a direct reference to one of the elements in the set, without checking the index passed in.
|
||||
|
||||
This is like getUnchecked, but returns a direct reference to the element, so that
|
||||
you can alter it directly. Obviously this can be dangerous, so only use it when
|
||||
absolutely necessary.
|
||||
|
||||
@param index the index of the element being requested (0 is the first element in the array)
|
||||
*/
|
||||
inline ElementType& getReference (const int index) const noexcept
|
||||
{
|
||||
return data.getReference (index);
|
||||
}
|
||||
|
||||
/** Returns the first element in the set, or 0 if the set is empty.
|
||||
|
||||
@see operator[], getUnchecked, getLast
|
||||
*/
|
||||
inline ElementType getFirst() const noexcept
|
||||
{
|
||||
return data.getFirst();
|
||||
}
|
||||
|
||||
/** Returns the last element in the set, or 0 if the set is empty.
|
||||
|
||||
@see operator[], getUnchecked, getFirst
|
||||
*/
|
||||
inline ElementType getLast() const noexcept
|
||||
{
|
||||
return data.getLast();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a pointer to the first element in the set.
|
||||
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||
*/
|
||||
inline ElementType* begin() const noexcept
|
||||
{
|
||||
return data.begin();
|
||||
}
|
||||
|
||||
/** Returns a pointer to the element which follows the last element in the set.
|
||||
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||
*/
|
||||
inline ElementType* end() const noexcept
|
||||
{
|
||||
return data.end();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Finds the index of the first element which matches the value passed in.
|
||||
|
||||
This will search the set for the given object, and return the index
|
||||
of its first occurrence. If the object isn't found, the method will return -1.
|
||||
|
||||
@param elementToLookFor the value or object to look for
|
||||
@returns the index of the object, or -1 if it's not found
|
||||
*/
|
||||
int indexOf (const ElementType& elementToLookFor) const noexcept
|
||||
{
|
||||
const ScopedLockType lock (data.getLock());
|
||||
|
||||
int s = 0;
|
||||
int e = data.size();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (s >= e)
|
||||
return -1;
|
||||
|
||||
if (elementToLookFor == data.getReference (s))
|
||||
return s;
|
||||
|
||||
const int halfway = (s + e) / 2;
|
||||
|
||||
if (halfway == s)
|
||||
return -1;
|
||||
else if (elementToLookFor < data.getReference (halfway))
|
||||
e = halfway;
|
||||
else
|
||||
s = halfway;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns true if the set contains at least one occurrence of an object.
|
||||
|
||||
@param elementToLookFor the value or object to look for
|
||||
@returns true if the item is found
|
||||
*/
|
||||
bool contains (const ElementType& elementToLookFor) const noexcept
|
||||
{
|
||||
return indexOf (elementToLookFor) >= 0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Adds a new element to the set, (as long as it's not already in there).
|
||||
|
||||
Note that if a matching element already exists, the new value will be assigned
|
||||
to the existing one using operator=, so that if there are any differences between
|
||||
the objects which were not recognised by the object's operator==, then the
|
||||
set will always contain a copy of the most recently added one.
|
||||
|
||||
@param newElement the new object to add to the set
|
||||
@returns true if the value was added, or false if it already existed
|
||||
@see set, insert, addIfNotAlreadyThere, addSorted, addSet, addArray
|
||||
*/
|
||||
bool add (const ElementType& newElement) noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
int s = 0;
|
||||
int e = data.size();
|
||||
|
||||
while (s < e)
|
||||
{
|
||||
ElementType& elem = data.getReference (s);
|
||||
if (newElement == elem)
|
||||
{
|
||||
elem = newElement; // force an update in case operator== permits differences.
|
||||
return false;
|
||||
}
|
||||
|
||||
const int halfway = (s + e) / 2;
|
||||
const bool isBeforeHalfway = (newElement < data.getReference (halfway));
|
||||
|
||||
if (halfway == s)
|
||||
{
|
||||
if (! isBeforeHalfway)
|
||||
++s;
|
||||
|
||||
break;
|
||||
}
|
||||
else if (isBeforeHalfway)
|
||||
e = halfway;
|
||||
else
|
||||
s = halfway;
|
||||
}
|
||||
|
||||
data.insert (s, newElement);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Adds elements from an array to this set.
|
||||
|
||||
@param elementsToAdd the array of elements to add
|
||||
@param numElementsToAdd how many elements are in this other array
|
||||
@see add
|
||||
*/
|
||||
void addArray (const ElementType* elementsToAdd,
|
||||
int numElementsToAdd) noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
while (--numElementsToAdd >= 0)
|
||||
add (*elementsToAdd++);
|
||||
}
|
||||
|
||||
/** Adds elements from another set to this one.
|
||||
|
||||
@param setToAddFrom the set from which to copy the elements
|
||||
@param startIndex the first element of the other set to start copying from
|
||||
@param numElementsToAdd how many elements to add from the other set. If this
|
||||
value is negative or greater than the number of available elements,
|
||||
all available elements will be copied.
|
||||
@see add
|
||||
*/
|
||||
template <class OtherSetType>
|
||||
void addSet (const OtherSetType& setToAddFrom,
|
||||
int startIndex = 0,
|
||||
int numElementsToAdd = -1) noexcept
|
||||
{
|
||||
const typename OtherSetType::ScopedLockType lock1 (setToAddFrom.getLock());
|
||||
|
||||
{
|
||||
const ScopedLockType lock2 (getLock());
|
||||
bassert (this != &setToAddFrom);
|
||||
|
||||
if (this != &setToAddFrom)
|
||||
{
|
||||
if (startIndex < 0)
|
||||
{
|
||||
jassertfalse;
|
||||
startIndex = 0;
|
||||
}
|
||||
|
||||
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > setToAddFrom.size())
|
||||
numElementsToAdd = setToAddFrom.size() - startIndex;
|
||||
|
||||
if (numElementsToAdd > 0)
|
||||
addArray (&setToAddFrom.data.getReference (startIndex), numElementsToAdd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Removes an element from the set.
|
||||
|
||||
This will remove the element at a given index.
|
||||
If the index passed in is out-of-range, nothing will happen.
|
||||
|
||||
@param indexToRemove the index of the element to remove
|
||||
@returns the element that has been removed
|
||||
@see removeValue, removeRange
|
||||
*/
|
||||
ElementType remove (const int indexToRemove) noexcept
|
||||
{
|
||||
return data.remove (indexToRemove);
|
||||
}
|
||||
|
||||
/** Removes an item from the set.
|
||||
|
||||
This will remove the given element from the set, if it's there.
|
||||
|
||||
@param valueToRemove the object to try to remove
|
||||
@see remove, removeRange
|
||||
*/
|
||||
void removeValue (const ElementType valueToRemove) noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
data.remove (indexOf (valueToRemove));
|
||||
}
|
||||
|
||||
/** Removes any elements which are also in another set.
|
||||
|
||||
@param otherSet the other set in which to look for elements to remove
|
||||
@see removeValuesNotIn, remove, removeValue, removeRange
|
||||
*/
|
||||
template <class OtherSetType>
|
||||
void removeValuesIn (const OtherSetType& otherSet) noexcept
|
||||
{
|
||||
const typename OtherSetType::ScopedLockType lock1 (otherSet.getLock());
|
||||
const ScopedLockType lock2 (getLock());
|
||||
|
||||
if (this == &otherSet)
|
||||
{
|
||||
clear();
|
||||
}
|
||||
else if (otherSet.size() > 0)
|
||||
{
|
||||
for (int i = data.size(); --i >= 0;)
|
||||
if (otherSet.contains (data.getReference (i)))
|
||||
remove (i);
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes any elements which are not found in another set.
|
||||
|
||||
Only elements which occur in this other set will be retained.
|
||||
|
||||
@param otherSet the set in which to look for elements NOT to remove
|
||||
@see removeValuesIn, remove, removeValue, removeRange
|
||||
*/
|
||||
template <class OtherSetType>
|
||||
void removeValuesNotIn (const OtherSetType& otherSet) noexcept
|
||||
{
|
||||
const typename OtherSetType::ScopedLockType lock1 (otherSet.getLock());
|
||||
const ScopedLockType lock2 (getLock());
|
||||
|
||||
if (this != &otherSet)
|
||||
{
|
||||
if (otherSet.size() <= 0)
|
||||
{
|
||||
clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = data.size(); --i >= 0;)
|
||||
if (! otherSet.contains (data.getReference (i)))
|
||||
remove (i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** This swaps the contents of this array with those of another array.
|
||||
|
||||
If you need to exchange two arrays, this is vastly quicker than using copy-by-value
|
||||
because it just swaps their internal pointers.
|
||||
*/
|
||||
void swapWith (SortedSet& otherSet) noexcept
|
||||
{
|
||||
data.swapWithArray (otherSet.data);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Reduces the amount of storage being used by the set.
|
||||
|
||||
Sets typically allocate slightly more storage than they need, and after
|
||||
removing elements, they may have quite a lot of unused space allocated.
|
||||
This method will reduce the amount of allocated storage to a minimum.
|
||||
*/
|
||||
void minimiseStorageOverheads() noexcept
|
||||
{
|
||||
data.minimiseStorageOverheads();
|
||||
}
|
||||
|
||||
/** Increases the set's internal storage to hold a minimum number of elements.
|
||||
|
||||
Calling this before adding a large known number of elements means that
|
||||
the set won't have to keep dynamically resizing itself as the elements
|
||||
are added, and it'll therefore be more efficient.
|
||||
*/
|
||||
void ensureStorageAllocated (const int minNumElements)
|
||||
{
|
||||
data.ensureStorageAllocated (minNumElements);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the CriticalSection that locks this array.
|
||||
To lock, you can call getLock().enter() and getLock().exit(), or preferably use
|
||||
an object of ScopedLockType as an RAII lock for it.
|
||||
*/
|
||||
inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return data.getLock(); }
|
||||
|
||||
/** Returns the type of scoped lock to use for locking this array */
|
||||
typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
|
||||
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
Array <ElementType, TypeOfCriticalSectionToUse> data;
|
||||
};
|
||||
|
||||
#if BEAST_MSVC
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif // BEAST_SORTEDSET_BEASTHEADER
|
||||
296
modules/beast_core/containers/beast_SparseSet.h
Normal file
296
modules/beast_core/containers/beast_SparseSet.h
Normal file
@@ -0,0 +1,296 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_SPARSESET_BEASTHEADER
|
||||
#define BEAST_SPARSESET_BEASTHEADER
|
||||
|
||||
#include "../maths/beast_Range.h"
|
||||
#include "../threads/beast_CriticalSection.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Holds a set of primitive values, storing them as a set of ranges.
|
||||
|
||||
This container acts like an array, but can efficiently hold large contiguous
|
||||
ranges of values. It's quite a specialised class, mostly useful for things
|
||||
like keeping the set of selected rows in a listbox.
|
||||
|
||||
The type used as a template paramter must be an integer type, such as int, short,
|
||||
int64, etc.
|
||||
*/
|
||||
template <class Type>
|
||||
class SparseSet
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a new empty set. */
|
||||
SparseSet()
|
||||
{
|
||||
}
|
||||
|
||||
/** Creates a copy of another SparseSet. */
|
||||
SparseSet (const SparseSet<Type>& other)
|
||||
: values (other.values)
|
||||
{
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Clears the set. */
|
||||
void clear()
|
||||
{
|
||||
values.clear();
|
||||
}
|
||||
|
||||
/** Checks whether the set is empty.
|
||||
|
||||
This is much quicker than using (size() == 0).
|
||||
*/
|
||||
bool isEmpty() const noexcept
|
||||
{
|
||||
return values.size() == 0;
|
||||
}
|
||||
|
||||
/** Returns the number of values in the set.
|
||||
|
||||
Because of the way the data is stored, this method can take longer if there
|
||||
are a lot of items in the set. Use isEmpty() for a quick test of whether there
|
||||
are any items.
|
||||
*/
|
||||
Type size() const
|
||||
{
|
||||
Type total (0);
|
||||
|
||||
for (int i = 0; i < values.size(); i += 2)
|
||||
total += values.getUnchecked (i + 1) - values.getUnchecked (i);
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/** Returns one of the values in the set.
|
||||
|
||||
@param index the index of the value to retrieve, in the range 0 to (size() - 1).
|
||||
@returns the value at this index, or 0 if it's out-of-range
|
||||
*/
|
||||
Type operator[] (Type index) const
|
||||
{
|
||||
for (int i = 0; i < values.size(); i += 2)
|
||||
{
|
||||
const Type start (values.getUnchecked (i));
|
||||
const Type len (values.getUnchecked (i + 1) - start);
|
||||
|
||||
if (index < len)
|
||||
return start + index;
|
||||
|
||||
index -= len;
|
||||
}
|
||||
|
||||
return Type();
|
||||
}
|
||||
|
||||
/** Checks whether a particular value is in the set. */
|
||||
bool contains (const Type valueToLookFor) const
|
||||
{
|
||||
for (int i = 0; i < values.size(); ++i)
|
||||
if (valueToLookFor < values.getUnchecked(i))
|
||||
return (i & 1) != 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the number of contiguous blocks of values.
|
||||
@see getRange
|
||||
*/
|
||||
int getNumRanges() const noexcept
|
||||
{
|
||||
return values.size() >> 1;
|
||||
}
|
||||
|
||||
/** Returns one of the contiguous ranges of values stored.
|
||||
@param rangeIndex the index of the range to look up, between 0
|
||||
and (getNumRanges() - 1)
|
||||
@see getTotalRange
|
||||
*/
|
||||
const Range<Type> getRange (const int rangeIndex) const
|
||||
{
|
||||
if (isPositiveAndBelow (rangeIndex, getNumRanges()))
|
||||
return Range<Type> (values.getUnchecked (rangeIndex << 1),
|
||||
values.getUnchecked ((rangeIndex << 1) + 1));
|
||||
|
||||
return Range<Type>();
|
||||
}
|
||||
|
||||
/** Returns the range between the lowest and highest values in the set.
|
||||
@see getRange
|
||||
*/
|
||||
Range<Type> getTotalRange() const
|
||||
{
|
||||
if (values.size() > 0)
|
||||
{
|
||||
bassert ((values.size() & 1) == 0);
|
||||
return Range<Type> (values.getUnchecked (0),
|
||||
values.getUnchecked (values.size() - 1));
|
||||
}
|
||||
|
||||
return Range<Type>();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Adds a range of contiguous values to the set.
|
||||
e.g. addRange (Range \<int\> (10, 14)) will add (10, 11, 12, 13) to the set.
|
||||
*/
|
||||
void addRange (const Range<Type> range)
|
||||
{
|
||||
bassert (range.getLength() >= 0);
|
||||
if (range.getLength() > 0)
|
||||
{
|
||||
removeRange (range);
|
||||
|
||||
values.addUsingDefaultSort (range.getStart());
|
||||
values.addUsingDefaultSort (range.getEnd());
|
||||
|
||||
simplify();
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes a range of values from the set.
|
||||
e.g. removeRange (Range\<int\> (10, 14)) will remove (10, 11, 12, 13) from the set.
|
||||
*/
|
||||
void removeRange (const Range<Type> rangeToRemove)
|
||||
{
|
||||
bassert (rangeToRemove.getLength() >= 0);
|
||||
|
||||
if (rangeToRemove.getLength() > 0
|
||||
&& values.size() > 0
|
||||
&& rangeToRemove.getStart() < values.getUnchecked (values.size() - 1)
|
||||
&& values.getUnchecked(0) < rangeToRemove.getEnd())
|
||||
{
|
||||
const bool onAtStart = contains (rangeToRemove.getStart() - 1);
|
||||
const Type lastValue (bmin (rangeToRemove.getEnd(), values.getLast()));
|
||||
const bool onAtEnd = contains (lastValue);
|
||||
|
||||
for (int i = values.size(); --i >= 0;)
|
||||
{
|
||||
if (values.getUnchecked(i) <= lastValue)
|
||||
{
|
||||
while (values.getUnchecked(i) >= rangeToRemove.getStart())
|
||||
{
|
||||
values.remove (i);
|
||||
|
||||
if (--i < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (onAtStart) values.addUsingDefaultSort (rangeToRemove.getStart());
|
||||
if (onAtEnd) values.addUsingDefaultSort (lastValue);
|
||||
|
||||
simplify();
|
||||
}
|
||||
}
|
||||
|
||||
/** Does an XOR of the values in a given range. */
|
||||
void invertRange (const Range<Type> range)
|
||||
{
|
||||
SparseSet newItems;
|
||||
newItems.addRange (range);
|
||||
|
||||
for (int i = getNumRanges(); --i >= 0;)
|
||||
newItems.removeRange (getRange (i));
|
||||
|
||||
removeRange (range);
|
||||
|
||||
for (int i = newItems.getNumRanges(); --i >= 0;)
|
||||
addRange (newItems.getRange(i));
|
||||
}
|
||||
|
||||
/** Checks whether any part of a given range overlaps any part of this set. */
|
||||
bool overlapsRange (const Range<Type> range)
|
||||
{
|
||||
if (range.getLength() > 0)
|
||||
{
|
||||
for (int i = getNumRanges(); --i >= 0;)
|
||||
{
|
||||
if (values.getUnchecked ((i << 1) + 1) <= range.getStart())
|
||||
return false;
|
||||
|
||||
if (values.getUnchecked (i << 1) < range.getEnd())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Checks whether the whole of a given range is contained within this one. */
|
||||
bool containsRange (const Range<Type> range)
|
||||
{
|
||||
if (range.getLength() > 0)
|
||||
{
|
||||
for (int i = getNumRanges(); --i >= 0;)
|
||||
{
|
||||
if (values.getUnchecked ((i << 1) + 1) <= range.getStart())
|
||||
return false;
|
||||
|
||||
if (values.getUnchecked (i << 1) <= range.getStart()
|
||||
&& range.getEnd() <= values.getUnchecked ((i << 1) + 1))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool operator== (const SparseSet<Type>& other) noexcept
|
||||
{
|
||||
return values == other.values;
|
||||
}
|
||||
|
||||
bool operator!= (const SparseSet<Type>& other) noexcept
|
||||
{
|
||||
return values != other.values;
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
// alternating start/end values of ranges of values that are present.
|
||||
Array<Type, DummyCriticalSection> values;
|
||||
|
||||
void simplify()
|
||||
{
|
||||
bassert ((values.size() & 1) == 0);
|
||||
|
||||
for (int i = values.size(); --i > 0;)
|
||||
if (values.getUnchecked(i) == values.getUnchecked (i - 1))
|
||||
values.removeRange (--i, 2);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // BEAST_SPARSESET_BEASTHEADER
|
||||
704
modules/beast_core/containers/beast_Variant.cpp
Normal file
704
modules/beast_core/containers/beast_Variant.cpp
Normal file
@@ -0,0 +1,704 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
enum VariantStreamMarkers
|
||||
{
|
||||
varMarker_Int = 1,
|
||||
varMarker_BoolTrue = 2,
|
||||
varMarker_BoolFalse = 3,
|
||||
varMarker_Double = 4,
|
||||
varMarker_String = 5,
|
||||
varMarker_Int64 = 6,
|
||||
varMarker_Array = 7,
|
||||
varMarker_Binary = 8
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class var::VariantType
|
||||
{
|
||||
public:
|
||||
VariantType() noexcept {}
|
||||
virtual ~VariantType() noexcept {}
|
||||
|
||||
virtual int toInt (const ValueUnion&) const noexcept { return 0; }
|
||||
virtual int64 toInt64 (const ValueUnion&) const noexcept { return 0; }
|
||||
virtual double toDouble (const ValueUnion&) const noexcept { return 0; }
|
||||
virtual String toString (const ValueUnion&) const { return String::empty; }
|
||||
virtual bool toBool (const ValueUnion&) const noexcept { return false; }
|
||||
virtual ReferenceCountedObject* toObject (const ValueUnion&) const noexcept { return nullptr; }
|
||||
virtual Array<var>* toArray (const ValueUnion&) const noexcept { return nullptr; }
|
||||
virtual MemoryBlock* toBinary (const ValueUnion&) const noexcept { return nullptr; }
|
||||
|
||||
virtual bool isVoid() const noexcept { return false; }
|
||||
virtual bool isInt() const noexcept { return false; }
|
||||
virtual bool isInt64() const noexcept { return false; }
|
||||
virtual bool isBool() const noexcept { return false; }
|
||||
virtual bool isDouble() const noexcept { return false; }
|
||||
virtual bool isString() const noexcept { return false; }
|
||||
virtual bool isObject() const noexcept { return false; }
|
||||
virtual bool isArray() const noexcept { return false; }
|
||||
virtual bool isBinary() const noexcept { return false; }
|
||||
virtual bool isMethod() const noexcept { return false; }
|
||||
|
||||
virtual void cleanUp (ValueUnion&) const noexcept {}
|
||||
virtual void createCopy (ValueUnion& dest, const ValueUnion& source) const { dest = source; }
|
||||
virtual bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept = 0;
|
||||
virtual void writeToStream (const ValueUnion& data, OutputStream& output) const = 0;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class var::VariantType_Void : public var::VariantType
|
||||
{
|
||||
public:
|
||||
VariantType_Void() noexcept {}
|
||||
static const VariantType_Void instance;
|
||||
|
||||
bool isVoid() const noexcept { return true; }
|
||||
bool equals (const ValueUnion&, const ValueUnion&, const VariantType& otherType) const noexcept { return otherType.isVoid(); }
|
||||
void writeToStream (const ValueUnion&, OutputStream& output) const { output.writeCompressedInt (0); }
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class var::VariantType_Int : public var::VariantType
|
||||
{
|
||||
public:
|
||||
VariantType_Int() noexcept {}
|
||||
static const VariantType_Int instance;
|
||||
|
||||
int toInt (const ValueUnion& data) const noexcept { return data.intValue; };
|
||||
int64 toInt64 (const ValueUnion& data) const noexcept { return (int64) data.intValue; };
|
||||
double toDouble (const ValueUnion& data) const noexcept { return (double) data.intValue; }
|
||||
String toString (const ValueUnion& data) const { return String (data.intValue); }
|
||||
bool toBool (const ValueUnion& data) const noexcept { return data.intValue != 0; }
|
||||
bool isInt() const noexcept { return true; }
|
||||
|
||||
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
|
||||
{
|
||||
return otherType.toInt (otherData) == data.intValue;
|
||||
}
|
||||
|
||||
void writeToStream (const ValueUnion& data, OutputStream& output) const
|
||||
{
|
||||
output.writeCompressedInt (5);
|
||||
output.writeByte (varMarker_Int);
|
||||
output.writeInt (data.intValue);
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class var::VariantType_Int64 : public var::VariantType
|
||||
{
|
||||
public:
|
||||
VariantType_Int64() noexcept {}
|
||||
static const VariantType_Int64 instance;
|
||||
|
||||
int toInt (const ValueUnion& data) const noexcept { return (int) data.int64Value; };
|
||||
int64 toInt64 (const ValueUnion& data) const noexcept { return data.int64Value; };
|
||||
double toDouble (const ValueUnion& data) const noexcept { return (double) data.int64Value; }
|
||||
String toString (const ValueUnion& data) const { return String (data.int64Value); }
|
||||
bool toBool (const ValueUnion& data) const noexcept { return data.int64Value != 0; }
|
||||
bool isInt64() const noexcept { return true; }
|
||||
|
||||
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
|
||||
{
|
||||
return otherType.toInt64 (otherData) == data.int64Value;
|
||||
}
|
||||
|
||||
void writeToStream (const ValueUnion& data, OutputStream& output) const
|
||||
{
|
||||
output.writeCompressedInt (9);
|
||||
output.writeByte (varMarker_Int64);
|
||||
output.writeInt64 (data.int64Value);
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class var::VariantType_Double : public var::VariantType
|
||||
{
|
||||
public:
|
||||
VariantType_Double() noexcept {}
|
||||
static const VariantType_Double instance;
|
||||
|
||||
int toInt (const ValueUnion& data) const noexcept { return (int) data.doubleValue; };
|
||||
int64 toInt64 (const ValueUnion& data) const noexcept { return (int64) data.doubleValue; };
|
||||
double toDouble (const ValueUnion& data) const noexcept { return data.doubleValue; }
|
||||
String toString (const ValueUnion& data) const { return String (data.doubleValue); }
|
||||
bool toBool (const ValueUnion& data) const noexcept { return data.doubleValue != 0; }
|
||||
bool isDouble() const noexcept { return true; }
|
||||
|
||||
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
|
||||
{
|
||||
return std::abs (otherType.toDouble (otherData) - data.doubleValue) < std::numeric_limits<double>::epsilon();
|
||||
}
|
||||
|
||||
void writeToStream (const ValueUnion& data, OutputStream& output) const
|
||||
{
|
||||
output.writeCompressedInt (9);
|
||||
output.writeByte (varMarker_Double);
|
||||
output.writeDouble (data.doubleValue);
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class var::VariantType_Bool : public var::VariantType
|
||||
{
|
||||
public:
|
||||
VariantType_Bool() noexcept {}
|
||||
static const VariantType_Bool instance;
|
||||
|
||||
int toInt (const ValueUnion& data) const noexcept { return data.boolValue ? 1 : 0; };
|
||||
int64 toInt64 (const ValueUnion& data) const noexcept { return data.boolValue ? 1 : 0; };
|
||||
double toDouble (const ValueUnion& data) const noexcept { return data.boolValue ? 1.0 : 0.0; }
|
||||
String toString (const ValueUnion& data) const { return String::charToString (data.boolValue ? (beast_wchar) '1' : (beast_wchar) '0'); }
|
||||
bool toBool (const ValueUnion& data) const noexcept { return data.boolValue; }
|
||||
bool isBool() const noexcept { return true; }
|
||||
|
||||
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
|
||||
{
|
||||
return otherType.toBool (otherData) == data.boolValue;
|
||||
}
|
||||
|
||||
void writeToStream (const ValueUnion& data, OutputStream& output) const
|
||||
{
|
||||
output.writeCompressedInt (1);
|
||||
output.writeByte (data.boolValue ? (char) varMarker_BoolTrue : (char) varMarker_BoolFalse);
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class var::VariantType_String : public var::VariantType
|
||||
{
|
||||
public:
|
||||
VariantType_String() noexcept {}
|
||||
static const VariantType_String instance;
|
||||
|
||||
void cleanUp (ValueUnion& data) const noexcept { getString (data)-> ~String(); }
|
||||
void createCopy (ValueUnion& dest, const ValueUnion& source) const { new (dest.stringValue) String (*getString (source)); }
|
||||
|
||||
bool isString() const noexcept { return true; }
|
||||
int toInt (const ValueUnion& data) const noexcept { return getString (data)->getIntValue(); };
|
||||
int64 toInt64 (const ValueUnion& data) const noexcept { return getString (data)->getLargeIntValue(); };
|
||||
double toDouble (const ValueUnion& data) const noexcept { return getString (data)->getDoubleValue(); }
|
||||
String toString (const ValueUnion& data) const { return *getString (data); }
|
||||
bool toBool (const ValueUnion& data) const noexcept { return getString (data)->getIntValue() != 0
|
||||
|| getString (data)->trim().equalsIgnoreCase ("true")
|
||||
|| getString (data)->trim().equalsIgnoreCase ("yes"); }
|
||||
|
||||
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
|
||||
{
|
||||
return otherType.toString (otherData) == *getString (data);
|
||||
}
|
||||
|
||||
void writeToStream (const ValueUnion& data, OutputStream& output) const
|
||||
{
|
||||
const String* const s = getString (data);
|
||||
const size_t len = s->getNumBytesAsUTF8() + 1;
|
||||
HeapBlock<char> temp (len);
|
||||
s->copyToUTF8 (temp, len);
|
||||
output.writeCompressedInt ((int) (len + 1));
|
||||
output.writeByte (varMarker_String);
|
||||
output.write (temp, len);
|
||||
}
|
||||
|
||||
private:
|
||||
static inline const String* getString (const ValueUnion& data) noexcept { return reinterpret_cast <const String*> (data.stringValue); }
|
||||
static inline String* getString (ValueUnion& data) noexcept { return reinterpret_cast <String*> (data.stringValue); }
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class var::VariantType_Object : public var::VariantType
|
||||
{
|
||||
public:
|
||||
VariantType_Object() noexcept {}
|
||||
static const VariantType_Object instance;
|
||||
|
||||
void cleanUp (ValueUnion& data) const noexcept { if (data.objectValue != nullptr) data.objectValue->decReferenceCount(); }
|
||||
|
||||
void createCopy (ValueUnion& dest, const ValueUnion& source) const
|
||||
{
|
||||
dest.objectValue = source.objectValue;
|
||||
if (dest.objectValue != nullptr)
|
||||
dest.objectValue->incReferenceCount();
|
||||
}
|
||||
|
||||
String toString (const ValueUnion& data) const { return "Object 0x" + String::toHexString ((int) (pointer_sized_int) data.objectValue); }
|
||||
bool toBool (const ValueUnion& data) const noexcept { return data.objectValue != 0; }
|
||||
ReferenceCountedObject* toObject (const ValueUnion& data) const noexcept { return data.objectValue; }
|
||||
bool isObject() const noexcept { return true; }
|
||||
|
||||
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
|
||||
{
|
||||
return otherType.toObject (otherData) == data.objectValue;
|
||||
}
|
||||
|
||||
void writeToStream (const ValueUnion&, OutputStream& output) const
|
||||
{
|
||||
jassertfalse; // Can't write an object to a stream!
|
||||
output.writeCompressedInt (0);
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class var::VariantType_Array : public var::VariantType
|
||||
{
|
||||
public:
|
||||
VariantType_Array() noexcept {}
|
||||
static const VariantType_Array instance;
|
||||
|
||||
void cleanUp (ValueUnion& data) const noexcept { delete data.arrayValue; }
|
||||
void createCopy (ValueUnion& dest, const ValueUnion& source) const { dest.arrayValue = new Array<var> (*(source.arrayValue)); }
|
||||
|
||||
String toString (const ValueUnion&) const { return "[Array]"; }
|
||||
bool isArray() const noexcept { return true; }
|
||||
Array<var>* toArray (const ValueUnion& data) const noexcept { return data.arrayValue; }
|
||||
|
||||
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
|
||||
{
|
||||
const Array<var>* const otherArray = otherType.toArray (otherData);
|
||||
return otherArray != nullptr && *otherArray == *(data.arrayValue);
|
||||
}
|
||||
|
||||
void writeToStream (const ValueUnion& data, OutputStream& output) const
|
||||
{
|
||||
MemoryOutputStream buffer (512);
|
||||
const int numItems = data.arrayValue->size();
|
||||
buffer.writeCompressedInt (numItems);
|
||||
|
||||
for (int i = 0; i < numItems; ++i)
|
||||
data.arrayValue->getReference(i).writeToStream (buffer);
|
||||
|
||||
output.writeCompressedInt (1 + (int) buffer.getDataSize());
|
||||
output.writeByte (varMarker_Array);
|
||||
output << buffer;
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class var::VariantType_Binary : public var::VariantType
|
||||
{
|
||||
public:
|
||||
VariantType_Binary() noexcept {}
|
||||
|
||||
static const VariantType_Binary instance;
|
||||
|
||||
void cleanUp (ValueUnion& data) const noexcept { delete data.binaryValue; }
|
||||
void createCopy (ValueUnion& dest, const ValueUnion& source) const { dest.binaryValue = new MemoryBlock (*source.binaryValue); }
|
||||
|
||||
String toString (const ValueUnion& data) const { return data.binaryValue->toBase64Encoding(); }
|
||||
bool isBinary() const noexcept { return true; }
|
||||
MemoryBlock* toBinary (const ValueUnion& data) const noexcept { return data.binaryValue; }
|
||||
|
||||
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
|
||||
{
|
||||
const MemoryBlock* const otherBlock = otherType.toBinary (otherData);
|
||||
return otherBlock != nullptr && *otherBlock == *data.binaryValue;
|
||||
}
|
||||
|
||||
void writeToStream (const ValueUnion& data, OutputStream& output) const
|
||||
{
|
||||
output.writeCompressedInt (1 + (int) data.binaryValue->getSize());
|
||||
output.writeByte (varMarker_Binary);
|
||||
output << *data.binaryValue;
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class var::VariantType_Method : public var::VariantType
|
||||
{
|
||||
public:
|
||||
VariantType_Method() noexcept {}
|
||||
static const VariantType_Method instance;
|
||||
|
||||
String toString (const ValueUnion&) const { return "Method"; }
|
||||
bool toBool (const ValueUnion& data) const noexcept { return data.methodValue != nullptr; }
|
||||
bool isMethod() const noexcept { return true; }
|
||||
|
||||
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
|
||||
{
|
||||
return otherType.isMethod() && otherData.methodValue == data.methodValue;
|
||||
}
|
||||
|
||||
void writeToStream (const ValueUnion&, OutputStream& output) const
|
||||
{
|
||||
jassertfalse; // Can't write a method to a stream!
|
||||
output.writeCompressedInt (0);
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
const var::VariantType_Void var::VariantType_Void::instance;
|
||||
const var::VariantType_Int var::VariantType_Int::instance;
|
||||
const var::VariantType_Int64 var::VariantType_Int64::instance;
|
||||
const var::VariantType_Bool var::VariantType_Bool::instance;
|
||||
const var::VariantType_Double var::VariantType_Double::instance;
|
||||
const var::VariantType_String var::VariantType_String::instance;
|
||||
const var::VariantType_Object var::VariantType_Object::instance;
|
||||
const var::VariantType_Array var::VariantType_Array::instance;
|
||||
const var::VariantType_Binary var::VariantType_Binary::instance;
|
||||
const var::VariantType_Method var::VariantType_Method::instance;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
var::var() noexcept : type (&VariantType_Void::instance)
|
||||
{
|
||||
}
|
||||
|
||||
var::~var() noexcept
|
||||
{
|
||||
type->cleanUp (value);
|
||||
}
|
||||
|
||||
const var var::null;
|
||||
|
||||
//==============================================================================
|
||||
var::var (const var& valueToCopy) : type (valueToCopy.type)
|
||||
{
|
||||
type->createCopy (value, valueToCopy.value);
|
||||
}
|
||||
|
||||
var::var (const int v) noexcept : type (&VariantType_Int::instance) { value.intValue = v; }
|
||||
var::var (const int64 v) noexcept : type (&VariantType_Int64::instance) { value.int64Value = v; }
|
||||
var::var (const bool v) noexcept : type (&VariantType_Bool::instance) { value.boolValue = v; }
|
||||
var::var (const double v) noexcept : type (&VariantType_Double::instance) { value.doubleValue = v; }
|
||||
var::var (MethodFunction m) noexcept : type (&VariantType_Method::instance) { value.methodValue = m; }
|
||||
var::var (const Array<var>& v) : type (&VariantType_Array::instance) { value.arrayValue = new Array<var> (v); }
|
||||
var::var (const String& v) : type (&VariantType_String::instance) { new (value.stringValue) String (v); }
|
||||
var::var (const char* const v) : type (&VariantType_String::instance) { new (value.stringValue) String (v); }
|
||||
var::var (const wchar_t* const v) : type (&VariantType_String::instance) { new (value.stringValue) String (v); }
|
||||
var::var (const void* v, size_t sz) : type (&VariantType_Binary::instance) { value.binaryValue = new MemoryBlock (v, sz); }
|
||||
var::var (const MemoryBlock& v) : type (&VariantType_Binary::instance) { value.binaryValue = new MemoryBlock (v); }
|
||||
|
||||
var::var (ReferenceCountedObject* const object) : type (&VariantType_Object::instance)
|
||||
{
|
||||
value.objectValue = object;
|
||||
|
||||
if (object != nullptr)
|
||||
object->incReferenceCount();
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
bool var::isVoid() const noexcept { return type->isVoid(); }
|
||||
bool var::isInt() const noexcept { return type->isInt(); }
|
||||
bool var::isInt64() const noexcept { return type->isInt64(); }
|
||||
bool var::isBool() const noexcept { return type->isBool(); }
|
||||
bool var::isDouble() const noexcept { return type->isDouble(); }
|
||||
bool var::isString() const noexcept { return type->isString(); }
|
||||
bool var::isObject() const noexcept { return type->isObject(); }
|
||||
bool var::isArray() const noexcept { return type->isArray(); }
|
||||
bool var::isBinaryData() const noexcept { return type->isBinary(); }
|
||||
bool var::isMethod() const noexcept { return type->isMethod(); }
|
||||
|
||||
var::operator int() const noexcept { return type->toInt (value); }
|
||||
var::operator int64() const noexcept { return type->toInt64 (value); }
|
||||
var::operator bool() const noexcept { return type->toBool (value); }
|
||||
var::operator float() const noexcept { return (float) type->toDouble (value); }
|
||||
var::operator double() const noexcept { return type->toDouble (value); }
|
||||
String var::toString() const { return type->toString (value); }
|
||||
var::operator String() const { return type->toString (value); }
|
||||
ReferenceCountedObject* var::getObject() const noexcept { return type->toObject (value); }
|
||||
Array<var>* var::getArray() const noexcept { return type->toArray (value); }
|
||||
MemoryBlock* var::getBinaryData() const noexcept { return type->toBinary (value); }
|
||||
DynamicObject* var::getDynamicObject() const noexcept { return dynamic_cast <DynamicObject*> (getObject()); }
|
||||
|
||||
//==============================================================================
|
||||
void var::swapWith (var& other) noexcept
|
||||
{
|
||||
std::swap (type, other.type);
|
||||
std::swap (value, other.value);
|
||||
}
|
||||
|
||||
var& var::operator= (const var& v) { type->cleanUp (value); type = v.type; type->createCopy (value, v.value); return *this; }
|
||||
var& var::operator= (const int v) { type->cleanUp (value); type = &VariantType_Int::instance; value.intValue = v; return *this; }
|
||||
var& var::operator= (const int64 v) { type->cleanUp (value); type = &VariantType_Int64::instance; value.int64Value = v; return *this; }
|
||||
var& var::operator= (const bool v) { type->cleanUp (value); type = &VariantType_Bool::instance; value.boolValue = v; return *this; }
|
||||
var& var::operator= (const double v) { type->cleanUp (value); type = &VariantType_Double::instance; value.doubleValue = v; return *this; }
|
||||
var& var::operator= (const char* const v) { type->cleanUp (value); type = &VariantType_String::instance; new (value.stringValue) String (v); return *this; }
|
||||
var& var::operator= (const wchar_t* const v) { type->cleanUp (value); type = &VariantType_String::instance; new (value.stringValue) String (v); return *this; }
|
||||
var& var::operator= (const String& v) { type->cleanUp (value); type = &VariantType_String::instance; new (value.stringValue) String (v); return *this; }
|
||||
var& var::operator= (const Array<var>& v) { var v2 (v); swapWith (v2); return *this; }
|
||||
var& var::operator= (ReferenceCountedObject* v) { var v2 (v); swapWith (v2); return *this; }
|
||||
var& var::operator= (MethodFunction v) { var v2 (v); swapWith (v2); return *this; }
|
||||
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
var::var (var&& other) noexcept
|
||||
: type (other.type),
|
||||
value (other.value)
|
||||
{
|
||||
other.type = &VariantType_Void::instance;
|
||||
}
|
||||
|
||||
var& var::operator= (var&& other) noexcept
|
||||
{
|
||||
swapWith (other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
var::var (String&& v) : type (&VariantType_String::instance)
|
||||
{
|
||||
new (value.stringValue) String (static_cast<String&&> (v));
|
||||
}
|
||||
|
||||
var::var (MemoryBlock&& v) : type (&VariantType_Binary::instance)
|
||||
{
|
||||
value.binaryValue = new MemoryBlock (static_cast<MemoryBlock&&> (v));
|
||||
}
|
||||
|
||||
var& var::operator= (String&& v)
|
||||
{
|
||||
type->cleanUp (value);
|
||||
type = &VariantType_String::instance;
|
||||
new (value.stringValue) String (static_cast<String&&> (v));
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
bool var::equals (const var& other) const noexcept
|
||||
{
|
||||
return type->equals (value, other.value, *other.type);
|
||||
}
|
||||
|
||||
bool var::equalsWithSameType (const var& other) const noexcept
|
||||
{
|
||||
return type == other.type && equals (other);
|
||||
}
|
||||
|
||||
bool operator== (const var& v1, const var& v2) noexcept { return v1.equals (v2); }
|
||||
bool operator!= (const var& v1, const var& v2) noexcept { return ! v1.equals (v2); }
|
||||
bool operator== (const var& v1, const String& v2) { return v1.toString() == v2; }
|
||||
bool operator!= (const var& v1, const String& v2) { return v1.toString() != v2; }
|
||||
bool operator== (const var& v1, const char* const v2) { return v1.toString() == v2; }
|
||||
bool operator!= (const var& v1, const char* const v2) { return v1.toString() != v2; }
|
||||
|
||||
|
||||
//==============================================================================
|
||||
var var::operator[] (const Identifier propertyName) const
|
||||
{
|
||||
if (DynamicObject* const o = getDynamicObject())
|
||||
return o->getProperty (propertyName);
|
||||
|
||||
return var::null;
|
||||
}
|
||||
|
||||
var var::operator[] (const char* const propertyName) const
|
||||
{
|
||||
return operator[] (Identifier (propertyName));
|
||||
}
|
||||
|
||||
var var::getProperty (const Identifier propertyName, const var& defaultReturnValue) const
|
||||
{
|
||||
if (DynamicObject* const o = getDynamicObject())
|
||||
return o->getProperties().getWithDefault (propertyName, defaultReturnValue);
|
||||
|
||||
return defaultReturnValue;
|
||||
}
|
||||
|
||||
var var::invoke (const Identifier method, const var* arguments, int numArguments) const
|
||||
{
|
||||
if (DynamicObject* const o = getDynamicObject())
|
||||
return o->invokeMethod (method, arguments, numArguments);
|
||||
|
||||
return var::null;
|
||||
}
|
||||
|
||||
var var::invokeMethod (DynamicObject* const target, const var* const arguments, const int numArguments) const
|
||||
{
|
||||
bassert (target != nullptr);
|
||||
|
||||
if (isMethod())
|
||||
return (target->*(value.methodValue)) (arguments, numArguments);
|
||||
|
||||
return var::null;
|
||||
}
|
||||
|
||||
var var::call (const Identifier method) const
|
||||
{
|
||||
return invoke (method, nullptr, 0);
|
||||
}
|
||||
|
||||
var var::call (const Identifier method, const var& arg1) const
|
||||
{
|
||||
return invoke (method, &arg1, 1);
|
||||
}
|
||||
|
||||
var var::call (const Identifier method, const var& arg1, const var& arg2) const
|
||||
{
|
||||
var args[] = { arg1, arg2 };
|
||||
return invoke (method, args, 2);
|
||||
}
|
||||
|
||||
var var::call (const Identifier method, const var& arg1, const var& arg2, const var& arg3)
|
||||
{
|
||||
var args[] = { arg1, arg2, arg3 };
|
||||
return invoke (method, args, 3);
|
||||
}
|
||||
|
||||
var var::call (const Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const
|
||||
{
|
||||
var args[] = { arg1, arg2, arg3, arg4 };
|
||||
return invoke (method, args, 4);
|
||||
}
|
||||
|
||||
var var::call (const Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const
|
||||
{
|
||||
var args[] = { arg1, arg2, arg3, arg4, arg5 };
|
||||
return invoke (method, args, 5);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
int var::size() const
|
||||
{
|
||||
if (const Array<var>* const array = getArray())
|
||||
return array->size();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const var& var::operator[] (int arrayIndex) const
|
||||
{
|
||||
const Array<var>* const array = getArray();
|
||||
|
||||
// When using this method, the var must actually be an array, and the index
|
||||
// must be in-range!
|
||||
bassert (array != nullptr && isPositiveAndBelow (arrayIndex, array->size()));
|
||||
|
||||
return array->getReference (arrayIndex);
|
||||
}
|
||||
|
||||
var& var::operator[] (int arrayIndex)
|
||||
{
|
||||
const Array<var>* const array = getArray();
|
||||
|
||||
// When using this method, the var must actually be an array, and the index
|
||||
// must be in-range!
|
||||
bassert (array != nullptr && isPositiveAndBelow (arrayIndex, array->size()));
|
||||
|
||||
return array->getReference (arrayIndex);
|
||||
}
|
||||
|
||||
Array<var>* var::convertToArray()
|
||||
{
|
||||
Array<var>* array = getArray();
|
||||
|
||||
if (array == nullptr)
|
||||
{
|
||||
const Array<var> tempVar;
|
||||
var v (tempVar);
|
||||
array = v.value.arrayValue;
|
||||
|
||||
if (! isVoid())
|
||||
array->add (*this);
|
||||
|
||||
swapWith (v);
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
void var::append (const var& n)
|
||||
{
|
||||
convertToArray()->add (n);
|
||||
}
|
||||
|
||||
void var::remove (const int index)
|
||||
{
|
||||
if (Array<var>* const array = getArray())
|
||||
array->remove (index);
|
||||
}
|
||||
|
||||
void var::insert (const int index, const var& n)
|
||||
{
|
||||
convertToArray()->insert (index, n);
|
||||
}
|
||||
|
||||
void var::resize (const int numArrayElementsWanted)
|
||||
{
|
||||
convertToArray()->resize (numArrayElementsWanted);
|
||||
}
|
||||
|
||||
int var::indexOf (const var& n) const
|
||||
{
|
||||
if (const Array<var>* const array = getArray())
|
||||
return array->indexOf (n);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void var::writeToStream (OutputStream& output) const
|
||||
{
|
||||
type->writeToStream (value, output);
|
||||
}
|
||||
|
||||
var var::readFromStream (InputStream& input)
|
||||
{
|
||||
const int numBytes = input.readCompressedInt();
|
||||
|
||||
if (numBytes > 0)
|
||||
{
|
||||
switch (input.readByte())
|
||||
{
|
||||
case varMarker_Int: return var (input.readInt());
|
||||
case varMarker_Int64: return var (input.readInt64());
|
||||
case varMarker_BoolTrue: return var (true);
|
||||
case varMarker_BoolFalse: return var (false);
|
||||
case varMarker_Double: return var (input.readDouble());
|
||||
case varMarker_String:
|
||||
{
|
||||
MemoryOutputStream mo;
|
||||
mo.writeFromInputStream (input, numBytes - 1);
|
||||
return var (mo.toUTF8());
|
||||
}
|
||||
|
||||
case varMarker_Binary:
|
||||
{
|
||||
MemoryBlock mb (numBytes - 1);
|
||||
|
||||
if (numBytes > 1)
|
||||
{
|
||||
const int numRead = input.read (mb.getData(), numBytes - 1);
|
||||
mb.setSize (numRead);
|
||||
}
|
||||
|
||||
return var (mb);
|
||||
}
|
||||
|
||||
case varMarker_Array:
|
||||
{
|
||||
var v;
|
||||
Array<var>* const destArray = v.convertToArray();
|
||||
|
||||
for (int i = input.readCompressedInt(); --i >= 0;)
|
||||
destArray->add (readFromStream (input));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
default:
|
||||
input.skipNextBytes (numBytes - 1); break;
|
||||
}
|
||||
}
|
||||
|
||||
return var::null;
|
||||
}
|
||||
302
modules/beast_core/containers/beast_Variant.h
Normal file
302
modules/beast_core/containers/beast_Variant.h
Normal file
@@ -0,0 +1,302 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_VARIANT_BEASTHEADER
|
||||
#define BEAST_VARIANT_BEASTHEADER
|
||||
|
||||
#include "../text/beast_Identifier.h"
|
||||
#include "../streams/beast_OutputStream.h"
|
||||
#include "../streams/beast_InputStream.h"
|
||||
#include "../containers/beast_Array.h"
|
||||
|
||||
#ifndef DOXYGEN
|
||||
class ReferenceCountedObject;
|
||||
class DynamicObject;
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A variant class, that can be used to hold a range of primitive values.
|
||||
|
||||
A var object can hold a range of simple primitive values, strings, or
|
||||
any kind of ReferenceCountedObject. The var class is intended to act like
|
||||
the kind of values used in dynamic scripting languages.
|
||||
|
||||
You can save/load var objects either in a small, proprietary binary format
|
||||
using writeToStream()/readFromStream(), or as JSON by using the JSON class.
|
||||
|
||||
@see JSON, DynamicObject
|
||||
*/
|
||||
class BEAST_API var
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
typedef const var (DynamicObject::*MethodFunction) (const var* arguments, int numArguments);
|
||||
typedef Identifier identifier;
|
||||
|
||||
//==============================================================================
|
||||
/** Creates a void variant. */
|
||||
var() noexcept;
|
||||
|
||||
/** Destructor. */
|
||||
~var() noexcept;
|
||||
|
||||
/** A static var object that can be used where you need an empty variant object. */
|
||||
static const var null;
|
||||
|
||||
var (const var& valueToCopy);
|
||||
var (int value) noexcept;
|
||||
var (int64 value) noexcept;
|
||||
var (bool value) noexcept;
|
||||
var (double value) noexcept;
|
||||
var (const char* value);
|
||||
var (const wchar_t* value);
|
||||
var (const String& value);
|
||||
var (const Array<var>& value);
|
||||
var (ReferenceCountedObject* object);
|
||||
var (MethodFunction method) noexcept;
|
||||
var (const void* binaryData, size_t dataSize);
|
||||
var (const MemoryBlock& binaryData);
|
||||
|
||||
var& operator= (const var& valueToCopy);
|
||||
var& operator= (int value);
|
||||
var& operator= (int64 value);
|
||||
var& operator= (bool value);
|
||||
var& operator= (double value);
|
||||
var& operator= (const char* value);
|
||||
var& operator= (const wchar_t* value);
|
||||
var& operator= (const String& value);
|
||||
var& operator= (const Array<var>& value);
|
||||
var& operator= (ReferenceCountedObject* object);
|
||||
var& operator= (MethodFunction method);
|
||||
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
var (var&& other) noexcept;
|
||||
var (String&& value);
|
||||
var (MemoryBlock&& binaryData);
|
||||
var& operator= (var&& other) noexcept;
|
||||
var& operator= (String&& value);
|
||||
#endif
|
||||
|
||||
void swapWith (var& other) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
operator int() const noexcept;
|
||||
operator int64() const noexcept;
|
||||
operator bool() const noexcept;
|
||||
operator float() const noexcept;
|
||||
operator double() const noexcept;
|
||||
operator String() const;
|
||||
String toString() const;
|
||||
|
||||
/** If this variant holds an array, this provides access to it.
|
||||
NOTE: Beware when you use this - the array pointer is only valid for the lifetime
|
||||
of the variant that returned it, so be very careful not to call this method on temporary
|
||||
var objects that are the return-value of a function, and which may go out of scope before
|
||||
you use the array!
|
||||
*/
|
||||
Array<var>* getArray() const noexcept;
|
||||
|
||||
/** If this variant holds a memory block, this provides access to it.
|
||||
NOTE: Beware when you use this - the MemoryBlock pointer is only valid for the lifetime
|
||||
of the variant that returned it, so be very careful not to call this method on temporary
|
||||
var objects that are the return-value of a function, and which may go out of scope before
|
||||
you use the MemoryBlock!
|
||||
*/
|
||||
MemoryBlock* getBinaryData() const noexcept;
|
||||
|
||||
ReferenceCountedObject* getObject() const noexcept;
|
||||
DynamicObject* getDynamicObject() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
bool isVoid() const noexcept;
|
||||
bool isInt() const noexcept;
|
||||
bool isInt64() const noexcept;
|
||||
bool isBool() const noexcept;
|
||||
bool isDouble() const noexcept;
|
||||
bool isString() const noexcept;
|
||||
bool isObject() const noexcept;
|
||||
bool isArray() const noexcept;
|
||||
bool isBinaryData() const noexcept;
|
||||
bool isMethod() const noexcept;
|
||||
|
||||
/** Returns true if this var has the same value as the one supplied.
|
||||
Note that this ignores the type, so a string var "123" and an integer var with the
|
||||
value 123 are considered to be equal.
|
||||
@see equalsWithSameType
|
||||
*/
|
||||
bool equals (const var& other) const noexcept;
|
||||
|
||||
/** Returns true if this var has the same value and type as the one supplied.
|
||||
This differs from equals() because e.g. "123" and 123 will be considered different.
|
||||
@see equals
|
||||
*/
|
||||
bool equalsWithSameType (const var& other) const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** If the var is an array, this returns the number of elements.
|
||||
If the var isn't actually an array, this will return 0.
|
||||
*/
|
||||
int size() const;
|
||||
|
||||
/** If the var is an array, this can be used to return one of its elements.
|
||||
To call this method, you must make sure that the var is actually an array, and
|
||||
that the index is a valid number. If these conditions aren't met, behaviour is
|
||||
undefined.
|
||||
For more control over the array's contents, you can call getArray() and manipulate
|
||||
it directly as an Array\<var\>.
|
||||
*/
|
||||
const var& operator[] (int arrayIndex) const;
|
||||
|
||||
/** If the var is an array, this can be used to return one of its elements.
|
||||
To call this method, you must make sure that the var is actually an array, and
|
||||
that the index is a valid number. If these conditions aren't met, behaviour is
|
||||
undefined.
|
||||
For more control over the array's contents, you can call getArray() and manipulate
|
||||
it directly as an Array\<var\>.
|
||||
*/
|
||||
var& operator[] (int arrayIndex);
|
||||
|
||||
/** Appends an element to the var, converting it to an array if it isn't already one.
|
||||
If the var isn't an array, it will be converted to one, and if its value was non-void,
|
||||
this value will be kept as the first element of the new array. The parameter value
|
||||
will then be appended to it.
|
||||
For more control over the array's contents, you can call getArray() and manipulate
|
||||
it directly as an Array\<var\>.
|
||||
*/
|
||||
void append (const var& valueToAppend);
|
||||
|
||||
/** Inserts an element to the var, converting it to an array if it isn't already one.
|
||||
If the var isn't an array, it will be converted to one, and if its value was non-void,
|
||||
this value will be kept as the first element of the new array. The parameter value
|
||||
will then be inserted into it.
|
||||
For more control over the array's contents, you can call getArray() and manipulate
|
||||
it directly as an Array\<var\>.
|
||||
*/
|
||||
void insert (int index, const var& value);
|
||||
|
||||
/** If the var is an array, this removes one of its elements.
|
||||
If the index is out-of-range or the var isn't an array, nothing will be done.
|
||||
For more control over the array's contents, you can call getArray() and manipulate
|
||||
it directly as an Array\<var\>.
|
||||
*/
|
||||
void remove (int index);
|
||||
|
||||
/** Treating the var as an array, this resizes it to contain the specified number of elements.
|
||||
If the var isn't an array, it will be converted to one, and if its value was non-void,
|
||||
this value will be kept as the first element of the new array before resizing.
|
||||
For more control over the array's contents, you can call getArray() and manipulate
|
||||
it directly as an Array\<var\>.
|
||||
*/
|
||||
void resize (int numArrayElementsWanted);
|
||||
|
||||
/** If the var is an array, this searches it for the first occurrence of the specified value,
|
||||
and returns its index.
|
||||
If the var isn't an array, or if the value isn't found, this returns -1.
|
||||
*/
|
||||
int indexOf (const var& value) const;
|
||||
|
||||
//==============================================================================
|
||||
/** If this variant is an object, this returns one of its properties. */
|
||||
var operator[] (const Identifier propertyName) const;
|
||||
/** If this variant is an object, this returns one of its properties. */
|
||||
var operator[] (const char* propertyName) const;
|
||||
/** If this variant is an object, this returns one of its properties, or a default
|
||||
fallback value if the property is not set. */
|
||||
var getProperty (const Identifier propertyName, const var& defaultReturnValue) const;
|
||||
|
||||
/** If this variant is an object, this invokes one of its methods with no arguments. */
|
||||
var call (const Identifier method) const;
|
||||
/** If this variant is an object, this invokes one of its methods with one argument. */
|
||||
var call (const Identifier method, const var& arg1) const;
|
||||
/** If this variant is an object, this invokes one of its methods with 2 arguments. */
|
||||
var call (const Identifier method, const var& arg1, const var& arg2) const;
|
||||
/** If this variant is an object, this invokes one of its methods with 3 arguments. */
|
||||
var call (const Identifier method, const var& arg1, const var& arg2, const var& arg3);
|
||||
/** If this variant is an object, this invokes one of its methods with 4 arguments. */
|
||||
var call (const Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const;
|
||||
/** If this variant is an object, this invokes one of its methods with 5 arguments. */
|
||||
var call (const Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const;
|
||||
/** If this variant is an object, this invokes one of its methods with a list of arguments. */
|
||||
var invoke (const Identifier method, const var* arguments, int numArguments) const;
|
||||
|
||||
//==============================================================================
|
||||
/** Writes a binary representation of this value to a stream.
|
||||
The data can be read back later using readFromStream().
|
||||
@see JSON
|
||||
*/
|
||||
void writeToStream (OutputStream& output) const;
|
||||
|
||||
/** Reads back a stored binary representation of a value.
|
||||
The data in the stream must have been written using writeToStream(), or this
|
||||
will have unpredictable results.
|
||||
@see JSON
|
||||
*/
|
||||
static var readFromStream (InputStream& input);
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class VariantType; friend class VariantType;
|
||||
class VariantType_Void; friend class VariantType_Void;
|
||||
class VariantType_Int; friend class VariantType_Int;
|
||||
class VariantType_Int64; friend class VariantType_Int64;
|
||||
class VariantType_Double; friend class VariantType_Double;
|
||||
class VariantType_Bool; friend class VariantType_Bool;
|
||||
class VariantType_String; friend class VariantType_String;
|
||||
class VariantType_Object; friend class VariantType_Object;
|
||||
class VariantType_Array; friend class VariantType_Array;
|
||||
class VariantType_Binary; friend class VariantType_Binary;
|
||||
class VariantType_Method; friend class VariantType_Method;
|
||||
|
||||
union ValueUnion
|
||||
{
|
||||
int intValue;
|
||||
int64 int64Value;
|
||||
bool boolValue;
|
||||
double doubleValue;
|
||||
char stringValue [sizeof (String)];
|
||||
ReferenceCountedObject* objectValue;
|
||||
Array<var>* arrayValue;
|
||||
MemoryBlock* binaryValue;
|
||||
MethodFunction methodValue;
|
||||
};
|
||||
|
||||
const VariantType* type;
|
||||
ValueUnion value;
|
||||
|
||||
Array<var>* convertToArray();
|
||||
friend class DynamicObject;
|
||||
var invokeMethod (DynamicObject*, const var*, int) const;
|
||||
};
|
||||
|
||||
/** Compares the values of two var objects, using the var::equals() comparison. */
|
||||
bool operator== (const var& v1, const var& v2) noexcept;
|
||||
/** Compares the values of two var objects, using the var::equals() comparison. */
|
||||
bool operator!= (const var& v1, const var& v2) noexcept;
|
||||
bool operator== (const var& v1, const String& v2);
|
||||
bool operator!= (const var& v1, const String& v2);
|
||||
bool operator== (const var& v1, const char* v2);
|
||||
bool operator!= (const var& v1, const char* v2);
|
||||
|
||||
|
||||
#endif // BEAST_VARIANT_BEASTHEADER
|
||||
154
modules/beast_core/files/beast_DirectoryIterator.cpp
Normal file
154
modules/beast_core/files/beast_DirectoryIterator.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
static StringArray parseWildcards (const String& pattern)
|
||||
{
|
||||
StringArray s;
|
||||
s.addTokens (pattern, ";,", "\"'");
|
||||
s.trim();
|
||||
s.removeEmptyStrings();
|
||||
return s;
|
||||
}
|
||||
|
||||
static bool fileMatches (const StringArray& wildCards, const String& filename)
|
||||
{
|
||||
for (int i = 0; i < wildCards.size(); ++i)
|
||||
if (filename.matchesWildcard (wildCards[i], ! File::areFileNamesCaseSensitive()))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
DirectoryIterator::DirectoryIterator (const File& directory, bool recursive,
|
||||
const String& pattern, const int type)
|
||||
: wildCards (parseWildcards (pattern)),
|
||||
fileFinder (directory, (recursive || wildCards.size() > 1) ? "*" : pattern),
|
||||
wildCard (pattern),
|
||||
path (File::addTrailingSeparator (directory.getFullPathName())),
|
||||
index (-1),
|
||||
totalNumFiles (-1),
|
||||
whatToLookFor (type),
|
||||
isRecursive (recursive),
|
||||
hasBeenAdvanced (false)
|
||||
{
|
||||
// you have to specify the type of files you're looking for!
|
||||
bassert ((type & (File::findFiles | File::findDirectories)) != 0);
|
||||
bassert (type > 0 && type <= 7);
|
||||
}
|
||||
|
||||
DirectoryIterator::~DirectoryIterator()
|
||||
{
|
||||
}
|
||||
|
||||
bool DirectoryIterator::next()
|
||||
{
|
||||
return next (nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
bool DirectoryIterator::next (bool* const isDirResult, bool* const isHiddenResult, int64* const fileSize,
|
||||
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||
{
|
||||
hasBeenAdvanced = true;
|
||||
|
||||
if (subIterator != nullptr)
|
||||
{
|
||||
if (subIterator->next (isDirResult, isHiddenResult, fileSize, modTime, creationTime, isReadOnly))
|
||||
return true;
|
||||
|
||||
subIterator = nullptr;
|
||||
}
|
||||
|
||||
String filename;
|
||||
bool isDirectory, isHidden = false;
|
||||
|
||||
while (fileFinder.next (filename, &isDirectory,
|
||||
(isHiddenResult != nullptr || (whatToLookFor & File::ignoreHiddenFiles) != 0) ? &isHidden : nullptr,
|
||||
fileSize, modTime, creationTime, isReadOnly))
|
||||
{
|
||||
++index;
|
||||
|
||||
if (! filename.containsOnly ("."))
|
||||
{
|
||||
bool matches = false;
|
||||
|
||||
if (isDirectory)
|
||||
{
|
||||
if (isRecursive && ((whatToLookFor & File::ignoreHiddenFiles) == 0 || ! isHidden))
|
||||
subIterator = new DirectoryIterator (File::createFileWithoutCheckingPath (path + filename),
|
||||
true, wildCard, whatToLookFor);
|
||||
|
||||
matches = (whatToLookFor & File::findDirectories) != 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
matches = (whatToLookFor & File::findFiles) != 0;
|
||||
}
|
||||
|
||||
// if recursive, we're not relying on the OS iterator to do the wildcard match, so do it now..
|
||||
if (matches && isRecursive)
|
||||
matches = fileMatches (wildCards, filename);
|
||||
|
||||
if (matches && (whatToLookFor & File::ignoreHiddenFiles) != 0)
|
||||
matches = ! isHidden;
|
||||
|
||||
if (matches)
|
||||
{
|
||||
currentFile = File::createFileWithoutCheckingPath (path + filename);
|
||||
if (isHiddenResult != nullptr) *isHiddenResult = isHidden;
|
||||
if (isDirResult != nullptr) *isDirResult = isDirectory;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (subIterator != nullptr)
|
||||
return next (isDirResult, isHiddenResult, fileSize, modTime, creationTime, isReadOnly);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const File& DirectoryIterator::getFile() const
|
||||
{
|
||||
if (subIterator != nullptr && subIterator->hasBeenAdvanced)
|
||||
return subIterator->getFile();
|
||||
|
||||
// You need to call DirectoryIterator::next() before asking it for the file that it found!
|
||||
bassert (hasBeenAdvanced);
|
||||
|
||||
return currentFile;
|
||||
}
|
||||
|
||||
float DirectoryIterator::getEstimatedProgress() const
|
||||
{
|
||||
if (totalNumFiles < 0)
|
||||
totalNumFiles = File (path).getNumberOfChildFiles (File::findFilesAndDirectories);
|
||||
|
||||
if (totalNumFiles <= 0)
|
||||
return 0.0f;
|
||||
|
||||
const float detailedIndex = (subIterator != nullptr) ? index + subIterator->getEstimatedProgress()
|
||||
: (float) index;
|
||||
|
||||
return detailedIndex / totalNumFiles;
|
||||
}
|
||||
154
modules/beast_core/files/beast_DirectoryIterator.h
Normal file
154
modules/beast_core/files/beast_DirectoryIterator.h
Normal file
@@ -0,0 +1,154 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_DIRECTORYITERATOR_BEASTHEADER
|
||||
#define BEAST_DIRECTORYITERATOR_BEASTHEADER
|
||||
|
||||
#include "beast_File.h"
|
||||
#include "../memory/beast_ScopedPointer.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Searches through a the files in a directory, returning each file that is found.
|
||||
|
||||
A DirectoryIterator will search through a directory and its subdirectories using
|
||||
a wildcard filepattern match.
|
||||
|
||||
If you may be finding a large number of files, this is better than
|
||||
using File::findChildFiles() because it doesn't block while it finds them
|
||||
all, and this is more memory-efficient.
|
||||
|
||||
It can also guess how far it's got using a wildly inaccurate algorithm.
|
||||
*/
|
||||
class BEAST_API DirectoryIterator
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a DirectoryIterator for a given directory.
|
||||
|
||||
After creating one of these, call its next() method to get the
|
||||
first file - e.g. @code
|
||||
|
||||
DirectoryIterator iter (File ("/animals/mooses"), true, "*.moose");
|
||||
|
||||
while (iter.next())
|
||||
{
|
||||
File theFileItFound (iter.getFile());
|
||||
|
||||
... etc
|
||||
}
|
||||
@endcode
|
||||
|
||||
@param directory the directory to search in
|
||||
@param isRecursive whether all the subdirectories should also be searched
|
||||
@param wildCard the file pattern to match. This may contain multiple patterns
|
||||
separated by a semi-colon or comma, e.g. "*.jpg;*.png"
|
||||
@param whatToLookFor a value from the File::TypesOfFileToFind enum, specifying
|
||||
whether to look for files, directories, or both.
|
||||
*/
|
||||
DirectoryIterator (const File& directory,
|
||||
bool isRecursive,
|
||||
const String& wildCard = "*",
|
||||
int whatToLookFor = File::findFiles);
|
||||
|
||||
/** Destructor. */
|
||||
~DirectoryIterator();
|
||||
|
||||
/** Moves the iterator along to the next file.
|
||||
|
||||
@returns true if a file was found (you can then use getFile() to see what it was) - or
|
||||
false if there are no more matching files.
|
||||
*/
|
||||
bool next();
|
||||
|
||||
/** Moves the iterator along to the next file, and returns various properties of that file.
|
||||
|
||||
If you need to find out details about the file, it's more efficient to call this method than
|
||||
to call the normal next() method and then find out the details afterwards.
|
||||
|
||||
All the parameters are optional, so pass null pointers for any items that you're not
|
||||
interested in.
|
||||
|
||||
@returns true if a file was found (you can then use getFile() to see what it was) - or
|
||||
false if there are no more matching files. If it returns false, then none of the
|
||||
parameters will be filled-in.
|
||||
*/
|
||||
bool next (bool* isDirectory,
|
||||
bool* isHidden,
|
||||
int64* fileSize,
|
||||
Time* modTime,
|
||||
Time* creationTime,
|
||||
bool* isReadOnly);
|
||||
|
||||
/** Returns the file that the iterator is currently pointing at.
|
||||
|
||||
The result of this call is only valid after a call to next() has returned true.
|
||||
*/
|
||||
const File& getFile() const;
|
||||
|
||||
/** Returns a guess of how far through the search the iterator has got.
|
||||
|
||||
@returns a value 0.0 to 1.0 to show the progress, although this won't be
|
||||
very accurate.
|
||||
*/
|
||||
float getEstimatedProgress() const;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class NativeIterator
|
||||
{
|
||||
public:
|
||||
NativeIterator (const File& directory, const String& wildCard);
|
||||
~NativeIterator();
|
||||
|
||||
bool next (String& filenameFound,
|
||||
bool* isDirectory, bool* isHidden, int64* fileSize,
|
||||
Time* modTime, Time* creationTime, bool* isReadOnly);
|
||||
|
||||
class Pimpl;
|
||||
|
||||
private:
|
||||
friend class DirectoryIterator;
|
||||
friend class ScopedPointer<Pimpl>;
|
||||
ScopedPointer<Pimpl> pimpl;
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeIterator)
|
||||
};
|
||||
|
||||
friend class ScopedPointer<NativeIterator::Pimpl>;
|
||||
StringArray wildCards;
|
||||
NativeIterator fileFinder;
|
||||
String wildCard, path;
|
||||
int index;
|
||||
mutable int totalNumFiles;
|
||||
const int whatToLookFor;
|
||||
const bool isRecursive;
|
||||
bool hasBeenAdvanced;
|
||||
ScopedPointer <DirectoryIterator> subIterator;
|
||||
File currentFile;
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DirectoryIterator)
|
||||
};
|
||||
|
||||
#endif // BEAST_DIRECTORYITERATOR_BEASTHEADER
|
||||
1086
modules/beast_core/files/beast_File.cpp
Normal file
1086
modules/beast_core/files/beast_File.cpp
Normal file
File diff suppressed because it is too large
Load Diff
955
modules/beast_core/files/beast_File.h
Normal file
955
modules/beast_core/files/beast_File.h
Normal file
@@ -0,0 +1,955 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_FILE_BEASTHEADER
|
||||
#define BEAST_FILE_BEASTHEADER
|
||||
|
||||
#include "../containers/beast_Array.h"
|
||||
#include "../time/beast_Time.h"
|
||||
#include "../text/beast_StringArray.h"
|
||||
#include "../memory/beast_MemoryBlock.h"
|
||||
#include "../memory/beast_ScopedPointer.h"
|
||||
#include "../misc/beast_Result.h"
|
||||
class FileInputStream;
|
||||
class FileOutputStream;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Represents a local file or directory.
|
||||
|
||||
This class encapsulates the absolute pathname of a file or directory, and
|
||||
has methods for finding out about the file and changing its properties.
|
||||
|
||||
To read or write to the file, there are methods for returning an input or
|
||||
output stream.
|
||||
|
||||
@see FileInputStream, FileOutputStream
|
||||
*/
|
||||
class BEAST_API File
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an (invalid) file object.
|
||||
|
||||
The file is initially set to an empty path, so getFullPath() will return
|
||||
an empty string, and comparing the file to File::nonexistent will return
|
||||
true.
|
||||
|
||||
You can use its operator= method to point it at a proper file.
|
||||
*/
|
||||
File() noexcept {}
|
||||
|
||||
/** Creates a file from an absolute path.
|
||||
|
||||
If the path supplied is a relative path, it is taken to be relative
|
||||
to the current working directory (see File::getCurrentWorkingDirectory()),
|
||||
but this isn't a recommended way of creating a file, because you
|
||||
never know what the CWD is going to be.
|
||||
|
||||
On the Mac/Linux, the path can include "~" notation for referring to
|
||||
user home directories.
|
||||
*/
|
||||
File (const String& path);
|
||||
|
||||
/** Creates a copy of another file object. */
|
||||
File (const File& other);
|
||||
|
||||
/** Destructor. */
|
||||
~File() noexcept {}
|
||||
|
||||
/** Sets the file based on an absolute pathname.
|
||||
|
||||
If the path supplied is a relative path, it is taken to be relative
|
||||
to the current working directory (see File::getCurrentWorkingDirectory()),
|
||||
but this isn't a recommended way of creating a file, because you
|
||||
never know what the CWD is going to be.
|
||||
|
||||
On the Mac/Linux, the path can include "~" notation for referring to
|
||||
user home directories.
|
||||
*/
|
||||
File& operator= (const String& newFilePath);
|
||||
|
||||
/** Copies from another file object. */
|
||||
File& operator= (const File& otherFile);
|
||||
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
File (File&& otherFile) noexcept;
|
||||
File& operator= (File&& otherFile) noexcept;
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
/** This static constant is used for referring to an 'invalid' file. */
|
||||
static const File nonexistent;
|
||||
|
||||
//==============================================================================
|
||||
/** Checks whether the file actually exists.
|
||||
|
||||
@returns true if the file exists, either as a file or a directory.
|
||||
@see existsAsFile, isDirectory
|
||||
*/
|
||||
bool exists() const;
|
||||
|
||||
/** Checks whether the file exists and is a file rather than a directory.
|
||||
|
||||
@returns true only if this is a real file, false if it's a directory
|
||||
or doesn't exist
|
||||
@see exists, isDirectory
|
||||
*/
|
||||
bool existsAsFile() const;
|
||||
|
||||
/** Checks whether the file is a directory that exists.
|
||||
|
||||
@returns true only if the file is a directory which actually exists, so
|
||||
false if it's a file or doesn't exist at all
|
||||
@see exists, existsAsFile
|
||||
*/
|
||||
bool isDirectory() const;
|
||||
|
||||
/** Returns the size of the file in bytes.
|
||||
|
||||
@returns the number of bytes in the file, or 0 if it doesn't exist.
|
||||
*/
|
||||
int64 getSize() const;
|
||||
|
||||
/** Utility function to convert a file size in bytes to a neat string description.
|
||||
|
||||
So for example 100 would return "100 bytes", 2000 would return "2 KB",
|
||||
2000000 would produce "2 MB", etc.
|
||||
*/
|
||||
static String descriptionOfSizeInBytes (int64 bytes);
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the complete, absolute path of this file.
|
||||
|
||||
This includes the filename and all its parent folders. On Windows it'll
|
||||
also include the drive letter prefix; on Mac or Linux it'll be a complete
|
||||
path starting from the root folder.
|
||||
|
||||
If you just want the file's name, you should use getFileName() or
|
||||
getFileNameWithoutExtension().
|
||||
|
||||
@see getFileName, getRelativePathFrom
|
||||
*/
|
||||
const String& getFullPathName() const noexcept { return fullPath; }
|
||||
|
||||
/** Returns the last section of the pathname.
|
||||
|
||||
Returns just the final part of the path - e.g. if the whole path
|
||||
is "/moose/fish/foo.txt" this will return "foo.txt".
|
||||
|
||||
For a directory, it returns the final part of the path - e.g. for the
|
||||
directory "/moose/fish" it'll return "fish".
|
||||
|
||||
If the filename begins with a dot, it'll return the whole filename, e.g. for
|
||||
"/moose/.fish", it'll return ".fish"
|
||||
|
||||
@see getFullPathName, getFileNameWithoutExtension
|
||||
*/
|
||||
String getFileName() const;
|
||||
|
||||
/** Creates a relative path that refers to a file relatively to a given directory.
|
||||
|
||||
e.g. File ("/moose/foo.txt").getRelativePathFrom (File ("/moose/fish/haddock"))
|
||||
would return "../../foo.txt".
|
||||
|
||||
If it's not possible to navigate from one file to the other, an absolute
|
||||
path is returned. If the paths are invalid, an empty string may also be
|
||||
returned.
|
||||
|
||||
@param directoryToBeRelativeTo the directory which the resultant string will
|
||||
be relative to. If this is actually a file rather than
|
||||
a directory, its parent directory will be used instead.
|
||||
If it doesn't exist, it's assumed to be a directory.
|
||||
@see getChildFile, isAbsolutePath
|
||||
*/
|
||||
String getRelativePathFrom (const File& directoryToBeRelativeTo) const;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the file's extension.
|
||||
|
||||
Returns the file extension of this file, also including the dot.
|
||||
|
||||
e.g. "/moose/fish/foo.txt" would return ".txt"
|
||||
|
||||
@see hasFileExtension, withFileExtension, getFileNameWithoutExtension
|
||||
*/
|
||||
String getFileExtension() const;
|
||||
|
||||
/** Checks whether the file has a given extension.
|
||||
|
||||
@param extensionToTest the extension to look for - it doesn't matter whether or
|
||||
not this string has a dot at the start, so ".wav" and "wav"
|
||||
will have the same effect. The comparison used is
|
||||
case-insensitve. To compare with multiple extensions, this
|
||||
parameter can contain multiple strings, separated by semi-colons -
|
||||
so, for example: hasFileExtension (".jpeg;png;gif") would return
|
||||
true if the file has any of those three extensions.
|
||||
|
||||
@see getFileExtension, withFileExtension, getFileNameWithoutExtension
|
||||
*/
|
||||
bool hasFileExtension (const String& extensionToTest) const;
|
||||
|
||||
/** Returns a version of this file with a different file extension.
|
||||
|
||||
e.g. File ("/moose/fish/foo.txt").withFileExtension ("html") returns "/moose/fish/foo.html"
|
||||
|
||||
@param newExtension the new extension, either with or without a dot at the start (this
|
||||
doesn't make any difference). To get remove a file's extension altogether,
|
||||
pass an empty string into this function.
|
||||
|
||||
@see getFileName, getFileExtension, hasFileExtension, getFileNameWithoutExtension
|
||||
*/
|
||||
File withFileExtension (const String& newExtension) const;
|
||||
|
||||
/** Returns the last part of the filename, without its file extension.
|
||||
|
||||
e.g. for "/moose/fish/foo.txt" this will return "foo".
|
||||
|
||||
@see getFileName, getFileExtension, hasFileExtension, withFileExtension
|
||||
*/
|
||||
String getFileNameWithoutExtension() const;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a 32-bit hash-code that identifies this file.
|
||||
|
||||
This is based on the filename. Obviously it's possible, although unlikely, that
|
||||
two files will have the same hash-code.
|
||||
*/
|
||||
int hashCode() const;
|
||||
|
||||
/** Returns a 64-bit hash-code that identifies this file.
|
||||
|
||||
This is based on the filename. Obviously it's possible, although unlikely, that
|
||||
two files will have the same hash-code.
|
||||
*/
|
||||
int64 hashCode64() const;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a file based on a relative path.
|
||||
|
||||
This will find a child file or directory of the current object.
|
||||
|
||||
e.g.
|
||||
File ("/moose/fish").getChildFile ("foo.txt") will produce "/moose/fish/foo.txt".
|
||||
File ("/moose/fish").getChildFile ("../foo.txt") will produce "/moose/foo.txt".
|
||||
|
||||
If the string is actually an absolute path, it will be treated as such, e.g.
|
||||
File ("/moose/fish").getChildFile ("/foo.txt") will produce "/foo.txt"
|
||||
|
||||
@see getSiblingFile, getParentDirectory, getRelativePathFrom, isAChildOf
|
||||
*/
|
||||
File getChildFile (String relativePath) const;
|
||||
|
||||
/** Returns a file which is in the same directory as this one.
|
||||
|
||||
This is equivalent to getParentDirectory().getChildFile (name).
|
||||
|
||||
@see getChildFile, getParentDirectory
|
||||
*/
|
||||
File getSiblingFile (const String& siblingFileName) const;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the directory that contains this file or directory.
|
||||
|
||||
e.g. for "/moose/fish/foo.txt" this will return "/moose/fish".
|
||||
*/
|
||||
File getParentDirectory() const;
|
||||
|
||||
/** Checks whether a file is somewhere inside a directory.
|
||||
|
||||
Returns true if this file is somewhere inside a subdirectory of the directory
|
||||
that is passed in. Neither file actually has to exist, because the function
|
||||
just checks the paths for similarities.
|
||||
|
||||
e.g. File ("/moose/fish/foo.txt").isAChildOf ("/moose") is true.
|
||||
File ("/moose/fish/foo.txt").isAChildOf ("/moose/fish") is also true.
|
||||
*/
|
||||
bool isAChildOf (const File& potentialParentDirectory) const;
|
||||
|
||||
//==============================================================================
|
||||
/** Chooses a filename relative to this one that doesn't already exist.
|
||||
|
||||
If this file is a directory, this will return a child file of this
|
||||
directory that doesn't exist, by adding numbers to a prefix and suffix until
|
||||
it finds one that isn't already there.
|
||||
|
||||
If the prefix + the suffix doesn't exist, it won't bother adding a number.
|
||||
|
||||
e.g. File ("/moose/fish").getNonexistentChildFile ("foo", ".txt", true) might
|
||||
return "/moose/fish/foo(2).txt" if there's already a file called "foo.txt".
|
||||
|
||||
@param prefix the string to use for the filename before the number
|
||||
@param suffix the string to add to the filename after the number
|
||||
@param putNumbersInBrackets if true, this will create filenames in the
|
||||
format "prefix(number)suffix", if false, it will leave the
|
||||
brackets out.
|
||||
*/
|
||||
File getNonexistentChildFile (const String& prefix,
|
||||
const String& suffix,
|
||||
bool putNumbersInBrackets = true) const;
|
||||
|
||||
/** Chooses a filename for a sibling file to this one that doesn't already exist.
|
||||
|
||||
If this file doesn't exist, this will just return itself, otherwise it
|
||||
will return an appropriate sibling that doesn't exist, e.g. if a file
|
||||
"/moose/fish/foo.txt" exists, this might return "/moose/fish/foo(2).txt".
|
||||
|
||||
@param putNumbersInBrackets whether to add brackets around the numbers that
|
||||
get appended to the new filename.
|
||||
*/
|
||||
File getNonexistentSibling (bool putNumbersInBrackets = true) const;
|
||||
|
||||
//==============================================================================
|
||||
/** Compares the pathnames for two files. */
|
||||
bool operator== (const File& otherFile) const;
|
||||
/** Compares the pathnames for two files. */
|
||||
bool operator!= (const File& otherFile) const;
|
||||
/** Compares the pathnames for two files. */
|
||||
bool operator< (const File& otherFile) const;
|
||||
/** Compares the pathnames for two files. */
|
||||
bool operator> (const File& otherFile) const;
|
||||
|
||||
//==============================================================================
|
||||
/** Checks whether a file can be created or written to.
|
||||
|
||||
@returns true if it's possible to create and write to this file. If the file
|
||||
doesn't already exist, this will check its parent directory to
|
||||
see if writing is allowed.
|
||||
@see setReadOnly
|
||||
*/
|
||||
bool hasWriteAccess() const;
|
||||
|
||||
/** Changes the write-permission of a file or directory.
|
||||
|
||||
@param shouldBeReadOnly whether to add or remove write-permission
|
||||
@param applyRecursively if the file is a directory and this is true, it will
|
||||
recurse through all the subfolders changing the permissions
|
||||
of all files
|
||||
@returns true if it manages to change the file's permissions.
|
||||
@see hasWriteAccess
|
||||
*/
|
||||
bool setReadOnly (bool shouldBeReadOnly,
|
||||
bool applyRecursively = false) const;
|
||||
|
||||
/** Returns true if this file is a hidden or system file.
|
||||
The criteria for deciding whether a file is hidden are platform-dependent.
|
||||
*/
|
||||
bool isHidden() const;
|
||||
|
||||
/** If this file is a link, this returns the file that it points to.
|
||||
If this file isn't actually link, it'll just return itself.
|
||||
*/
|
||||
File getLinkedTarget() const;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the last modification time of this file.
|
||||
|
||||
@returns the time, or an invalid time if the file doesn't exist.
|
||||
@see setLastModificationTime, getLastAccessTime, getCreationTime
|
||||
*/
|
||||
Time getLastModificationTime() const;
|
||||
|
||||
/** Returns the last time this file was accessed.
|
||||
|
||||
@returns the time, or an invalid time if the file doesn't exist.
|
||||
@see setLastAccessTime, getLastModificationTime, getCreationTime
|
||||
*/
|
||||
Time getLastAccessTime() const;
|
||||
|
||||
/** Returns the time that this file was created.
|
||||
|
||||
@returns the time, or an invalid time if the file doesn't exist.
|
||||
@see getLastModificationTime, getLastAccessTime
|
||||
*/
|
||||
Time getCreationTime() const;
|
||||
|
||||
/** Changes the modification time for this file.
|
||||
|
||||
@param newTime the time to apply to the file
|
||||
@returns true if it manages to change the file's time.
|
||||
@see getLastModificationTime, setLastAccessTime, setCreationTime
|
||||
*/
|
||||
bool setLastModificationTime (Time newTime) const;
|
||||
|
||||
/** Changes the last-access time for this file.
|
||||
|
||||
@param newTime the time to apply to the file
|
||||
@returns true if it manages to change the file's time.
|
||||
@see getLastAccessTime, setLastModificationTime, setCreationTime
|
||||
*/
|
||||
bool setLastAccessTime (Time newTime) const;
|
||||
|
||||
/** Changes the creation date for this file.
|
||||
|
||||
@param newTime the time to apply to the file
|
||||
@returns true if it manages to change the file's time.
|
||||
@see getCreationTime, setLastModificationTime, setLastAccessTime
|
||||
*/
|
||||
bool setCreationTime (Time newTime) const;
|
||||
|
||||
/** If possible, this will try to create a version string for the given file.
|
||||
|
||||
The OS may be able to look at the file and give a version for it - e.g. with
|
||||
executables, bundles, dlls, etc. If no version is available, this will
|
||||
return an empty string.
|
||||
*/
|
||||
String getVersion() const;
|
||||
|
||||
//==============================================================================
|
||||
/** Creates an empty file if it doesn't already exist.
|
||||
|
||||
If the file that this object refers to doesn't exist, this will create a file
|
||||
of zero size.
|
||||
|
||||
If it already exists or is a directory, this method will do nothing.
|
||||
|
||||
@returns true if the file has been created (or if it already existed).
|
||||
@see createDirectory
|
||||
*/
|
||||
Result create() const;
|
||||
|
||||
/** Creates a new directory for this filename.
|
||||
|
||||
This will try to create the file as a directory, and fill also create
|
||||
any parent directories it needs in order to complete the operation.
|
||||
|
||||
@returns a result to indicate whether the directory was created successfully, or
|
||||
an error message if it failed.
|
||||
@see create
|
||||
*/
|
||||
Result createDirectory() const;
|
||||
|
||||
/** Deletes a file.
|
||||
|
||||
If this file is actually a directory, it may not be deleted correctly if it
|
||||
contains files. See deleteRecursively() as a better way of deleting directories.
|
||||
|
||||
@returns true if the file has been successfully deleted (or if it didn't exist to
|
||||
begin with).
|
||||
@see deleteRecursively
|
||||
*/
|
||||
bool deleteFile() const;
|
||||
|
||||
/** Deletes a file or directory and all its subdirectories.
|
||||
|
||||
If this file is a directory, this will try to delete it and all its subfolders. If
|
||||
it's just a file, it will just try to delete the file.
|
||||
|
||||
@returns true if the file and all its subfolders have been successfully deleted
|
||||
(or if it didn't exist to begin with).
|
||||
@see deleteFile
|
||||
*/
|
||||
bool deleteRecursively() const;
|
||||
|
||||
/** Moves this file or folder to the trash.
|
||||
|
||||
@returns true if the operation succeeded. It could fail if the trash is full, or
|
||||
if the file is write-protected, so you should check the return value
|
||||
and act appropriately.
|
||||
*/
|
||||
bool moveToTrash() const;
|
||||
|
||||
/** Moves or renames a file.
|
||||
|
||||
Tries to move a file to a different location.
|
||||
If the target file already exists, this will attempt to delete it first, and
|
||||
will fail if this can't be done.
|
||||
|
||||
Note that the destination file isn't the directory to put it in, it's the actual
|
||||
filename that you want the new file to have.
|
||||
|
||||
@returns true if the operation succeeds
|
||||
*/
|
||||
bool moveFileTo (const File& targetLocation) const;
|
||||
|
||||
/** Copies a file.
|
||||
|
||||
Tries to copy a file to a different location.
|
||||
If the target file already exists, this will attempt to delete it first, and
|
||||
will fail if this can't be done.
|
||||
|
||||
@returns true if the operation succeeds
|
||||
*/
|
||||
bool copyFileTo (const File& targetLocation) const;
|
||||
|
||||
/** Copies a directory.
|
||||
|
||||
Tries to copy an entire directory, recursively.
|
||||
|
||||
If this file isn't a directory or if any target files can't be created, this
|
||||
will return false.
|
||||
|
||||
@param newDirectory the directory that this one should be copied to. Note that this
|
||||
is the name of the actual directory to create, not the directory
|
||||
into which the new one should be placed, so there must be enough
|
||||
write privileges to create it if it doesn't exist. Any files inside
|
||||
it will be overwritten by similarly named ones that are copied.
|
||||
*/
|
||||
bool copyDirectoryTo (const File& newDirectory) const;
|
||||
|
||||
//==============================================================================
|
||||
/** Used in file searching, to specify whether to return files, directories, or both.
|
||||
*/
|
||||
enum TypesOfFileToFind
|
||||
{
|
||||
findDirectories = 1, /**< Use this flag to indicate that you want to find directories. */
|
||||
findFiles = 2, /**< Use this flag to indicate that you want to find files. */
|
||||
findFilesAndDirectories = 3, /**< Use this flag to indicate that you want to find both files and directories. */
|
||||
ignoreHiddenFiles = 4 /**< Add this flag to avoid returning any hidden files in the results. */
|
||||
};
|
||||
|
||||
/** Searches inside a directory for files matching a wildcard pattern.
|
||||
|
||||
Assuming that this file is a directory, this method will search it
|
||||
for either files or subdirectories whose names match a filename pattern.
|
||||
|
||||
@param results an array to which File objects will be added for the
|
||||
files that the search comes up with
|
||||
@param whatToLookFor a value from the TypesOfFileToFind enum, specifying whether to
|
||||
return files, directories, or both. If the ignoreHiddenFiles flag
|
||||
is also added to this value, hidden files won't be returned
|
||||
@param searchRecursively if true, all subdirectories will be recursed into to do
|
||||
an exhaustive search
|
||||
@param wildCardPattern the filename pattern to search for, e.g. "*.txt"
|
||||
@returns the number of results that have been found
|
||||
|
||||
@see getNumberOfChildFiles, DirectoryIterator
|
||||
*/
|
||||
int findChildFiles (Array<File>& results,
|
||||
int whatToLookFor,
|
||||
bool searchRecursively,
|
||||
const String& wildCardPattern = "*") const;
|
||||
|
||||
/** Searches inside a directory and counts how many files match a wildcard pattern.
|
||||
|
||||
Assuming that this file is a directory, this method will search it
|
||||
for either files or subdirectories whose names match a filename pattern,
|
||||
and will return the number of matches found.
|
||||
|
||||
This isn't a recursive call, and will only search this directory, not
|
||||
its children.
|
||||
|
||||
@param whatToLookFor a value from the TypesOfFileToFind enum, specifying whether to
|
||||
count files, directories, or both. If the ignoreHiddenFiles flag
|
||||
is also added to this value, hidden files won't be counted
|
||||
@param wildCardPattern the filename pattern to search for, e.g. "*.txt"
|
||||
@returns the number of matches found
|
||||
@see findChildFiles, DirectoryIterator
|
||||
*/
|
||||
int getNumberOfChildFiles (int whatToLookFor,
|
||||
const String& wildCardPattern = "*") const;
|
||||
|
||||
/** Returns true if this file is a directory that contains one or more subdirectories.
|
||||
@see isDirectory, findChildFiles
|
||||
*/
|
||||
bool containsSubDirectories() const;
|
||||
|
||||
//==============================================================================
|
||||
/** Creates a stream to read from this file.
|
||||
|
||||
@returns a stream that will read from this file (initially positioned at the
|
||||
start of the file), or nullptr if the file can't be opened for some reason
|
||||
@see createOutputStream, loadFileAsData
|
||||
*/
|
||||
FileInputStream* createInputStream() const;
|
||||
|
||||
/** Creates a stream to write to this file.
|
||||
|
||||
If the file exists, the stream that is returned will be positioned ready for
|
||||
writing at the end of the file, so you might want to use deleteFile() first
|
||||
to write to an empty file.
|
||||
|
||||
@returns a stream that will write to this file (initially positioned at the
|
||||
end of the file), or nullptr if the file can't be opened for some reason
|
||||
@see createInputStream, appendData, appendText
|
||||
*/
|
||||
FileOutputStream* createOutputStream (int bufferSize = 0x8000) const;
|
||||
|
||||
//==============================================================================
|
||||
/** Loads a file's contents into memory as a block of binary data.
|
||||
|
||||
Of course, trying to load a very large file into memory will blow up, so
|
||||
it's better to check first.
|
||||
|
||||
@param result the data block to which the file's contents should be appended - note
|
||||
that if the memory block might already contain some data, you
|
||||
might want to clear it first
|
||||
@returns true if the file could all be read into memory
|
||||
*/
|
||||
bool loadFileAsData (MemoryBlock& result) const;
|
||||
|
||||
/** Reads a file into memory as a string.
|
||||
|
||||
Attempts to load the entire file as a zero-terminated string.
|
||||
|
||||
This makes use of InputStream::readEntireStreamAsString, which can
|
||||
read either UTF-16 or UTF-8 file formats.
|
||||
*/
|
||||
String loadFileAsString() const;
|
||||
|
||||
/** Reads the contents of this file as text and splits it into lines, which are
|
||||
appended to the given StringArray.
|
||||
*/
|
||||
void readLines (StringArray& destLines) const;
|
||||
|
||||
//==============================================================================
|
||||
/** Appends a block of binary data to the end of the file.
|
||||
|
||||
This will try to write the given buffer to the end of the file.
|
||||
|
||||
@returns false if it can't write to the file for some reason
|
||||
*/
|
||||
bool appendData (const void* dataToAppend,
|
||||
size_t numberOfBytes) const;
|
||||
|
||||
/** Replaces this file's contents with a given block of data.
|
||||
|
||||
This will delete the file and replace it with the given data.
|
||||
|
||||
A nice feature of this method is that it's safe - instead of deleting
|
||||
the file first and then re-writing it, it creates a new temporary file,
|
||||
writes the data to that, and then moves the new file to replace the existing
|
||||
file. This means that if the power gets pulled out or something crashes,
|
||||
you're a lot less likely to end up with a corrupted or unfinished file..
|
||||
|
||||
Returns true if the operation succeeds, or false if it fails.
|
||||
|
||||
@see appendText
|
||||
*/
|
||||
bool replaceWithData (const void* dataToWrite,
|
||||
size_t numberOfBytes) const;
|
||||
|
||||
/** Appends a string to the end of the file.
|
||||
|
||||
This will try to append a text string to the file, as either 16-bit unicode
|
||||
or 8-bit characters in the default system encoding.
|
||||
|
||||
It can also write the 'ff fe' unicode header bytes before the text to indicate
|
||||
the endianness of the file.
|
||||
|
||||
Any single \\n characters in the string are replaced with \\r\\n before it is written.
|
||||
|
||||
@see replaceWithText
|
||||
*/
|
||||
bool appendText (const String& textToAppend,
|
||||
bool asUnicode = false,
|
||||
bool writeUnicodeHeaderBytes = false) const;
|
||||
|
||||
/** Replaces this file's contents with a given text string.
|
||||
|
||||
This will delete the file and replace it with the given text.
|
||||
|
||||
A nice feature of this method is that it's safe - instead of deleting
|
||||
the file first and then re-writing it, it creates a new temporary file,
|
||||
writes the text to that, and then moves the new file to replace the existing
|
||||
file. This means that if the power gets pulled out or something crashes,
|
||||
you're a lot less likely to end up with an empty file..
|
||||
|
||||
For an explanation of the parameters here, see the appendText() method.
|
||||
|
||||
Returns true if the operation succeeds, or false if it fails.
|
||||
|
||||
@see appendText
|
||||
*/
|
||||
bool replaceWithText (const String& textToWrite,
|
||||
bool asUnicode = false,
|
||||
bool writeUnicodeHeaderBytes = false) const;
|
||||
|
||||
/** Attempts to scan the contents of this file and compare it to another file, returning
|
||||
true if this is possible and they match byte-for-byte.
|
||||
*/
|
||||
bool hasIdenticalContentTo (const File& other) const;
|
||||
|
||||
//==============================================================================
|
||||
/** Creates a set of files to represent each file root.
|
||||
|
||||
e.g. on Windows this will create files for "c:\", "d:\" etc according
|
||||
to which ones are available. On the Mac/Linux, this will probably
|
||||
just add a single entry for "/".
|
||||
*/
|
||||
static void findFileSystemRoots (Array<File>& results);
|
||||
|
||||
/** Finds the name of the drive on which this file lives.
|
||||
@returns the volume label of the drive, or an empty string if this isn't possible
|
||||
*/
|
||||
String getVolumeLabel() const;
|
||||
|
||||
/** Returns the serial number of the volume on which this file lives.
|
||||
@returns the serial number, or zero if there's a problem doing this
|
||||
*/
|
||||
int getVolumeSerialNumber() const;
|
||||
|
||||
/** Returns the number of bytes free on the drive that this file lives on.
|
||||
|
||||
@returns the number of bytes free, or 0 if there's a problem finding this out
|
||||
@see getVolumeTotalSize
|
||||
*/
|
||||
int64 getBytesFreeOnVolume() const;
|
||||
|
||||
/** Returns the total size of the drive that contains this file.
|
||||
|
||||
@returns the total number of bytes that the volume can hold
|
||||
@see getBytesFreeOnVolume
|
||||
*/
|
||||
int64 getVolumeTotalSize() const;
|
||||
|
||||
/** Returns true if this file is on a CD or DVD drive. */
|
||||
bool isOnCDRomDrive() const;
|
||||
|
||||
/** Returns true if this file is on a hard disk.
|
||||
|
||||
This will fail if it's a network drive, but will still be true for
|
||||
removable hard-disks.
|
||||
*/
|
||||
bool isOnHardDisk() const;
|
||||
|
||||
/** Returns true if this file is on a removable disk drive.
|
||||
|
||||
This might be a usb-drive, a CD-rom, or maybe a network drive.
|
||||
*/
|
||||
bool isOnRemovableDrive() const;
|
||||
|
||||
//==============================================================================
|
||||
/** Launches the file as a process.
|
||||
|
||||
- if the file is executable, this will run it.
|
||||
|
||||
- if it's a document of some kind, it will launch the document with its
|
||||
default viewer application.
|
||||
|
||||
- if it's a folder, it will be opened in Explorer, Finder, or equivalent.
|
||||
|
||||
@see revealToUser
|
||||
*/
|
||||
bool startAsProcess (const String& parameters = String::empty) const;
|
||||
|
||||
/** Opens Finder, Explorer, or whatever the OS uses, to show the user this file's location.
|
||||
@see startAsProcess
|
||||
*/
|
||||
void revealToUser() const;
|
||||
|
||||
//==============================================================================
|
||||
/** A set of types of location that can be passed to the getSpecialLocation() method.
|
||||
*/
|
||||
enum SpecialLocationType
|
||||
{
|
||||
/** The user's home folder. This is the same as using File ("~"). */
|
||||
userHomeDirectory,
|
||||
|
||||
/** The user's default documents folder. On Windows, this might be the user's
|
||||
"My Documents" folder. On the Mac it'll be their "Documents" folder. Linux
|
||||
doesn't tend to have one of these, so it might just return their home folder.
|
||||
*/
|
||||
userDocumentsDirectory,
|
||||
|
||||
/** The folder that contains the user's desktop objects. */
|
||||
userDesktopDirectory,
|
||||
|
||||
/** The folder in which applications store their persistent user-specific settings.
|
||||
On Windows, this might be "\Documents and Settings\username\Application Data".
|
||||
On the Mac, it might be "~/Library". If you're going to store your settings in here,
|
||||
always create your own sub-folder to put them in, to avoid making a mess.
|
||||
*/
|
||||
userApplicationDataDirectory,
|
||||
|
||||
/** An equivalent of the userApplicationDataDirectory folder that is shared by all users
|
||||
of the computer, rather than just the current user.
|
||||
|
||||
On the Mac it'll be "/Library", on Windows, it could be something like
|
||||
"\Documents and Settings\All Users\Application Data".
|
||||
|
||||
Depending on the setup, this folder may be read-only.
|
||||
*/
|
||||
commonApplicationDataDirectory,
|
||||
|
||||
/** The folder that should be used for temporary files.
|
||||
Always delete them when you're finished, to keep the user's computer tidy!
|
||||
*/
|
||||
tempDirectory,
|
||||
|
||||
/** Returns this application's executable file.
|
||||
|
||||
If running as a plug-in or DLL, this will (where possible) be the DLL rather than the
|
||||
host app.
|
||||
|
||||
On the mac this will return the unix binary, not the package folder - see
|
||||
currentApplicationFile for that.
|
||||
|
||||
See also invokedExecutableFile, which is similar, but if the exe was launched from a
|
||||
file link, invokedExecutableFile will return the name of the link.
|
||||
*/
|
||||
currentExecutableFile,
|
||||
|
||||
/** Returns this application's location.
|
||||
|
||||
If running as a plug-in or DLL, this will (where possible) be the DLL rather than the
|
||||
host app.
|
||||
|
||||
On the mac this will return the package folder (if it's in one), not the unix binary
|
||||
that's inside it - compare with currentExecutableFile.
|
||||
*/
|
||||
currentApplicationFile,
|
||||
|
||||
/** Returns the file that was invoked to launch this executable.
|
||||
This may differ from currentExecutableFile if the app was started from e.g. a link - this
|
||||
will return the name of the link that was used, whereas currentExecutableFile will return
|
||||
the actual location of the target executable.
|
||||
*/
|
||||
invokedExecutableFile,
|
||||
|
||||
/** In a plugin, this will return the path of the host executable. */
|
||||
hostApplicationPath,
|
||||
|
||||
/** The directory in which applications normally get installed.
|
||||
So on windows, this would be something like "c:\program files", on the
|
||||
Mac "/Applications", or "/usr" on linux.
|
||||
*/
|
||||
globalApplicationsDirectory,
|
||||
|
||||
/** The most likely place where a user might store their music files. */
|
||||
userMusicDirectory,
|
||||
|
||||
/** The most likely place where a user might store their movie files. */
|
||||
userMoviesDirectory,
|
||||
|
||||
/** The most likely place where a user might store their picture files. */
|
||||
userPicturesDirectory
|
||||
};
|
||||
|
||||
/** Finds the location of a special type of file or directory, such as a home folder or
|
||||
documents folder.
|
||||
|
||||
@see SpecialLocationType
|
||||
*/
|
||||
static File BEAST_CALLTYPE getSpecialLocation (const SpecialLocationType type);
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a temporary file in the system's temp directory.
|
||||
This will try to return the name of a non-existent temp file.
|
||||
To get the temp folder, you can use getSpecialLocation (File::tempDirectory).
|
||||
*/
|
||||
static File createTempFile (const String& fileNameEnding);
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the current working directory.
|
||||
@see setAsCurrentWorkingDirectory
|
||||
*/
|
||||
static File getCurrentWorkingDirectory();
|
||||
|
||||
/** Sets the current working directory to be this file.
|
||||
|
||||
For this to work the file must point to a valid directory.
|
||||
|
||||
@returns true if the current directory has been changed.
|
||||
@see getCurrentWorkingDirectory
|
||||
*/
|
||||
bool setAsCurrentWorkingDirectory() const;
|
||||
|
||||
//==============================================================================
|
||||
/** The system-specific file separator character.
|
||||
On Windows, this will be '\', on Mac/Linux, it'll be '/'
|
||||
*/
|
||||
static const beast_wchar separator;
|
||||
|
||||
/** The system-specific file separator character, as a string.
|
||||
On Windows, this will be '\', on Mac/Linux, it'll be '/'
|
||||
*/
|
||||
static const String separatorString;
|
||||
|
||||
//==============================================================================
|
||||
/** Removes illegal characters from a filename.
|
||||
|
||||
This will return a copy of the given string after removing characters
|
||||
that are not allowed in a legal filename, and possibly shortening the
|
||||
string if it's too long.
|
||||
|
||||
Because this will remove slashes, don't use it on an absolute pathname.
|
||||
|
||||
@see createLegalPathName
|
||||
*/
|
||||
static String createLegalFileName (const String& fileNameToFix);
|
||||
|
||||
/** Removes illegal characters from a pathname.
|
||||
|
||||
Similar to createLegalFileName(), but this won't remove slashes, so can
|
||||
be used on a complete pathname.
|
||||
|
||||
@see createLegalFileName
|
||||
*/
|
||||
static String createLegalPathName (const String& pathNameToFix);
|
||||
|
||||
/** Indicates whether filenames are case-sensitive on the current operating system. */
|
||||
static bool areFileNamesCaseSensitive();
|
||||
|
||||
/** Returns true if the string seems to be a fully-specified absolute path. */
|
||||
static bool isAbsolutePath (const String& path);
|
||||
|
||||
/** Creates a file that simply contains this string, without doing the sanity-checking
|
||||
that the normal constructors do.
|
||||
|
||||
Best to avoid this unless you really know what you're doing.
|
||||
*/
|
||||
static File createFileWithoutCheckingPath (const String& path) noexcept;
|
||||
|
||||
/** Adds a separator character to the end of a path if it doesn't already have one. */
|
||||
static String addTrailingSeparator (const String& path);
|
||||
|
||||
#if BEAST_MAC || BEAST_IOS || DOXYGEN
|
||||
//==============================================================================
|
||||
/** OSX ONLY - Finds the OSType of a file from the its resources. */
|
||||
OSType getMacOSType() const;
|
||||
|
||||
/** OSX ONLY - Returns true if this file is actually a bundle. */
|
||||
bool isBundle() const;
|
||||
#endif
|
||||
|
||||
#if BEAST_MAC || DOXYGEN
|
||||
/** OSX ONLY - Adds this file to the OSX dock */
|
||||
void addToDock() const;
|
||||
#endif
|
||||
|
||||
#if BEAST_WINDOWS
|
||||
/** Windows ONLY - Creates a win32 .LNK shortcut file that links to this file. */
|
||||
bool createLink (const String& description, const File& linkFileToCreate) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
String fullPath;
|
||||
|
||||
static String parseAbsolutePath (const String&);
|
||||
String getPathUpToLastSlash() const;
|
||||
|
||||
Result createDirectoryInternal (const String&) const;
|
||||
bool copyInternal (const File&) const;
|
||||
bool moveInternal (const File&) const;
|
||||
bool setFileTimesInternal (int64 m, int64 a, int64 c) const;
|
||||
void getFileTimesInternal (int64& m, int64& a, int64& c) const;
|
||||
bool setFileReadOnlyInternal (bool) const;
|
||||
|
||||
BEAST_LEAK_DETECTOR (File)
|
||||
};
|
||||
|
||||
#endif // BEAST_FILE_BEASTHEADER
|
||||
90
modules/beast_core/files/beast_FileInputStream.cpp
Normal file
90
modules/beast_core/files/beast_FileInputStream.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
int64 beast_fileSetPosition (void* handle, int64 pos);
|
||||
|
||||
//==============================================================================
|
||||
FileInputStream::FileInputStream (const File& f)
|
||||
: file (f),
|
||||
fileHandle (nullptr),
|
||||
currentPosition (0),
|
||||
status (Result::ok()),
|
||||
needToSeek (true)
|
||||
{
|
||||
openHandle();
|
||||
}
|
||||
|
||||
FileInputStream::~FileInputStream()
|
||||
{
|
||||
closeHandle();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
int64 FileInputStream::getTotalLength()
|
||||
{
|
||||
return file.getSize();
|
||||
}
|
||||
|
||||
int FileInputStream::read (void* buffer, int bytesToRead)
|
||||
{
|
||||
bassert (openedOk());
|
||||
bassert (buffer != nullptr && bytesToRead >= 0);
|
||||
|
||||
if (needToSeek)
|
||||
{
|
||||
if (beast_fileSetPosition (fileHandle, currentPosition) < 0)
|
||||
return 0;
|
||||
|
||||
needToSeek = false;
|
||||
}
|
||||
|
||||
const size_t num = readInternal (buffer, (size_t) bytesToRead);
|
||||
currentPosition += num;
|
||||
|
||||
return (int) num;
|
||||
}
|
||||
|
||||
bool FileInputStream::isExhausted()
|
||||
{
|
||||
return currentPosition >= getTotalLength();
|
||||
}
|
||||
|
||||
int64 FileInputStream::getPosition()
|
||||
{
|
||||
return currentPosition;
|
||||
}
|
||||
|
||||
bool FileInputStream::setPosition (int64 pos)
|
||||
{
|
||||
bassert (openedOk());
|
||||
|
||||
if (pos != currentPosition)
|
||||
{
|
||||
pos = blimit ((int64) 0, getTotalLength(), pos);
|
||||
|
||||
needToSeek |= (currentPosition != pos);
|
||||
currentPosition = pos;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
94
modules/beast_core/files/beast_FileInputStream.h
Normal file
94
modules/beast_core/files/beast_FileInputStream.h
Normal file
@@ -0,0 +1,94 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_FILEINPUTSTREAM_BEASTHEADER
|
||||
#define BEAST_FILEINPUTSTREAM_BEASTHEADER
|
||||
|
||||
#include "beast_File.h"
|
||||
#include "../streams/beast_InputStream.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
An input stream that reads from a local file.
|
||||
|
||||
@see InputStream, FileOutputStream, File::createInputStream
|
||||
*/
|
||||
class BEAST_API FileInputStream : public InputStream
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a FileInputStream.
|
||||
|
||||
@param fileToRead the file to read from - if the file can't be accessed for some
|
||||
reason, then the stream will just contain no data
|
||||
*/
|
||||
explicit FileInputStream (const File& fileToRead);
|
||||
|
||||
/** Destructor. */
|
||||
~FileInputStream();
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the file that this stream is reading from. */
|
||||
const File& getFile() const noexcept { return file; }
|
||||
|
||||
/** Returns the status of the file stream.
|
||||
The result will be ok if the file opened successfully. If an error occurs while
|
||||
opening or reading from the file, this will contain an error message.
|
||||
*/
|
||||
const Result& getStatus() const noexcept { return status; }
|
||||
|
||||
/** Returns true if the stream couldn't be opened for some reason.
|
||||
@see getResult()
|
||||
*/
|
||||
bool failedToOpen() const noexcept { return status.failed(); }
|
||||
|
||||
/** Returns true if the stream opened without problems.
|
||||
@see getResult()
|
||||
*/
|
||||
bool openedOk() const noexcept { return status.wasOk(); }
|
||||
|
||||
|
||||
//==============================================================================
|
||||
int64 getTotalLength();
|
||||
int read (void* destBuffer, int maxBytesToRead);
|
||||
bool isExhausted();
|
||||
int64 getPosition();
|
||||
bool setPosition (int64 pos);
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
File file;
|
||||
void* fileHandle;
|
||||
int64 currentPosition;
|
||||
Result status;
|
||||
bool needToSeek;
|
||||
|
||||
void openHandle();
|
||||
void closeHandle();
|
||||
size_t readInternal (void* buffer, size_t numBytes);
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileInputStream)
|
||||
};
|
||||
|
||||
#endif // BEAST_FILEINPUTSTREAM_BEASTHEADER
|
||||
131
modules/beast_core/files/beast_FileOutputStream.cpp
Normal file
131
modules/beast_core/files/beast_FileOutputStream.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
int64 beast_fileSetPosition (void* handle, int64 pos);
|
||||
|
||||
//==============================================================================
|
||||
FileOutputStream::FileOutputStream (const File& f, const int bufferSize_)
|
||||
: file (f),
|
||||
fileHandle (nullptr),
|
||||
status (Result::ok()),
|
||||
currentPosition (0),
|
||||
bufferSize (bufferSize_),
|
||||
bytesInBuffer (0),
|
||||
buffer ((size_t) bmax (bufferSize_, 16))
|
||||
{
|
||||
openHandle();
|
||||
}
|
||||
|
||||
FileOutputStream::~FileOutputStream()
|
||||
{
|
||||
flushBuffer();
|
||||
flushInternal();
|
||||
closeHandle();
|
||||
}
|
||||
|
||||
int64 FileOutputStream::getPosition()
|
||||
{
|
||||
return currentPosition;
|
||||
}
|
||||
|
||||
bool FileOutputStream::setPosition (int64 newPosition)
|
||||
{
|
||||
if (newPosition != currentPosition)
|
||||
{
|
||||
flushBuffer();
|
||||
currentPosition = beast_fileSetPosition (fileHandle, newPosition);
|
||||
}
|
||||
|
||||
return newPosition == currentPosition;
|
||||
}
|
||||
|
||||
bool FileOutputStream::flushBuffer()
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
if (bytesInBuffer > 0)
|
||||
{
|
||||
ok = (writeInternal (buffer, bytesInBuffer) == (ssize_t) bytesInBuffer);
|
||||
bytesInBuffer = 0;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void FileOutputStream::flush()
|
||||
{
|
||||
flushBuffer();
|
||||
flushInternal();
|
||||
}
|
||||
|
||||
bool FileOutputStream::write (const void* const src, const size_t numBytes)
|
||||
{
|
||||
bassert (src != nullptr && ((ssize_t) numBytes) >= 0);
|
||||
|
||||
if (bytesInBuffer + numBytes < bufferSize)
|
||||
{
|
||||
memcpy (buffer + bytesInBuffer, src, numBytes);
|
||||
bytesInBuffer += numBytes;
|
||||
currentPosition += numBytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! flushBuffer())
|
||||
return false;
|
||||
|
||||
if (numBytes < bufferSize)
|
||||
{
|
||||
memcpy (buffer + bytesInBuffer, src, numBytes);
|
||||
bytesInBuffer += numBytes;
|
||||
currentPosition += numBytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
const ssize_t bytesWritten = writeInternal (src, numBytes);
|
||||
|
||||
if (bytesWritten < 0)
|
||||
return false;
|
||||
|
||||
currentPosition += bytesWritten;
|
||||
return bytesWritten == (ssize_t) numBytes;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FileOutputStream::writeRepeatedByte (uint8 byte, size_t numBytes)
|
||||
{
|
||||
bassert (((ssize_t) numBytes) >= 0);
|
||||
|
||||
if (bytesInBuffer + numBytes < bufferSize)
|
||||
{
|
||||
memset (buffer + bytesInBuffer, byte, numBytes);
|
||||
bytesInBuffer += numBytes;
|
||||
currentPosition += numBytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
OutputStream::writeRepeatedByte (byte, numBytes);
|
||||
}
|
||||
}
|
||||
114
modules/beast_core/files/beast_FileOutputStream.h
Normal file
114
modules/beast_core/files/beast_FileOutputStream.h
Normal file
@@ -0,0 +1,114 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_FILEOUTPUTSTREAM_BEASTHEADER
|
||||
#define BEAST_FILEOUTPUTSTREAM_BEASTHEADER
|
||||
|
||||
#include "beast_File.h"
|
||||
#include "../streams/beast_OutputStream.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
An output stream that writes into a local file.
|
||||
|
||||
@see OutputStream, FileInputStream, File::createOutputStream
|
||||
*/
|
||||
class BEAST_API FileOutputStream : public OutputStream
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a FileOutputStream.
|
||||
|
||||
If the file doesn't exist, it will first be created. If the file can't be
|
||||
created or opened, the failedToOpen() method will return
|
||||
true.
|
||||
|
||||
If the file already exists when opened, the stream's write-postion will
|
||||
be set to the end of the file. To overwrite an existing file,
|
||||
use File::deleteFile() before opening the stream, or use setPosition(0)
|
||||
after it's opened (although this won't truncate the file).
|
||||
|
||||
@see TemporaryFile
|
||||
*/
|
||||
FileOutputStream (const File& fileToWriteTo,
|
||||
int bufferSizeToUse = 16384);
|
||||
|
||||
/** Destructor. */
|
||||
~FileOutputStream();
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the file that this stream is writing to.
|
||||
*/
|
||||
const File& getFile() const { return file; }
|
||||
|
||||
/** Returns the status of the file stream.
|
||||
The result will be ok if the file opened successfully. If an error occurs while
|
||||
opening or writing to the file, this will contain an error message.
|
||||
*/
|
||||
const Result& getStatus() const noexcept { return status; }
|
||||
|
||||
/** Returns true if the stream couldn't be opened for some reason.
|
||||
@see getResult()
|
||||
*/
|
||||
bool failedToOpen() const noexcept { return status.failed(); }
|
||||
|
||||
/** Returns true if the stream opened without problems.
|
||||
@see getResult()
|
||||
*/
|
||||
bool openedOk() const noexcept { return status.wasOk(); }
|
||||
|
||||
/** Attempts to truncate the file to the current write position.
|
||||
To truncate a file to a specific size, first use setPosition() to seek to the
|
||||
appropriate location, and then call this method.
|
||||
*/
|
||||
Result truncate();
|
||||
|
||||
//==============================================================================
|
||||
void flush();
|
||||
int64 getPosition();
|
||||
bool setPosition (int64 pos);
|
||||
bool write (const void* data, size_t numBytes);
|
||||
void writeRepeatedByte (uint8 byte, size_t numTimesToRepeat);
|
||||
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
File file;
|
||||
void* fileHandle;
|
||||
Result status;
|
||||
int64 currentPosition;
|
||||
size_t bufferSize, bytesInBuffer;
|
||||
HeapBlock <char> buffer;
|
||||
|
||||
void openHandle();
|
||||
void closeHandle();
|
||||
void flushInternal();
|
||||
bool flushBuffer();
|
||||
int64 setPositionInternal (int64);
|
||||
ssize_t writeInternal (const void*, size_t);
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileOutputStream)
|
||||
};
|
||||
|
||||
#endif // BEAST_FILEOUTPUTSTREAM_BEASTHEADER
|
||||
166
modules/beast_core/files/beast_FileSearchPath.cpp
Normal file
166
modules/beast_core/files/beast_FileSearchPath.cpp
Normal file
@@ -0,0 +1,166 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
FileSearchPath::FileSearchPath()
|
||||
{
|
||||
}
|
||||
|
||||
FileSearchPath::FileSearchPath (const String& path)
|
||||
{
|
||||
init (path);
|
||||
}
|
||||
|
||||
FileSearchPath::FileSearchPath (const FileSearchPath& other)
|
||||
: directories (other.directories)
|
||||
{
|
||||
}
|
||||
|
||||
FileSearchPath::~FileSearchPath()
|
||||
{
|
||||
}
|
||||
|
||||
FileSearchPath& FileSearchPath::operator= (const String& path)
|
||||
{
|
||||
init (path);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void FileSearchPath::init (const String& path)
|
||||
{
|
||||
directories.clear();
|
||||
directories.addTokens (path, ";", "\"");
|
||||
directories.trim();
|
||||
directories.removeEmptyStrings();
|
||||
|
||||
for (int i = directories.size(); --i >= 0;)
|
||||
directories.set (i, directories[i].unquoted());
|
||||
}
|
||||
|
||||
int FileSearchPath::getNumPaths() const
|
||||
{
|
||||
return directories.size();
|
||||
}
|
||||
|
||||
File FileSearchPath::operator[] (const int index) const
|
||||
{
|
||||
return File (directories [index]);
|
||||
}
|
||||
|
||||
String FileSearchPath::toString() const
|
||||
{
|
||||
StringArray directories2 (directories);
|
||||
for (int i = directories2.size(); --i >= 0;)
|
||||
if (directories2[i].containsChar (';'))
|
||||
directories2.set (i, directories2[i].quoted());
|
||||
|
||||
return directories2.joinIntoString (";");
|
||||
}
|
||||
|
||||
void FileSearchPath::add (const File& dir, const int insertIndex)
|
||||
{
|
||||
directories.insert (insertIndex, dir.getFullPathName());
|
||||
}
|
||||
|
||||
void FileSearchPath::addIfNotAlreadyThere (const File& dir)
|
||||
{
|
||||
for (int i = 0; i < directories.size(); ++i)
|
||||
if (File (directories[i]) == dir)
|
||||
return;
|
||||
|
||||
add (dir);
|
||||
}
|
||||
|
||||
void FileSearchPath::remove (const int index)
|
||||
{
|
||||
directories.remove (index);
|
||||
}
|
||||
|
||||
void FileSearchPath::addPath (const FileSearchPath& other)
|
||||
{
|
||||
for (int i = 0; i < other.getNumPaths(); ++i)
|
||||
addIfNotAlreadyThere (other[i]);
|
||||
}
|
||||
|
||||
void FileSearchPath::removeRedundantPaths()
|
||||
{
|
||||
for (int i = directories.size(); --i >= 0;)
|
||||
{
|
||||
const File d1 (directories[i]);
|
||||
|
||||
for (int j = directories.size(); --j >= 0;)
|
||||
{
|
||||
const File d2 (directories[j]);
|
||||
|
||||
if ((i != j) && (d1.isAChildOf (d2) || d1 == d2))
|
||||
{
|
||||
directories.remove (i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileSearchPath::removeNonExistentPaths()
|
||||
{
|
||||
for (int i = directories.size(); --i >= 0;)
|
||||
if (! File (directories[i]).isDirectory())
|
||||
directories.remove (i);
|
||||
}
|
||||
|
||||
int FileSearchPath::findChildFiles (Array<File>& results,
|
||||
const int whatToLookFor,
|
||||
const bool searchRecursively,
|
||||
const String& wildCardPattern) const
|
||||
{
|
||||
int total = 0;
|
||||
|
||||
for (int i = 0; i < directories.size(); ++i)
|
||||
total += operator[] (i).findChildFiles (results,
|
||||
whatToLookFor,
|
||||
searchRecursively,
|
||||
wildCardPattern);
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
bool FileSearchPath::isFileInPath (const File& fileToCheck,
|
||||
const bool checkRecursively) const
|
||||
{
|
||||
for (int i = directories.size(); --i >= 0;)
|
||||
{
|
||||
const File d (directories[i]);
|
||||
|
||||
if (checkRecursively)
|
||||
{
|
||||
if (fileToCheck.isAChildOf (d))
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fileToCheck.getParentDirectory() == d)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
164
modules/beast_core/files/beast_FileSearchPath.h
Normal file
164
modules/beast_core/files/beast_FileSearchPath.h
Normal file
@@ -0,0 +1,164 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_FILESEARCHPATH_BEASTHEADER
|
||||
#define BEAST_FILESEARCHPATH_BEASTHEADER
|
||||
|
||||
#include "beast_File.h"
|
||||
#include "../text/beast_StringArray.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Encapsulates a set of folders that make up a search path.
|
||||
|
||||
@see File
|
||||
*/
|
||||
class BEAST_API FileSearchPath
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an empty search path. */
|
||||
FileSearchPath();
|
||||
|
||||
/** Creates a search path from a string of pathnames.
|
||||
|
||||
The path can be semicolon- or comma-separated, e.g.
|
||||
"/foo/bar;/foo/moose;/fish/moose"
|
||||
|
||||
The separate folders are tokenised and added to the search path.
|
||||
*/
|
||||
FileSearchPath (const String& path);
|
||||
|
||||
/** Creates a copy of another search path. */
|
||||
FileSearchPath (const FileSearchPath& other);
|
||||
|
||||
/** Destructor. */
|
||||
~FileSearchPath();
|
||||
|
||||
/** Uses a string containing a list of pathnames to re-initialise this list.
|
||||
|
||||
This search path is cleared and the semicolon- or comma-separated folders
|
||||
in this string are added instead. e.g. "/foo/bar;/foo/moose;/fish/moose"
|
||||
*/
|
||||
FileSearchPath& operator= (const String& path);
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the number of folders in this search path.
|
||||
|
||||
@see operator[]
|
||||
*/
|
||||
int getNumPaths() const;
|
||||
|
||||
/** Returns one of the folders in this search path.
|
||||
|
||||
The file returned isn't guaranteed to actually be a valid directory.
|
||||
|
||||
@see getNumPaths
|
||||
*/
|
||||
File operator[] (int index) const;
|
||||
|
||||
/** Returns the search path as a semicolon-separated list of directories. */
|
||||
String toString() const;
|
||||
|
||||
//==============================================================================
|
||||
/** Adds a new directory to the search path.
|
||||
|
||||
The new directory is added to the end of the list if the insertIndex parameter is
|
||||
less than zero, otherwise it is inserted at the given index.
|
||||
*/
|
||||
void add (const File& directoryToAdd,
|
||||
int insertIndex = -1);
|
||||
|
||||
/** Adds a new directory to the search path if it's not already in there. */
|
||||
void addIfNotAlreadyThere (const File& directoryToAdd);
|
||||
|
||||
/** Removes a directory from the search path. */
|
||||
void remove (int indexToRemove);
|
||||
|
||||
/** Merges another search path into this one.
|
||||
|
||||
This will remove any duplicate directories.
|
||||
*/
|
||||
void addPath (const FileSearchPath& other);
|
||||
|
||||
/** Removes any directories that are actually subdirectories of one of the other directories in the search path.
|
||||
|
||||
If the search is intended to be recursive, there's no point having nested folders in the search
|
||||
path, because they'll just get searched twice and you'll get duplicate results.
|
||||
|
||||
e.g. if the path is "c:\abc\de;c:\abc", this method will simplify it to "c:\abc"
|
||||
*/
|
||||
void removeRedundantPaths();
|
||||
|
||||
/** Removes any directories that don't actually exist. */
|
||||
void removeNonExistentPaths();
|
||||
|
||||
//==============================================================================
|
||||
/** Searches the path for a wildcard.
|
||||
|
||||
This will search all the directories in the search path in order, adding any
|
||||
matching files to the results array.
|
||||
|
||||
@param results an array to append the results to
|
||||
@param whatToLookFor a value from the File::TypesOfFileToFind enum, specifying whether to
|
||||
return files, directories, or both.
|
||||
@param searchRecursively whether to recursively search the subdirectories too
|
||||
@param wildCardPattern a pattern to match against the filenames
|
||||
@returns the number of files added to the array
|
||||
@see File::findChildFiles
|
||||
*/
|
||||
int findChildFiles (Array<File>& results,
|
||||
int whatToLookFor,
|
||||
bool searchRecursively,
|
||||
const String& wildCardPattern = "*") const;
|
||||
|
||||
//==============================================================================
|
||||
/** Finds out whether a file is inside one of the path's directories.
|
||||
|
||||
This will return true if the specified file is a child of one of the
|
||||
directories specified by this path. Note that this doesn't actually do any
|
||||
searching or check that the files exist - it just looks at the pathnames
|
||||
to work out whether the file would be inside a directory.
|
||||
|
||||
@param fileToCheck the file to look for
|
||||
@param checkRecursively if true, then this will return true if the file is inside a
|
||||
subfolder of one of the path's directories (at any depth). If false
|
||||
it will only return true if the file is actually a direct child
|
||||
of one of the directories.
|
||||
@see File::isAChildOf
|
||||
|
||||
*/
|
||||
bool isFileInPath (const File& fileToCheck,
|
||||
bool checkRecursively) const;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
StringArray directories;
|
||||
|
||||
void init (const String& path);
|
||||
|
||||
BEAST_LEAK_DETECTOR (FileSearchPath)
|
||||
};
|
||||
|
||||
#endif // BEAST_FILESEARCHPATH_BEASTHEADER
|
||||
111
modules/beast_core/files/beast_MemoryMappedFile.h
Normal file
111
modules/beast_core/files/beast_MemoryMappedFile.h
Normal file
@@ -0,0 +1,111 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_MEMORYMAPPEDFILE_BEASTHEADER
|
||||
#define BEAST_MEMORYMAPPEDFILE_BEASTHEADER
|
||||
|
||||
#include "beast_File.h"
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Maps a file into virtual memory for easy reading and/or writing.
|
||||
*/
|
||||
class BEAST_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);
|
||||
|
||||
/** 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<int64>& fileRange,
|
||||
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 (size_t) range.getLength(); }
|
||||
|
||||
/** Returns the section of the file at which the mapped memory represents. */
|
||||
Range<int64> getRange() const noexcept { return range; }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
void* address;
|
||||
Range<int64> range;
|
||||
|
||||
#if BEAST_WINDOWS
|
||||
void* fileHandle;
|
||||
#else
|
||||
int fileHandle;
|
||||
#endif
|
||||
|
||||
void openInternal (const File&, AccessMode);
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryMappedFile)
|
||||
};
|
||||
|
||||
|
||||
#endif // BEAST_MEMORYMAPPEDFILE_BEASTHEADER
|
||||
112
modules/beast_core/files/beast_TemporaryFile.cpp
Normal file
112
modules/beast_core/files/beast_TemporaryFile.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
static File createTempFile (const File& parentDirectory, String name,
|
||||
const String& suffix, const int optionFlags)
|
||||
{
|
||||
if ((optionFlags & TemporaryFile::useHiddenFile) != 0)
|
||||
name = "." + name;
|
||||
|
||||
return parentDirectory.getNonexistentChildFile (name, suffix, (optionFlags & TemporaryFile::putNumbersInBrackets) != 0);
|
||||
}
|
||||
|
||||
TemporaryFile::TemporaryFile (const String& suffix, const int optionFlags)
|
||||
: temporaryFile (createTempFile (File::getSpecialLocation (File::tempDirectory),
|
||||
"temp_" + String::toHexString (Random::getSystemRandom().nextInt()),
|
||||
suffix, optionFlags))
|
||||
{
|
||||
}
|
||||
|
||||
TemporaryFile::TemporaryFile (const File& target, const int optionFlags)
|
||||
: temporaryFile (createTempFile (target.getParentDirectory(),
|
||||
target.getFileNameWithoutExtension()
|
||||
+ "_temp" + String::toHexString (Random::getSystemRandom().nextInt()),
|
||||
target.getFileExtension(), optionFlags)),
|
||||
targetFile (target)
|
||||
{
|
||||
// If you use this constructor, you need to give it a valid target file!
|
||||
bassert (targetFile != File::nonexistent);
|
||||
}
|
||||
|
||||
TemporaryFile::TemporaryFile (const File& target, const File& temporary)
|
||||
: temporaryFile (temporary), targetFile (target)
|
||||
{
|
||||
}
|
||||
|
||||
TemporaryFile::~TemporaryFile()
|
||||
{
|
||||
if (! deleteTemporaryFile())
|
||||
{
|
||||
/* Failed to delete our temporary file! The most likely reason for this would be
|
||||
that you've not closed an output stream that was being used to write to file.
|
||||
|
||||
If you find that something beyond your control is changing permissions on
|
||||
your temporary files and preventing them from being deleted, you may want to
|
||||
call TemporaryFile::deleteTemporaryFile() to detect those error cases and
|
||||
handle them appropriately.
|
||||
*/
|
||||
jassertfalse;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool TemporaryFile::overwriteTargetFileWithTemporary() const
|
||||
{
|
||||
// This method only works if you created this object with the constructor
|
||||
// that takes a target file!
|
||||
bassert (targetFile != File::nonexistent);
|
||||
|
||||
if (temporaryFile.exists())
|
||||
{
|
||||
// Have a few attempts at overwriting the file before giving up..
|
||||
for (int i = 5; --i >= 0;)
|
||||
{
|
||||
if (temporaryFile.moveFileTo (targetFile))
|
||||
return true;
|
||||
|
||||
Thread::sleep (100);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// There's no temporary file to use. If your write failed, you should
|
||||
// probably check, and not bother calling this method.
|
||||
jassertfalse;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TemporaryFile::deleteTemporaryFile() const
|
||||
{
|
||||
// Have a few attempts at deleting the file before giving up..
|
||||
for (int i = 5; --i >= 0;)
|
||||
{
|
||||
if (temporaryFile.deleteFile())
|
||||
return true;
|
||||
|
||||
Thread::sleep (50);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
166
modules/beast_core/files/beast_TemporaryFile.h
Normal file
166
modules/beast_core/files/beast_TemporaryFile.h
Normal file
@@ -0,0 +1,166 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_TEMPORARYFILE_BEASTHEADER
|
||||
#define BEAST_TEMPORARYFILE_BEASTHEADER
|
||||
|
||||
#include "beast_File.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Manages a temporary file, which will be deleted when this object is deleted.
|
||||
|
||||
This object is intended to be used as a stack based object, using its scope
|
||||
to make sure the temporary file isn't left lying around.
|
||||
|
||||
For example:
|
||||
|
||||
@code
|
||||
{
|
||||
File myTargetFile ("~/myfile.txt");
|
||||
|
||||
// this will choose a file called something like "~/myfile_temp239348.txt"
|
||||
// which definitely doesn't exist at the time the constructor is called.
|
||||
TemporaryFile temp (myTargetFile);
|
||||
|
||||
// create a stream to the temporary file, and write some data to it...
|
||||
ScopedPointer <FileOutputStream> out (temp.getFile().createOutputStream());
|
||||
|
||||
if (out != nullptr)
|
||||
{
|
||||
out->write ( ...etc )
|
||||
out = nullptr; // (deletes the stream)
|
||||
|
||||
// ..now we've finished writing, this will rename the temp file to
|
||||
// make it replace the target file we specified above.
|
||||
bool succeeded = temp.overwriteTargetFileWithTemporary();
|
||||
}
|
||||
|
||||
// ..and even if something went wrong and our overwrite failed,
|
||||
// as the TemporaryFile object goes out of scope here, it'll make sure
|
||||
// that the temp file gets deleted.
|
||||
}
|
||||
@endcode
|
||||
|
||||
@see File, FileOutputStream
|
||||
*/
|
||||
class BEAST_API TemporaryFile
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
enum OptionFlags
|
||||
{
|
||||
useHiddenFile = 1, /**< Indicates that the temporary file should be hidden -
|
||||
i.e. its name should start with a dot. */
|
||||
putNumbersInBrackets = 2 /**< Indicates that when numbers are appended to make sure
|
||||
the file is unique, they should go in brackets rather
|
||||
than just being appended (see File::getNonexistentSibling() )*/
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Creates a randomly-named temporary file in the default temp directory.
|
||||
|
||||
@param suffix a file suffix to use for the file
|
||||
@param optionFlags a combination of the values listed in the OptionFlags enum
|
||||
The file will not be created until you write to it. And remember that when
|
||||
this object is deleted, the file will also be deleted!
|
||||
*/
|
||||
TemporaryFile (const String& suffix = String::empty,
|
||||
int optionFlags = 0);
|
||||
|
||||
/** Creates a temporary file in the same directory as a specified file.
|
||||
|
||||
This is useful if you have a file that you want to overwrite, but don't
|
||||
want to harm the original file if the write operation fails. You can
|
||||
use this to create a temporary file next to the target file, then
|
||||
write to the temporary file, and finally use overwriteTargetFileWithTemporary()
|
||||
to replace the target file with the one you've just written.
|
||||
|
||||
This class won't create any files until you actually write to them. And remember
|
||||
that when this object is deleted, the temporary file will also be deleted!
|
||||
|
||||
@param targetFile the file that you intend to overwrite - the temporary
|
||||
file will be created in the same directory as this
|
||||
@param optionFlags a combination of the values listed in the OptionFlags enum
|
||||
*/
|
||||
TemporaryFile (const File& targetFile,
|
||||
int optionFlags = 0);
|
||||
|
||||
/** Creates a temporary file using an explicit filename.
|
||||
The other constructors are a better choice than this one, unless for some reason
|
||||
you need to explicitly specify the temporary file you want to use.
|
||||
|
||||
@param targetFile the file that you intend to overwrite
|
||||
@param temporaryFile the temporary file to be used
|
||||
*/
|
||||
TemporaryFile (const File& targetFile,
|
||||
const File& temporaryFile);
|
||||
|
||||
/** Destructor.
|
||||
|
||||
When this object is deleted it will make sure that its temporary file is
|
||||
also deleted! If the operation fails, it'll throw an assertion in debug
|
||||
mode.
|
||||
*/
|
||||
~TemporaryFile();
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the temporary file. */
|
||||
const File& getFile() const noexcept { return temporaryFile; }
|
||||
|
||||
/** Returns the target file that was specified in the constructor. */
|
||||
const File& getTargetFile() const noexcept { return targetFile; }
|
||||
|
||||
/** Tries to move the temporary file to overwrite the target file that was
|
||||
specified in the constructor.
|
||||
|
||||
If you used the constructor that specified a target file, this will attempt
|
||||
to replace that file with the temporary one.
|
||||
|
||||
Before calling this, make sure:
|
||||
- that you've actually written to the temporary file
|
||||
- that you've closed any open streams that you were using to write to it
|
||||
- and that you don't have any streams open to the target file, which would
|
||||
prevent it being overwritten
|
||||
|
||||
If the file move succeeds, this returns false, and the temporary file will
|
||||
have disappeared. If it fails, the temporary file will probably still exist,
|
||||
but will be deleted when this object is destroyed.
|
||||
*/
|
||||
bool overwriteTargetFileWithTemporary() const;
|
||||
|
||||
/** Attempts to delete the temporary file, if it exists.
|
||||
@returns true if the file is successfully deleted (or if it didn't exist).
|
||||
*/
|
||||
bool deleteTemporaryFile() const;
|
||||
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
const File temporaryFile, targetFile;
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TemporaryFile)
|
||||
};
|
||||
|
||||
#endif // BEAST_TEMPORARYFILE_BEASTHEADER
|
||||
645
modules/beast_core/json/beast_JSON.cpp
Normal file
645
modules/beast_core/json/beast_JSON.cpp
Normal file
@@ -0,0 +1,645 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
class JSONParser
|
||||
{
|
||||
public:
|
||||
static Result parseObjectOrArray (String::CharPointerType t, var& result)
|
||||
{
|
||||
t = t.findEndOfWhitespace();
|
||||
|
||||
switch (t.getAndAdvance())
|
||||
{
|
||||
case 0: result = var::null; return Result::ok();
|
||||
case '{': return parseObject (t, result);
|
||||
case '[': return parseArray (t, result);
|
||||
}
|
||||
|
||||
return createFail ("Expected '{' or '['", &t);
|
||||
}
|
||||
|
||||
private:
|
||||
static Result parseAny (String::CharPointerType& t, var& result)
|
||||
{
|
||||
t = t.findEndOfWhitespace();
|
||||
String::CharPointerType t2 (t);
|
||||
|
||||
switch (t2.getAndAdvance())
|
||||
{
|
||||
case '{': t = t2; return parseObject (t, result);
|
||||
case '[': t = t2; return parseArray (t, result);
|
||||
case '"': t = t2; return parseString (t, result);
|
||||
|
||||
case '-':
|
||||
t2 = t2.findEndOfWhitespace();
|
||||
if (! CharacterFunctions::isDigit (*t2))
|
||||
break;
|
||||
|
||||
t = t2;
|
||||
return parseNumber (t, result, true);
|
||||
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
return parseNumber (t, result, false);
|
||||
|
||||
case 't': // "true"
|
||||
if (t2.getAndAdvance() == 'r' && t2.getAndAdvance() == 'u' && t2.getAndAdvance() == 'e')
|
||||
{
|
||||
t = t2;
|
||||
result = var (true);
|
||||
return Result::ok();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'f': // "false"
|
||||
if (t2.getAndAdvance() == 'a' && t2.getAndAdvance() == 'l'
|
||||
&& t2.getAndAdvance() == 's' && t2.getAndAdvance() == 'e')
|
||||
{
|
||||
t = t2;
|
||||
result = var (false);
|
||||
return Result::ok();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'n': // "null"
|
||||
if (t2.getAndAdvance() == 'u' && t2.getAndAdvance() == 'l' && t2.getAndAdvance() == 'l')
|
||||
{
|
||||
t = t2;
|
||||
result = var::null;
|
||||
return Result::ok();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return createFail ("Syntax error", &t);
|
||||
}
|
||||
|
||||
static Result createFail (const char* const message, const String::CharPointerType* location = nullptr)
|
||||
{
|
||||
String m (message);
|
||||
if (location != nullptr)
|
||||
m << ": \"" << String (*location, 20) << '"';
|
||||
|
||||
return Result::fail (m);
|
||||
}
|
||||
|
||||
static Result parseNumber (String::CharPointerType& t, var& result, const bool isNegative)
|
||||
{
|
||||
String::CharPointerType oldT (t);
|
||||
|
||||
int64 intValue = t.getAndAdvance() - '0';
|
||||
bassert (intValue >= 0 && intValue < 10);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
String::CharPointerType previousChar (t);
|
||||
const beast_wchar c = t.getAndAdvance();
|
||||
const int digit = ((int) c) - '0';
|
||||
|
||||
if (isPositiveAndBelow (digit, 10))
|
||||
{
|
||||
intValue = intValue * 10 + digit;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == 'e' || c == 'E' || c == '.')
|
||||
{
|
||||
t = oldT;
|
||||
const double asDouble = CharacterFunctions::readDoubleValue (t);
|
||||
result = isNegative ? -asDouble : asDouble;
|
||||
return Result::ok();
|
||||
}
|
||||
|
||||
if (CharacterFunctions::isWhitespace (c)
|
||||
|| c == ',' || c == '}' || c == ']' || c == 0)
|
||||
{
|
||||
t = previousChar;
|
||||
break;
|
||||
}
|
||||
|
||||
return createFail ("Syntax error in number", &oldT);
|
||||
}
|
||||
|
||||
const int64 correctedValue = isNegative ? -intValue : intValue;
|
||||
|
||||
if ((intValue >> 31) != 0)
|
||||
result = correctedValue;
|
||||
else
|
||||
result = (int) correctedValue;
|
||||
|
||||
return Result::ok();
|
||||
}
|
||||
|
||||
static Result parseObject (String::CharPointerType& t, var& result)
|
||||
{
|
||||
DynamicObject* const resultObject = new DynamicObject();
|
||||
result = resultObject;
|
||||
NamedValueSet& resultProperties = resultObject->getProperties();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
t = t.findEndOfWhitespace();
|
||||
|
||||
String::CharPointerType oldT (t);
|
||||
const beast_wchar c = t.getAndAdvance();
|
||||
|
||||
if (c == '}')
|
||||
break;
|
||||
|
||||
if (c == 0)
|
||||
return createFail ("Unexpected end-of-input in object declaration");
|
||||
|
||||
if (c == '"')
|
||||
{
|
||||
var propertyNameVar;
|
||||
Result r (parseString (t, propertyNameVar));
|
||||
|
||||
if (r.failed())
|
||||
return r;
|
||||
|
||||
const String propertyName (propertyNameVar.toString());
|
||||
|
||||
if (propertyName.isNotEmpty())
|
||||
{
|
||||
t = t.findEndOfWhitespace();
|
||||
oldT = t;
|
||||
|
||||
const beast_wchar c2 = t.getAndAdvance();
|
||||
if (c2 != ':')
|
||||
return createFail ("Expected ':', but found", &oldT);
|
||||
|
||||
resultProperties.set (propertyName, var::null);
|
||||
var* propertyValue = resultProperties.getVarPointer (propertyName);
|
||||
|
||||
Result r2 (parseAny (t, *propertyValue));
|
||||
|
||||
if (r2.failed())
|
||||
return r2;
|
||||
|
||||
t = t.findEndOfWhitespace();
|
||||
oldT = t;
|
||||
|
||||
const beast_wchar nextChar = t.getAndAdvance();
|
||||
|
||||
if (nextChar == ',')
|
||||
continue;
|
||||
|
||||
if (nextChar == '}')
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return createFail ("Expected object member declaration, but found", &oldT);
|
||||
}
|
||||
|
||||
return Result::ok();
|
||||
}
|
||||
|
||||
static Result parseArray (String::CharPointerType& t, var& result)
|
||||
{
|
||||
result = var (Array<var>());
|
||||
Array<var>* const destArray = result.getArray();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
t = t.findEndOfWhitespace();
|
||||
|
||||
String::CharPointerType oldT (t);
|
||||
const beast_wchar c = t.getAndAdvance();
|
||||
|
||||
if (c == ']')
|
||||
break;
|
||||
|
||||
if (c == 0)
|
||||
return createFail ("Unexpected end-of-input in array declaration");
|
||||
|
||||
t = oldT;
|
||||
destArray->add (var::null);
|
||||
Result r (parseAny (t, destArray->getReference (destArray->size() - 1)));
|
||||
|
||||
if (r.failed())
|
||||
return r;
|
||||
|
||||
t = t.findEndOfWhitespace();
|
||||
oldT = t;
|
||||
|
||||
const beast_wchar nextChar = t.getAndAdvance();
|
||||
|
||||
if (nextChar == ',')
|
||||
continue;
|
||||
|
||||
if (nextChar == ']')
|
||||
break;
|
||||
|
||||
return createFail ("Expected object array item, but found", &oldT);
|
||||
}
|
||||
|
||||
return Result::ok();
|
||||
}
|
||||
|
||||
static Result parseString (String::CharPointerType& t, var& result)
|
||||
{
|
||||
MemoryOutputStream buffer (256);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
beast_wchar c = t.getAndAdvance();
|
||||
|
||||
if (c == '"')
|
||||
break;
|
||||
|
||||
if (c == '\\')
|
||||
{
|
||||
c = t.getAndAdvance();
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '"':
|
||||
case '\\':
|
||||
case '/': break;
|
||||
|
||||
case 'b': c = '\b'; break;
|
||||
case 'f': c = '\f'; break;
|
||||
case 'n': c = '\n'; break;
|
||||
case 'r': c = '\r'; break;
|
||||
case 't': c = '\t'; break;
|
||||
|
||||
case 'u':
|
||||
{
|
||||
c = 0;
|
||||
|
||||
for (int i = 4; --i >= 0;)
|
||||
{
|
||||
const int digitValue = CharacterFunctions::getHexDigitValue (t.getAndAdvance());
|
||||
if (digitValue < 0)
|
||||
return createFail ("Syntax error in unicode escape sequence");
|
||||
|
||||
c = (beast_wchar) ((c << 4) + digitValue);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (c == 0)
|
||||
return createFail ("Unexpected end-of-input in string constant");
|
||||
|
||||
buffer.appendUTF8Char (c);
|
||||
}
|
||||
|
||||
result = buffer.toString();
|
||||
return Result::ok();
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class JSONFormatter
|
||||
{
|
||||
public:
|
||||
static void write (OutputStream& out, const var& v,
|
||||
const int indentLevel, const bool allOnOneLine)
|
||||
{
|
||||
if (v.isString())
|
||||
{
|
||||
writeString (out, v.toString().getCharPointer());
|
||||
}
|
||||
else if (v.isVoid())
|
||||
{
|
||||
out << "null";
|
||||
}
|
||||
else if (v.isBool())
|
||||
{
|
||||
out << (static_cast<bool> (v) ? "true" : "false");
|
||||
}
|
||||
else if (v.isArray())
|
||||
{
|
||||
writeArray (out, *v.getArray(), indentLevel, allOnOneLine);
|
||||
}
|
||||
else if (v.isObject())
|
||||
{
|
||||
if (DynamicObject* const object = v.getDynamicObject())
|
||||
writeObject (out, *object, indentLevel, allOnOneLine);
|
||||
else
|
||||
jassertfalse; // Only DynamicObjects can be converted to JSON!
|
||||
}
|
||||
else
|
||||
{
|
||||
// Can't convert these other types of object to JSON!
|
||||
bassert (! (v.isMethod() || v.isBinaryData()));
|
||||
|
||||
out << v.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
enum { indentSize = 2 };
|
||||
|
||||
static void writeEscapedChar (OutputStream& out, const unsigned short value)
|
||||
{
|
||||
out << "\\u" << String::toHexString ((int) value).paddedLeft ('0', 4);
|
||||
}
|
||||
|
||||
static void writeString (OutputStream& out, String::CharPointerType t)
|
||||
{
|
||||
out << '"';
|
||||
|
||||
for (;;)
|
||||
{
|
||||
const beast_wchar c (t.getAndAdvance());
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 0: out << '"'; return;
|
||||
|
||||
case '\"': out << "\\\""; break;
|
||||
case '\\': out << "\\\\"; break;
|
||||
case '\b': out << "\\b"; break;
|
||||
case '\f': out << "\\f"; break;
|
||||
case '\t': out << "\\t"; break;
|
||||
case '\r': out << "\\r"; break;
|
||||
case '\n': out << "\\n"; break;
|
||||
|
||||
default:
|
||||
if (c >= 32 && c < 127)
|
||||
{
|
||||
out << (char) c;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CharPointer_UTF16::getBytesRequiredFor (c) > 2)
|
||||
{
|
||||
CharPointer_UTF16::CharType chars[2];
|
||||
CharPointer_UTF16 utf16 (chars);
|
||||
utf16.write (c);
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
writeEscapedChar (out, (unsigned short) chars[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
writeEscapedChar (out, (unsigned short) c);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void writeSpaces (OutputStream& out, int numSpaces)
|
||||
{
|
||||
out.writeRepeatedByte (' ', (size_t) numSpaces);
|
||||
}
|
||||
|
||||
static void writeArray (OutputStream& out, const Array<var>& array,
|
||||
const int indentLevel, const bool allOnOneLine)
|
||||
{
|
||||
out << '[';
|
||||
if (! allOnOneLine)
|
||||
out << newLine;
|
||||
|
||||
for (int i = 0; i < array.size(); ++i)
|
||||
{
|
||||
if (! allOnOneLine)
|
||||
writeSpaces (out, indentLevel + indentSize);
|
||||
|
||||
write (out, array.getReference(i), indentLevel + indentSize, allOnOneLine);
|
||||
|
||||
if (i < array.size() - 1)
|
||||
{
|
||||
if (allOnOneLine)
|
||||
out << ", ";
|
||||
else
|
||||
out << ',' << newLine;
|
||||
}
|
||||
else if (! allOnOneLine)
|
||||
out << newLine;
|
||||
}
|
||||
|
||||
if (! allOnOneLine)
|
||||
writeSpaces (out, indentLevel);
|
||||
|
||||
out << ']';
|
||||
}
|
||||
|
||||
static void writeObject (OutputStream& out, DynamicObject& object,
|
||||
const int indentLevel, const bool allOnOneLine)
|
||||
{
|
||||
NamedValueSet& props = object.getProperties();
|
||||
|
||||
out << '{';
|
||||
if (! allOnOneLine)
|
||||
out << newLine;
|
||||
|
||||
LinkedListPointer<NamedValueSet::NamedValue>* i = &(props.values);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
NamedValueSet::NamedValue* const v = i->get();
|
||||
|
||||
if (v == nullptr)
|
||||
break;
|
||||
|
||||
if (! allOnOneLine)
|
||||
writeSpaces (out, indentLevel + indentSize);
|
||||
|
||||
writeString (out, v->name);
|
||||
out << ": ";
|
||||
write (out, v->value, indentLevel + indentSize, allOnOneLine);
|
||||
|
||||
if (v->nextListItem.get() != nullptr)
|
||||
{
|
||||
if (allOnOneLine)
|
||||
out << ", ";
|
||||
else
|
||||
out << ',' << newLine;
|
||||
}
|
||||
else if (! allOnOneLine)
|
||||
out << newLine;
|
||||
|
||||
i = &(v->nextListItem);
|
||||
}
|
||||
|
||||
if (! allOnOneLine)
|
||||
writeSpaces (out, indentLevel);
|
||||
|
||||
out << '}';
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
var JSON::parse (const String& text)
|
||||
{
|
||||
var result;
|
||||
|
||||
if (! JSONParser::parseObjectOrArray (text.getCharPointer(), result))
|
||||
result = var::null;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var JSON::parse (InputStream& input)
|
||||
{
|
||||
return parse (input.readEntireStreamAsString());
|
||||
}
|
||||
|
||||
var JSON::parse (const File& file)
|
||||
{
|
||||
return parse (file.loadFileAsString());
|
||||
}
|
||||
|
||||
Result JSON::parse (const String& text, var& result)
|
||||
{
|
||||
return JSONParser::parseObjectOrArray (text.getCharPointer(), result);
|
||||
}
|
||||
|
||||
String JSON::toString (const var& data, const bool allOnOneLine)
|
||||
{
|
||||
MemoryOutputStream mo (1024);
|
||||
JSONFormatter::write (mo, data, 0, allOnOneLine);
|
||||
return mo.toString();
|
||||
}
|
||||
|
||||
void JSON::writeToStream (OutputStream& output, const var& data, const bool allOnOneLine)
|
||||
{
|
||||
JSONFormatter::write (output, data, 0, allOnOneLine);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
//==============================================================================
|
||||
#if BEAST_UNIT_TESTS
|
||||
|
||||
class JSONTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
JSONTests() : UnitTest ("JSON") {}
|
||||
|
||||
static String createRandomWideCharString (Random& r)
|
||||
{
|
||||
beast_wchar buffer[40] = { 0 };
|
||||
|
||||
for (int i = 0; i < numElementsInArray (buffer) - 1; ++i)
|
||||
{
|
||||
if (r.nextBool())
|
||||
{
|
||||
do
|
||||
{
|
||||
buffer[i] = (beast_wchar) (1 + r.nextInt (0x10ffff - 1));
|
||||
}
|
||||
while (! CharPointer_UTF16::canRepresent (buffer[i]));
|
||||
}
|
||||
else
|
||||
buffer[i] = (beast_wchar) (1 + r.nextInt (0xff));
|
||||
}
|
||||
|
||||
return CharPointer_UTF32 (buffer);
|
||||
}
|
||||
|
||||
static String createRandomIdentifier (Random& r)
|
||||
{
|
||||
char buffer[30] = { 0 };
|
||||
|
||||
for (int i = 0; i < numElementsInArray (buffer) - 1; ++i)
|
||||
{
|
||||
static const char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-:";
|
||||
buffer[i] = chars [r.nextInt (sizeof (chars) - 1)];
|
||||
}
|
||||
|
||||
return CharPointer_ASCII (buffer);
|
||||
}
|
||||
|
||||
static var createRandomVar (Random& r, int depth)
|
||||
{
|
||||
switch (r.nextInt (depth > 3 ? 6 : 8))
|
||||
{
|
||||
case 0: return var::null;
|
||||
case 1: return r.nextInt();
|
||||
case 2: return r.nextInt64();
|
||||
case 3: return r.nextBool();
|
||||
case 4: return r.nextDouble();
|
||||
case 5: return createRandomWideCharString (r);
|
||||
|
||||
case 6:
|
||||
{
|
||||
var v (createRandomVar (r, depth + 1));
|
||||
|
||||
for (int i = 1 + r.nextInt (30); --i >= 0;)
|
||||
v.append (createRandomVar (r, depth + 1));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
case 7:
|
||||
{
|
||||
DynamicObject* o = new DynamicObject();
|
||||
|
||||
for (int i = r.nextInt (30); --i >= 0;)
|
||||
o->setProperty (createRandomIdentifier (r), createRandomVar (r, depth + 1));
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
default:
|
||||
return var::null;
|
||||
}
|
||||
}
|
||||
|
||||
void runTest()
|
||||
{
|
||||
beginTest ("JSON");
|
||||
Random r;
|
||||
r.setSeedRandomly();
|
||||
|
||||
expect (JSON::parse (String::empty) == var::null);
|
||||
expect (JSON::parse ("{}").isObject());
|
||||
expect (JSON::parse ("[]").isArray());
|
||||
expect (JSON::parse ("[ 1234 ]")[0].isInt());
|
||||
expect (JSON::parse ("[ 12345678901234 ]")[0].isInt64());
|
||||
expect (JSON::parse ("[ 1.123e3 ]")[0].isDouble());
|
||||
expect (JSON::parse ("[ -1234]")[0].isInt());
|
||||
expect (JSON::parse ("[-12345678901234]")[0].isInt64());
|
||||
expect (JSON::parse ("[-1.123e3]")[0].isDouble());
|
||||
|
||||
for (int i = 100; --i >= 0;)
|
||||
{
|
||||
var v;
|
||||
|
||||
if (i > 0)
|
||||
v = createRandomVar (r, 0);
|
||||
|
||||
const bool oneLine = r.nextBool();
|
||||
String asString (JSON::toString (v, oneLine));
|
||||
var parsed = JSON::parse ("[" + asString + "]")[0];
|
||||
String parsedString (JSON::toString (parsed, oneLine));
|
||||
expect (asString.isNotEmpty() && parsedString == asString);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static JSONTests JSONUnitTests;
|
||||
|
||||
#endif
|
||||
113
modules/beast_core/json/beast_JSON.h
Normal file
113
modules/beast_core/json/beast_JSON.h
Normal file
@@ -0,0 +1,113 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_JSON_BEASTHEADER
|
||||
#define BEAST_JSON_BEASTHEADER
|
||||
|
||||
#include "../misc/beast_Result.h"
|
||||
#include "../containers/beast_Variant.h"
|
||||
class InputStream;
|
||||
class OutputStream;
|
||||
class File;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Contains static methods for converting JSON-formatted text to and from var objects.
|
||||
|
||||
The var class is structurally compatible with JSON-formatted data, so these
|
||||
functions allow you to parse JSON into a var object, and to convert a var
|
||||
object to JSON-formatted text.
|
||||
|
||||
@see var
|
||||
*/
|
||||
class BEAST_API JSON
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Parses a string of JSON-formatted text, and returns a result code containing
|
||||
any parse errors.
|
||||
|
||||
This will return the parsed structure in the parsedResult parameter, and will
|
||||
return a Result object to indicate whether parsing was successful, and if not,
|
||||
it will contain an error message.
|
||||
|
||||
If you're not interested in the error message, you can use one of the other
|
||||
shortcut parse methods, which simply return a var::null if the parsing fails.
|
||||
*/
|
||||
static Result parse (const String& text, var& parsedResult);
|
||||
|
||||
/** Attempts to parse some JSON-formatted text, and returns the result as a var object.
|
||||
|
||||
If the parsing fails, this simply returns var::null - if you need to find out more
|
||||
detail about the parse error, use the alternative parse() method which returns a Result.
|
||||
*/
|
||||
static var parse (const String& text);
|
||||
|
||||
/** Attempts to parse some JSON-formatted text from a file, and returns the result
|
||||
as a var object.
|
||||
|
||||
Note that this is just a short-cut for reading the entire file into a string and
|
||||
parsing the result.
|
||||
|
||||
If the parsing fails, this simply returns var::null - if you need to find out more
|
||||
detail about the parse error, use the alternative parse() method which returns a Result.
|
||||
*/
|
||||
static var parse (const File& file);
|
||||
|
||||
/** Attempts to parse some JSON-formatted text from a stream, and returns the result
|
||||
as a var object.
|
||||
|
||||
Note that this is just a short-cut for reading the entire stream into a string and
|
||||
parsing the result.
|
||||
|
||||
If the parsing fails, this simply returns var::null - if you need to find out more
|
||||
detail about the parse error, use the alternative parse() method which returns a Result.
|
||||
*/
|
||||
static var parse (InputStream& input);
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a string which contains a JSON-formatted representation of the var object.
|
||||
If allOnOneLine is true, the result will be compacted into a single line of text
|
||||
with no carriage-returns. If false, it will be laid-out in a more human-readable format.
|
||||
@see writeToStream
|
||||
*/
|
||||
static String toString (const var& objectToFormat,
|
||||
bool allOnOneLine = false);
|
||||
|
||||
/** Writes a JSON-formatted representation of the var object to the given stream.
|
||||
If allOnOneLine is true, the result will be compacted into a single line of text
|
||||
with no carriage-returns. If false, it will be laid-out in a more human-readable format.
|
||||
@see toString
|
||||
*/
|
||||
static void writeToStream (OutputStream& output,
|
||||
const var& objectToFormat,
|
||||
bool allOnOneLine = false);
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
JSON(); // This class can't be instantiated - just use its static methods.
|
||||
};
|
||||
|
||||
|
||||
#endif // BEAST_JSON_BEASTHEADER
|
||||
129
modules/beast_core/logging/beast_FileLogger.cpp
Normal file
129
modules/beast_core/logging/beast_FileLogger.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
FileLogger::FileLogger (const File& file,
|
||||
const String& welcomeMessage,
|
||||
const int64 maxInitialFileSizeBytes)
|
||||
: logFile (file)
|
||||
{
|
||||
if (maxInitialFileSizeBytes >= 0)
|
||||
trimFileSize (maxInitialFileSizeBytes);
|
||||
|
||||
if (! file.exists())
|
||||
file.create(); // (to create the parent directories)
|
||||
|
||||
String welcome;
|
||||
welcome << newLine
|
||||
<< "**********************************************************" << newLine
|
||||
<< welcomeMessage << newLine
|
||||
<< "Log started: " << Time::getCurrentTime().toString (true, true) << newLine;
|
||||
|
||||
FileLogger::logMessage (welcome);
|
||||
}
|
||||
|
||||
FileLogger::~FileLogger() {}
|
||||
|
||||
//==============================================================================
|
||||
void FileLogger::logMessage (const String& message)
|
||||
{
|
||||
const ScopedLock sl (logLock);
|
||||
DBG (message);
|
||||
FileOutputStream out (logFile, 256);
|
||||
out << message << newLine;
|
||||
}
|
||||
|
||||
void FileLogger::trimFileSize (int64 maxFileSizeBytes) const
|
||||
{
|
||||
if (maxFileSizeBytes <= 0)
|
||||
{
|
||||
logFile.deleteFile();
|
||||
}
|
||||
else
|
||||
{
|
||||
const int64 fileSize = logFile.getSize();
|
||||
|
||||
if (fileSize > maxFileSizeBytes)
|
||||
{
|
||||
TemporaryFile tempFile (logFile);
|
||||
|
||||
{
|
||||
FileOutputStream out (tempFile.getFile());
|
||||
FileInputStream in (logFile);
|
||||
|
||||
if (! (out.openedOk() && in.openedOk()))
|
||||
return;
|
||||
|
||||
in.setPosition (fileSize - maxFileSizeBytes);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
const char c = in.readByte();
|
||||
if (c == 0)
|
||||
return;
|
||||
|
||||
if (c == '\n' || c == '\r')
|
||||
{
|
||||
out << c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out.writeFromInputStream (in, -1);
|
||||
}
|
||||
|
||||
tempFile.overwriteTargetFileWithTemporary();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
File FileLogger::getSystemLogFileFolder()
|
||||
{
|
||||
#if BEAST_MAC
|
||||
return File ("~/Library/Logs");
|
||||
#else
|
||||
return File::getSpecialLocation (File::userApplicationDataDirectory);
|
||||
#endif
|
||||
}
|
||||
|
||||
FileLogger* FileLogger::createDefaultAppLogger (const String& logFileSubDirectoryName,
|
||||
const String& logFileName,
|
||||
const String& welcomeMessage,
|
||||
const int64 maxInitialFileSizeBytes)
|
||||
{
|
||||
return new FileLogger (getSystemLogFileFolder().getChildFile (logFileSubDirectoryName)
|
||||
.getChildFile (logFileName),
|
||||
welcomeMessage, maxInitialFileSizeBytes);
|
||||
}
|
||||
|
||||
FileLogger* FileLogger::createDateStampedLogger (const String& logFileSubDirectoryName,
|
||||
const String& logFileNameRoot,
|
||||
const String& logFileNameSuffix,
|
||||
const String& welcomeMessage)
|
||||
{
|
||||
return new FileLogger (getSystemLogFileFolder().getChildFile (logFileSubDirectoryName)
|
||||
.getChildFile (logFileNameRoot + Time::getCurrentTime().formatted ("%Y-%m-%d_%H-%M-%S"))
|
||||
.withFileExtension (logFileNameSuffix)
|
||||
.getNonexistentSibling(),
|
||||
welcomeMessage, 0);
|
||||
}
|
||||
134
modules/beast_core/logging/beast_FileLogger.h
Normal file
134
modules/beast_core/logging/beast_FileLogger.h
Normal file
@@ -0,0 +1,134 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_FILELOGGER_BEASTHEADER
|
||||
#define BEAST_FILELOGGER_BEASTHEADER
|
||||
|
||||
#include "beast_Logger.h"
|
||||
#include "../files/beast_File.h"
|
||||
#include "../memory/beast_ScopedPointer.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A simple implementation of a Logger that writes to a file.
|
||||
|
||||
@see Logger
|
||||
*/
|
||||
class BEAST_API FileLogger : public Logger
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a FileLogger for a given file.
|
||||
|
||||
@param fileToWriteTo the file that to use - new messages will be appended
|
||||
to the file. If the file doesn't exist, it will be created,
|
||||
along with any parent directories that are needed.
|
||||
@param welcomeMessage when opened, the logger will write a header to the log, along
|
||||
with the current date and time, and this welcome message
|
||||
@param maxInitialFileSizeBytes if this is zero or greater, then if the file already exists
|
||||
but is larger than this number of bytes, then the start of the
|
||||
file will be truncated to keep the size down. This prevents a log
|
||||
file getting ridiculously large over time. The file will be truncated
|
||||
at a new-line boundary. If this value is less than zero, no size limit
|
||||
will be imposed; if it's zero, the file will always be deleted. Note that
|
||||
the size is only checked once when this object is created - any logging
|
||||
that is done later will be appended without any checking
|
||||
*/
|
||||
FileLogger (const File& fileToWriteTo,
|
||||
const String& welcomeMessage,
|
||||
const int64 maxInitialFileSizeBytes = 128 * 1024);
|
||||
|
||||
/** Destructor. */
|
||||
~FileLogger();
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the file that this logger is writing to. */
|
||||
const File& getLogFile() const noexcept { return logFile; }
|
||||
|
||||
//==============================================================================
|
||||
/** Helper function to create a log file in the correct place for this platform.
|
||||
|
||||
The method might return nullptr if the file can't be created for some reason.
|
||||
|
||||
@param logFileSubDirectoryName the name of the subdirectory to create inside the logs folder (as
|
||||
returned by getSystemLogFileFolder). It's best to use something
|
||||
like the name of your application here.
|
||||
@param logFileName the name of the file to create, e.g. "MyAppLog.txt".
|
||||
@param welcomeMessage a message that will be written to the log when it's opened.
|
||||
@param maxInitialFileSizeBytes (see the FileLogger constructor for more info on this)
|
||||
*/
|
||||
static FileLogger* createDefaultAppLogger (const String& logFileSubDirectoryName,
|
||||
const String& logFileName,
|
||||
const String& welcomeMessage,
|
||||
const int64 maxInitialFileSizeBytes = 128 * 1024);
|
||||
|
||||
/** Helper function to create a log file in the correct place for this platform.
|
||||
|
||||
The filename used is based on the root and suffix strings provided, along with a
|
||||
time and date string, meaning that a new, empty log file will be always be created
|
||||
rather than appending to an exising one.
|
||||
|
||||
The method might return nullptr if the file can't be created for some reason.
|
||||
|
||||
@param logFileSubDirectoryName the name of the subdirectory to create inside the logs folder (as
|
||||
returned by getSystemLogFileFolder). It's best to use something
|
||||
like the name of your application here.
|
||||
@param logFileNameRoot the start of the filename to use, e.g. "MyAppLog_". This will have
|
||||
a timestamp and the logFileNameSuffix appended to it
|
||||
@param logFileNameSuffix the file suffix to use, e.g. ".txt"
|
||||
@param welcomeMessage a message that will be written to the log when it's opened.
|
||||
*/
|
||||
static FileLogger* createDateStampedLogger (const String& logFileSubDirectoryName,
|
||||
const String& logFileNameRoot,
|
||||
const String& logFileNameSuffix,
|
||||
const String& welcomeMessage);
|
||||
|
||||
//==============================================================================
|
||||
/** Returns an OS-specific folder where log-files should be stored.
|
||||
|
||||
On Windows this will return a logger with a path such as:
|
||||
c:\\Documents and Settings\\username\\Application Data\\[logFileSubDirectoryName]\\[logFileName]
|
||||
|
||||
On the Mac it'll create something like:
|
||||
~/Library/Logs/[logFileSubDirectoryName]/[logFileName]
|
||||
|
||||
@see createDefaultAppLogger
|
||||
*/
|
||||
static File getSystemLogFileFolder();
|
||||
|
||||
// (implementation of the Logger virtual method)
|
||||
void logMessage (const String&);
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
File logFile;
|
||||
CriticalSection logLock;
|
||||
|
||||
void trimFileSize (int64 maxFileSizeBytes) const;
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileLogger)
|
||||
};
|
||||
|
||||
|
||||
#endif // BEAST_FILELOGGER_BEASTHEADER
|
||||
58
modules/beast_core/logging/beast_Logger.cpp
Normal file
58
modules/beast_core/logging/beast_Logger.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
Logger::Logger() {}
|
||||
|
||||
Logger::~Logger()
|
||||
{
|
||||
// You're deleting this logger while it's still being used!
|
||||
// Always call Logger::setCurrentLogger (nullptr) before deleting the active logger.
|
||||
bassert (currentLogger != this);
|
||||
}
|
||||
|
||||
Logger* Logger::currentLogger = nullptr;
|
||||
|
||||
void Logger::setCurrentLogger (Logger* const newLogger) noexcept { currentLogger = newLogger; }
|
||||
Logger* Logger::getCurrentLogger() noexcept { return currentLogger; }
|
||||
|
||||
void Logger::writeToLog (const String& message)
|
||||
{
|
||||
if (currentLogger != nullptr)
|
||||
currentLogger->logMessage (message);
|
||||
else
|
||||
outputDebugString (message);
|
||||
}
|
||||
|
||||
#if BEAST_LOG_ASSERTIONS || BEAST_DEBUG
|
||||
void BEAST_API BEAST_CALLTYPE logAssertion (const char* const filename, const int lineNum) noexcept
|
||||
{
|
||||
String m ("BEAST Assertion failure in ");
|
||||
m << File::createFileWithoutCheckingPath (filename).getFileName() << ':' << lineNum;
|
||||
|
||||
#if BEAST_LOG_ASSERTIONS
|
||||
Logger::writeToLog (m);
|
||||
#else
|
||||
DBG (m);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
94
modules/beast_core/logging/beast_Logger.h
Normal file
94
modules/beast_core/logging/beast_Logger.h
Normal file
@@ -0,0 +1,94 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_LOGGER_BEASTHEADER
|
||||
#define BEAST_LOGGER_BEASTHEADER
|
||||
|
||||
#include "../text/beast_String.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Acts as an application-wide logging class.
|
||||
|
||||
A subclass of Logger can be created and passed into the Logger::setCurrentLogger
|
||||
method and this will then be used by all calls to writeToLog.
|
||||
|
||||
The logger class also contains methods for writing messages to the debugger's
|
||||
output stream.
|
||||
|
||||
@see FileLogger
|
||||
*/
|
||||
class BEAST_API Logger
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Destructor. */
|
||||
virtual ~Logger();
|
||||
|
||||
//==============================================================================
|
||||
/** Sets the current logging class to use.
|
||||
|
||||
Note that the object passed in will not be owned or deleted by the logger, so
|
||||
the caller must make sure that it is not deleted while still being used.
|
||||
A null pointer can be passed-in to disable any logging.
|
||||
*/
|
||||
static void BEAST_CALLTYPE setCurrentLogger (Logger* newLogger) noexcept;
|
||||
|
||||
/** Returns the current logger, or nullptr if none has been set. */
|
||||
static Logger* getCurrentLogger() noexcept;
|
||||
|
||||
/** Writes a string to the current logger.
|
||||
|
||||
This will pass the string to the logger's logMessage() method if a logger
|
||||
has been set.
|
||||
|
||||
@see logMessage
|
||||
*/
|
||||
static void BEAST_CALLTYPE writeToLog (const String& message);
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** Writes a message to the standard error stream.
|
||||
|
||||
This can be called directly, or by using the DBG() macro in
|
||||
beast_PlatformDefs.h (which will avoid calling the method in non-debug builds).
|
||||
*/
|
||||
static void BEAST_CALLTYPE outputDebugString (const String& text);
|
||||
|
||||
|
||||
protected:
|
||||
//==============================================================================
|
||||
Logger();
|
||||
|
||||
/** This is overloaded by subclasses to implement custom logging behaviour.
|
||||
@see setCurrentLogger
|
||||
*/
|
||||
virtual void logMessage (const String& message) = 0;
|
||||
|
||||
private:
|
||||
static Logger* currentLogger;
|
||||
};
|
||||
|
||||
|
||||
#endif // BEAST_LOGGER_BEASTHEADER
|
||||
1016
modules/beast_core/maths/beast_BigInteger.cpp
Normal file
1016
modules/beast_core/maths/beast_BigInteger.cpp
Normal file
File diff suppressed because it is too large
Load Diff
329
modules/beast_core/maths/beast_BigInteger.h
Normal file
329
modules/beast_core/maths/beast_BigInteger.h
Normal file
@@ -0,0 +1,329 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_BIGINTEGER_BEASTHEADER
|
||||
#define BEAST_BIGINTEGER_BEASTHEADER
|
||||
|
||||
#include "../text/beast_String.h"
|
||||
#include "../memory/beast_HeapBlock.h"
|
||||
class MemoryBlock;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
An arbitrarily large integer class.
|
||||
|
||||
A BigInteger can be used in a similar way to a normal integer, but has no size
|
||||
limit (except for memory and performance constraints).
|
||||
|
||||
Negative values are possible, but the value isn't stored as 2s-complement, so
|
||||
be careful if you use negative values and look at the values of individual bits.
|
||||
*/
|
||||
class BEAST_API BigInteger
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an empty BigInteger */
|
||||
BigInteger();
|
||||
|
||||
/** Creates a BigInteger containing an integer value in its low bits.
|
||||
The low 32 bits of the number are initialised with this value.
|
||||
*/
|
||||
BigInteger (uint32 value);
|
||||
|
||||
/** Creates a BigInteger containing an integer value in its low bits.
|
||||
The low 32 bits of the number are initialised with the absolute value
|
||||
passed in, and its sign is set to reflect the sign of the number.
|
||||
*/
|
||||
BigInteger (int32 value);
|
||||
|
||||
/** Creates a BigInteger containing an integer value in its low bits.
|
||||
The low 64 bits of the number are initialised with the absolute value
|
||||
passed in, and its sign is set to reflect the sign of the number.
|
||||
*/
|
||||
BigInteger (int64 value);
|
||||
|
||||
/** Creates a copy of another BigInteger. */
|
||||
BigInteger (const BigInteger& other);
|
||||
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
BigInteger (BigInteger&& other) noexcept;
|
||||
BigInteger& operator= (BigInteger&& other) noexcept;
|
||||
#endif
|
||||
|
||||
/** Destructor. */
|
||||
~BigInteger();
|
||||
|
||||
//==============================================================================
|
||||
/** Copies another BigInteger onto this one. */
|
||||
BigInteger& operator= (const BigInteger& other);
|
||||
|
||||
/** Swaps the internal contents of this with another object. */
|
||||
void swapWith (BigInteger& other) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the value of a specified bit in the number.
|
||||
If the index is out-of-range, the result will be false.
|
||||
*/
|
||||
bool operator[] (int bit) const noexcept;
|
||||
|
||||
/** Returns true if no bits are set. */
|
||||
bool isZero() const noexcept;
|
||||
|
||||
/** Returns true if the value is 1. */
|
||||
bool isOne() const noexcept;
|
||||
|
||||
/** Attempts to get the lowest bits of the value as an integer.
|
||||
If the value is bigger than the integer limits, this will return only the lower bits.
|
||||
*/
|
||||
int toInteger() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Resets the value to 0. */
|
||||
void clear();
|
||||
|
||||
/** Clears a particular bit in the number. */
|
||||
void clearBit (int bitNumber) noexcept;
|
||||
|
||||
/** Sets a specified bit to 1. */
|
||||
void setBit (int bitNumber);
|
||||
|
||||
/** Sets or clears a specified bit. */
|
||||
void setBit (int bitNumber, bool shouldBeSet);
|
||||
|
||||
/** Sets a range of bits to be either on or off.
|
||||
|
||||
@param startBit the first bit to change
|
||||
@param numBits the number of bits to change
|
||||
@param shouldBeSet whether to turn these bits on or off
|
||||
*/
|
||||
void setRange (int startBit, int numBits, bool shouldBeSet);
|
||||
|
||||
/** Inserts a bit an a given position, shifting up any bits above it. */
|
||||
void insertBit (int bitNumber, bool shouldBeSet);
|
||||
|
||||
/** Returns a range of bits as a new BigInteger.
|
||||
|
||||
e.g. getBitRangeAsInt (0, 64) would return the lowest 64 bits.
|
||||
@see getBitRangeAsInt
|
||||
*/
|
||||
BigInteger getBitRange (int startBit, int numBits) const;
|
||||
|
||||
/** Returns a range of bits as an integer value.
|
||||
|
||||
e.g. getBitRangeAsInt (0, 32) would return the lowest 32 bits.
|
||||
|
||||
Asking for more than 32 bits isn't allowed (obviously) - for that, use
|
||||
getBitRange().
|
||||
*/
|
||||
uint32 getBitRangeAsInt (int startBit, int numBits) const noexcept;
|
||||
|
||||
/** Sets a range of bits to an integer value.
|
||||
|
||||
Copies the given integer onto a range of bits, starting at startBit,
|
||||
and using up to numBits of the available bits.
|
||||
*/
|
||||
void setBitRangeAsInt (int startBit, int numBits, uint32 valueToSet);
|
||||
|
||||
/** Shifts a section of bits left or right.
|
||||
|
||||
@param howManyBitsLeft how far to move the bits (+ve numbers shift it left, -ve numbers shift it right).
|
||||
@param startBit the first bit to affect - if this is > 0, only bits above that index will be affected.
|
||||
*/
|
||||
void shiftBits (int howManyBitsLeft, int startBit);
|
||||
|
||||
/** Returns the total number of set bits in the value. */
|
||||
int countNumberOfSetBits() const noexcept;
|
||||
|
||||
/** Looks for the index of the next set bit after a given starting point.
|
||||
|
||||
This searches from startIndex (inclusive) upwards for the first set bit,
|
||||
and returns its index. If no set bits are found, it returns -1.
|
||||
*/
|
||||
int findNextSetBit (int startIndex) const noexcept;
|
||||
|
||||
/** Looks for the index of the next clear bit after a given starting point.
|
||||
|
||||
This searches from startIndex (inclusive) upwards for the first clear bit,
|
||||
and returns its index.
|
||||
*/
|
||||
int findNextClearBit (int startIndex) const noexcept;
|
||||
|
||||
/** Returns the index of the highest set bit in the number.
|
||||
If the value is zero, this will return -1.
|
||||
*/
|
||||
int getHighestBit() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
// All the standard arithmetic ops...
|
||||
|
||||
BigInteger& operator+= (const BigInteger& other);
|
||||
BigInteger& operator-= (const BigInteger& other);
|
||||
BigInteger& operator*= (const BigInteger& other);
|
||||
BigInteger& operator/= (const BigInteger& other);
|
||||
BigInteger& operator|= (const BigInteger& other);
|
||||
BigInteger& operator&= (const BigInteger& other);
|
||||
BigInteger& operator^= (const BigInteger& other);
|
||||
BigInteger& operator%= (const BigInteger& other);
|
||||
BigInteger& operator<<= (int numBitsToShift);
|
||||
BigInteger& operator>>= (int numBitsToShift);
|
||||
BigInteger& operator++();
|
||||
BigInteger& operator--();
|
||||
BigInteger operator++ (int);
|
||||
BigInteger operator-- (int);
|
||||
|
||||
BigInteger operator-() const;
|
||||
BigInteger operator+ (const BigInteger& other) const;
|
||||
BigInteger operator- (const BigInteger& other) const;
|
||||
BigInteger operator* (const BigInteger& other) const;
|
||||
BigInteger operator/ (const BigInteger& other) const;
|
||||
BigInteger operator| (const BigInteger& other) const;
|
||||
BigInteger operator& (const BigInteger& other) const;
|
||||
BigInteger operator^ (const BigInteger& other) const;
|
||||
BigInteger operator% (const BigInteger& other) const;
|
||||
BigInteger operator<< (int numBitsToShift) const;
|
||||
BigInteger operator>> (int numBitsToShift) const;
|
||||
|
||||
bool operator== (const BigInteger& other) const noexcept;
|
||||
bool operator!= (const BigInteger& other) const noexcept;
|
||||
bool operator< (const BigInteger& other) const noexcept;
|
||||
bool operator<= (const BigInteger& other) const noexcept;
|
||||
bool operator> (const BigInteger& other) const noexcept;
|
||||
bool operator>= (const BigInteger& other) const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Does a signed comparison of two BigIntegers.
|
||||
|
||||
Return values are:
|
||||
- 0 if the numbers are the same
|
||||
- < 0 if this number is smaller than the other
|
||||
- > 0 if this number is bigger than the other
|
||||
*/
|
||||
int compare (const BigInteger& other) const noexcept;
|
||||
|
||||
/** Compares the magnitudes of two BigIntegers, ignoring their signs.
|
||||
|
||||
Return values are:
|
||||
- 0 if the numbers are the same
|
||||
- < 0 if this number is smaller than the other
|
||||
- > 0 if this number is bigger than the other
|
||||
*/
|
||||
int compareAbsolute (const BigInteger& other) const noexcept;
|
||||
|
||||
/** Divides this value by another one and returns the remainder.
|
||||
|
||||
This number is divided by other, leaving the quotient in this number,
|
||||
with the remainder being copied to the other BigInteger passed in.
|
||||
*/
|
||||
void divideBy (const BigInteger& divisor, BigInteger& remainder);
|
||||
|
||||
/** Returns the largest value that will divide both this value and the one passed-in.
|
||||
*/
|
||||
BigInteger findGreatestCommonDivisor (BigInteger other) const;
|
||||
|
||||
/** Performs a combined exponent and modulo operation.
|
||||
This BigInteger's value becomes (this ^ exponent) % modulus.
|
||||
*/
|
||||
void exponentModulo (const BigInteger& exponent, const BigInteger& modulus);
|
||||
|
||||
/** Performs an inverse modulo on the value.
|
||||
i.e. the result is (this ^ -1) mod (modulus).
|
||||
*/
|
||||
void inverseModulo (const BigInteger& modulus);
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if the value is less than zero.
|
||||
@see setNegative, negate
|
||||
*/
|
||||
bool isNegative() const noexcept;
|
||||
|
||||
/** Changes the sign of the number to be positive or negative.
|
||||
@see isNegative, negate
|
||||
*/
|
||||
void setNegative (bool shouldBeNegative) noexcept;
|
||||
|
||||
/** Inverts the sign of the number.
|
||||
@see isNegative, setNegative
|
||||
*/
|
||||
void negate() noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Converts the number to a string.
|
||||
|
||||
Specify a base such as 2 (binary), 8 (octal), 10 (decimal), 16 (hex).
|
||||
If minimumNumCharacters is greater than 0, the returned string will be
|
||||
padded with leading zeros to reach at least that length.
|
||||
*/
|
||||
String toString (int base, int minimumNumCharacters = 1) const;
|
||||
|
||||
/** Reads the numeric value from a string.
|
||||
|
||||
Specify a base such as 2 (binary), 8 (octal), 10 (decimal), 16 (hex).
|
||||
Any invalid characters will be ignored.
|
||||
*/
|
||||
void parseString (const String& text, int base);
|
||||
|
||||
//==============================================================================
|
||||
/** Turns the number into a block of binary data.
|
||||
|
||||
The data is arranged as little-endian, so the first byte of data is the low 8 bits
|
||||
of the number, and so on.
|
||||
|
||||
@see loadFromMemoryBlock
|
||||
*/
|
||||
MemoryBlock toMemoryBlock() const;
|
||||
|
||||
/** Converts a block of raw data into a number.
|
||||
|
||||
The data is arranged as little-endian, so the first byte of data is the low 8 bits
|
||||
of the number, and so on.
|
||||
|
||||
@see toMemoryBlock
|
||||
*/
|
||||
void loadFromMemoryBlock (const MemoryBlock& data);
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
HeapBlock <uint32> values;
|
||||
size_t numValues;
|
||||
int highestBit;
|
||||
bool negative;
|
||||
|
||||
void ensureSize (size_t numVals);
|
||||
void shiftLeft (int bits, int startBit);
|
||||
void shiftRight (int bits, int startBit);
|
||||
|
||||
BEAST_LEAK_DETECTOR (BigInteger)
|
||||
};
|
||||
|
||||
/** Writes a BigInteger to an OutputStream as a UTF8 decimal string. */
|
||||
OutputStream& BEAST_CALLTYPE operator<< (OutputStream& stream, const BigInteger& value);
|
||||
|
||||
//==============================================================================
|
||||
#ifndef DOXYGEN
|
||||
// For backwards compatibility, BitArray is defined as an alias for BigInteger.
|
||||
typedef BigInteger BitArray;
|
||||
#endif
|
||||
|
||||
|
||||
#endif // BEAST_BIGINTEGER_BEASTHEADER
|
||||
1180
modules/beast_core/maths/beast_Expression.cpp
Normal file
1180
modules/beast_core/maths/beast_Expression.cpp
Normal file
File diff suppressed because it is too large
Load Diff
269
modules/beast_core/maths/beast_Expression.h
Normal file
269
modules/beast_core/maths/beast_Expression.h
Normal file
@@ -0,0 +1,269 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_EXPRESSION_BEASTHEADER
|
||||
#define BEAST_EXPRESSION_BEASTHEADER
|
||||
|
||||
#include "../memory/beast_ReferenceCountedObject.h"
|
||||
#include "../containers/beast_Array.h"
|
||||
#include "../memory/beast_ScopedPointer.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A class for dynamically evaluating simple numeric expressions.
|
||||
|
||||
This class can parse a simple C-style string expression involving floating point
|
||||
numbers, named symbols and functions. The basic arithmetic operations of +, -, *, /
|
||||
are supported, as well as parentheses, and any alphanumeric identifiers are
|
||||
assumed to be named symbols which will be resolved when the expression is
|
||||
evaluated.
|
||||
|
||||
Expressions which use identifiers and functions require a subclass of
|
||||
Expression::Scope to be supplied when evaluating them, and this object
|
||||
is expected to be able to resolve the symbol names and perform the functions that
|
||||
are used.
|
||||
*/
|
||||
class BEAST_API Expression
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a simple expression with a value of 0. */
|
||||
Expression();
|
||||
|
||||
/** Destructor. */
|
||||
~Expression();
|
||||
|
||||
/** Creates a simple expression with a specified constant value. */
|
||||
explicit Expression (double constant);
|
||||
|
||||
/** Creates a copy of an expression. */
|
||||
Expression (const Expression& other);
|
||||
|
||||
/** Copies another expression. */
|
||||
Expression& operator= (const Expression& other);
|
||||
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
Expression (Expression&& other) noexcept;
|
||||
Expression& operator= (Expression&& other) noexcept;
|
||||
#endif
|
||||
|
||||
/** Creates an expression by parsing a string.
|
||||
If there's a syntax error in the string, this will throw a ParseError exception.
|
||||
@throws ParseError
|
||||
*/
|
||||
explicit Expression (const String& stringToParse);
|
||||
|
||||
/** Returns a string version of the expression. */
|
||||
String toString() const;
|
||||
|
||||
/** Returns an expression which is an addtion operation of two existing expressions. */
|
||||
Expression operator+ (const Expression& other) const;
|
||||
/** Returns an expression which is a subtraction operation of two existing expressions. */
|
||||
Expression operator- (const Expression& other) const;
|
||||
/** Returns an expression which is a multiplication operation of two existing expressions. */
|
||||
Expression operator* (const Expression& other) const;
|
||||
/** Returns an expression which is a division operation of two existing expressions. */
|
||||
Expression operator/ (const Expression& other) const;
|
||||
/** Returns an expression which performs a negation operation on an existing expression. */
|
||||
Expression operator-() const;
|
||||
|
||||
/** Returns an Expression which is an identifier reference. */
|
||||
static Expression symbol (const String& symbol);
|
||||
|
||||
/** Returns an Expression which is a function call. */
|
||||
static Expression function (const String& functionName, const Array<Expression>& parameters);
|
||||
|
||||
/** Returns an Expression which parses a string from a character pointer, and updates the pointer
|
||||
to indicate where it finished.
|
||||
|
||||
The pointer is incremented so that on return, it indicates the character that follows
|
||||
the end of the expression that was parsed.
|
||||
|
||||
If there's a syntax error in the string, this will throw a ParseError exception.
|
||||
@throws ParseError
|
||||
*/
|
||||
static Expression parse (String::CharPointerType& stringToParse);
|
||||
|
||||
//==============================================================================
|
||||
/** When evaluating an Expression object, this class is used to resolve symbols and
|
||||
perform functions that the expression uses.
|
||||
*/
|
||||
class BEAST_API Scope
|
||||
{
|
||||
public:
|
||||
Scope();
|
||||
virtual ~Scope();
|
||||
|
||||
/** Returns some kind of globally unique ID that identifies this scope. */
|
||||
virtual String getScopeUID() const;
|
||||
|
||||
/** Returns the value of a symbol.
|
||||
If the symbol is unknown, this can throw an Expression::EvaluationError exception.
|
||||
The member value is set to the part of the symbol that followed the dot, if there is
|
||||
one, e.g. for "foo.bar", symbol = "foo" and member = "bar".
|
||||
@throws Expression::EvaluationError
|
||||
*/
|
||||
virtual Expression getSymbolValue (const String& symbol) const;
|
||||
|
||||
/** Executes a named function.
|
||||
If the function name is unknown, this can throw an Expression::EvaluationError exception.
|
||||
@throws Expression::EvaluationError
|
||||
*/
|
||||
virtual double evaluateFunction (const String& functionName,
|
||||
const double* parameters, int numParameters) const;
|
||||
|
||||
/** Used as a callback by the Scope::visitRelativeScope() method.
|
||||
You should never create an instance of this class yourself, it's used by the
|
||||
expression evaluation code.
|
||||
*/
|
||||
class Visitor
|
||||
{
|
||||
public:
|
||||
virtual ~Visitor() {}
|
||||
virtual void visit (const Scope&) = 0;
|
||||
};
|
||||
|
||||
/** Creates a Scope object for a named scope, and then calls a visitor
|
||||
to do some kind of processing with this new scope.
|
||||
|
||||
If the name is valid, this method must create a suitable (temporary) Scope
|
||||
object to represent it, and must call the Visitor::visit() method with this
|
||||
new scope.
|
||||
*/
|
||||
virtual void visitRelativeScope (const String& scopeName, Visitor& visitor) const;
|
||||
};
|
||||
|
||||
/** Evaluates this expression, without using a Scope.
|
||||
Without a Scope, no symbols can be used, and only basic functions such as sin, cos, tan,
|
||||
min, max are available.
|
||||
To find out about any errors during evaluation, use the other version of this method which
|
||||
takes a String parameter.
|
||||
*/
|
||||
double evaluate() const;
|
||||
|
||||
/** Evaluates this expression, providing a scope that should be able to evaluate any symbols
|
||||
or functions that it uses.
|
||||
To find out about any errors during evaluation, use the other version of this method which
|
||||
takes a String parameter.
|
||||
*/
|
||||
double evaluate (const Scope& scope) const;
|
||||
|
||||
/** Evaluates this expression, providing a scope that should be able to evaluate any symbols
|
||||
or functions that it uses.
|
||||
*/
|
||||
double evaluate (const Scope& scope, String& evaluationError) const;
|
||||
|
||||
/** Attempts to return an expression which is a copy of this one, but with a constant adjusted
|
||||
to make the expression resolve to a target value.
|
||||
|
||||
E.g. if the expression is "x + 10" and x is 5, then asking for a target value of 8 will return
|
||||
the expression "x + 3". Obviously some expressions can't be reversed in this way, in which
|
||||
case they might just be adjusted by adding a constant to the original expression.
|
||||
|
||||
@throws Expression::EvaluationError
|
||||
*/
|
||||
Expression adjustedToGiveNewResult (double targetValue, const Scope& scope) const;
|
||||
|
||||
/** Represents a symbol that is used in an Expression. */
|
||||
struct Symbol
|
||||
{
|
||||
Symbol (const String& scopeUID, const String& symbolName);
|
||||
bool operator== (const Symbol&) const noexcept;
|
||||
bool operator!= (const Symbol&) const noexcept;
|
||||
|
||||
String scopeUID; /**< The unique ID of the Scope that contains this symbol. */
|
||||
String symbolName; /**< The name of the symbol. */
|
||||
};
|
||||
|
||||
/** Returns a copy of this expression in which all instances of a given symbol have been renamed. */
|
||||
Expression withRenamedSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope) const;
|
||||
|
||||
/** Returns true if this expression makes use of the specified symbol.
|
||||
If a suitable scope is supplied, the search will dereference and recursively check
|
||||
all symbols, so that it can be determined whether this expression relies on the given
|
||||
symbol at any level in its evaluation. If the scope parameter is null, this just checks
|
||||
whether the expression contains any direct references to the symbol.
|
||||
|
||||
@throws Expression::EvaluationError
|
||||
*/
|
||||
bool referencesSymbol (const Symbol& symbol, const Scope& scope) const;
|
||||
|
||||
/** Returns true if this expression contains any symbols. */
|
||||
bool usesAnySymbols() const;
|
||||
|
||||
/** Returns a list of all symbols that may be needed to resolve this expression in the given scope. */
|
||||
void findReferencedSymbols (Array<Symbol>& results, const Scope& scope) const;
|
||||
|
||||
//==============================================================================
|
||||
/** An exception that can be thrown by Expression::parse(). */
|
||||
class ParseError : public std::exception
|
||||
{
|
||||
public:
|
||||
ParseError (const String& message);
|
||||
|
||||
String description;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Expression type.
|
||||
@see Expression::getType()
|
||||
*/
|
||||
enum Type
|
||||
{
|
||||
constantType,
|
||||
functionType,
|
||||
operatorType,
|
||||
symbolType
|
||||
};
|
||||
|
||||
/** Returns the type of this expression. */
|
||||
Type getType() const noexcept;
|
||||
|
||||
/** If this expression is a symbol, function or operator, this returns its identifier. */
|
||||
String getSymbolOrFunction() const;
|
||||
|
||||
/** Returns the number of inputs to this expression.
|
||||
@see getInput
|
||||
*/
|
||||
int getNumInputs() const;
|
||||
|
||||
/** Retrieves one of the inputs to this expression.
|
||||
@see getNumInputs
|
||||
*/
|
||||
Expression getInput (int index) const;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class Term;
|
||||
struct Helpers;
|
||||
friend class Term;
|
||||
friend struct Helpers;
|
||||
friend class ScopedPointer<Term>;
|
||||
friend class ReferenceCountedObjectPtr<Term>;
|
||||
ReferenceCountedObjectPtr<Term> term;
|
||||
|
||||
explicit Expression (Term*);
|
||||
};
|
||||
|
||||
#endif // BEAST_EXPRESSION_BEASTHEADER
|
||||
515
modules/beast_core/maths/beast_MathsFunctions.h
Normal file
515
modules/beast_core/maths/beast_MathsFunctions.h
Normal file
@@ -0,0 +1,515 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_MATHSFUNCTIONS_BEASTHEADER
|
||||
#define BEAST_MATHSFUNCTIONS_BEASTHEADER
|
||||
|
||||
//==============================================================================
|
||||
/*
|
||||
This file sets up some handy mathematical typdefs and functions.
|
||||
*/
|
||||
|
||||
//==============================================================================
|
||||
// Definitions for the int8, int16, int32, int64 and pointer_sized_int types.
|
||||
|
||||
/** A platform-independent 8-bit signed integer type. */
|
||||
typedef signed char int8;
|
||||
/** A platform-independent 8-bit unsigned integer type. */
|
||||
typedef unsigned char uint8;
|
||||
/** A platform-independent 16-bit signed integer type. */
|
||||
typedef signed short int16;
|
||||
/** A platform-independent 16-bit unsigned integer type. */
|
||||
typedef unsigned short uint16;
|
||||
/** A platform-independent 32-bit signed integer type. */
|
||||
typedef signed int int32;
|
||||
/** A platform-independent 32-bit unsigned integer type. */
|
||||
typedef unsigned int uint32;
|
||||
|
||||
#if BEAST_MSVC
|
||||
/** A platform-independent 64-bit integer type. */
|
||||
typedef __int64 int64;
|
||||
/** A platform-independent 64-bit unsigned integer type. */
|
||||
typedef unsigned __int64 uint64;
|
||||
/** A platform-independent macro for writing 64-bit literals, needed because
|
||||
different compilers have different syntaxes for this.
|
||||
|
||||
E.g. writing literal64bit (0x1000000000) will translate to 0x1000000000LL for
|
||||
GCC, or 0x1000000000 for MSVC.
|
||||
*/
|
||||
#define literal64bit(longLiteral) ((__int64) longLiteral)
|
||||
#else
|
||||
/** A platform-independent 64-bit integer type. */
|
||||
typedef long long int64;
|
||||
/** A platform-independent 64-bit unsigned integer type. */
|
||||
typedef unsigned long long uint64;
|
||||
/** A platform-independent macro for writing 64-bit literals, needed because
|
||||
different compilers have different syntaxes for this.
|
||||
|
||||
E.g. writing literal64bit (0x1000000000) will translate to 0x1000000000LL for
|
||||
GCC, or 0x1000000000 for MSVC.
|
||||
*/
|
||||
#define literal64bit(longLiteral) (longLiteral##LL)
|
||||
#endif
|
||||
|
||||
|
||||
#if BEAST_64BIT
|
||||
/** A signed integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
|
||||
typedef int64 pointer_sized_int;
|
||||
/** An unsigned integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
|
||||
typedef uint64 pointer_sized_uint;
|
||||
#elif BEAST_MSVC
|
||||
/** A signed integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
|
||||
typedef _W64 int pointer_sized_int;
|
||||
/** An unsigned integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
|
||||
typedef _W64 unsigned int pointer_sized_uint;
|
||||
#else
|
||||
/** A signed integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
|
||||
typedef int pointer_sized_int;
|
||||
/** An unsigned integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
|
||||
typedef unsigned int pointer_sized_uint;
|
||||
#endif
|
||||
|
||||
#if BEAST_MSVC
|
||||
typedef pointer_sized_int ssize_t;
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
// Some indispensible min/max functions
|
||||
|
||||
/** Returns the larger of two values. */
|
||||
template <typename Type>
|
||||
inline Type bmax (const Type a, const Type b) { return (a < b) ? b : a; }
|
||||
|
||||
/** Returns the larger of three values. */
|
||||
template <typename Type>
|
||||
inline Type bmax (const Type a, const Type b, const Type c) { return (a < b) ? ((b < c) ? c : b) : ((a < c) ? c : a); }
|
||||
|
||||
/** Returns the larger of four values. */
|
||||
template <typename Type>
|
||||
inline Type bmax (const Type a, const Type b, const Type c, const Type d) { return bmax (a, bmax (b, c, d)); }
|
||||
|
||||
/** Returns the smaller of two values. */
|
||||
template <typename Type>
|
||||
inline Type bmin (const Type a, const Type b) { return (b < a) ? b : a; }
|
||||
|
||||
/** Returns the smaller of three values. */
|
||||
template <typename Type>
|
||||
inline Type bmin (const Type a, const Type b, const Type c) { return (b < a) ? ((c < b) ? c : b) : ((c < a) ? c : a); }
|
||||
|
||||
/** Returns the smaller of four values. */
|
||||
template <typename Type>
|
||||
inline Type bmin (const Type a, const Type b, const Type c, const Type d) { return bmin (a, bmin (b, c, d)); }
|
||||
|
||||
/** Scans an array of values, returning the minimum value that it contains. */
|
||||
template <typename Type>
|
||||
const Type findMinimum (const Type* data, int numValues)
|
||||
{
|
||||
if (numValues <= 0)
|
||||
return Type();
|
||||
|
||||
Type result (*data++);
|
||||
|
||||
while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
|
||||
{
|
||||
const Type& v = *data++;
|
||||
if (v < result) result = v;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Scans an array of values, returning the maximum value that it contains. */
|
||||
template <typename Type>
|
||||
const Type findMaximum (const Type* values, int numValues)
|
||||
{
|
||||
if (numValues <= 0)
|
||||
return Type();
|
||||
|
||||
Type result (*values++);
|
||||
|
||||
while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
|
||||
{
|
||||
const Type& v = *values++;
|
||||
if (result < v) result = v;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Scans an array of values, returning the minimum and maximum values that it contains. */
|
||||
template <typename Type>
|
||||
void findMinAndMax (const Type* values, int numValues, Type& lowest, Type& highest)
|
||||
{
|
||||
if (numValues <= 0)
|
||||
{
|
||||
lowest = Type();
|
||||
highest = Type();
|
||||
}
|
||||
else
|
||||
{
|
||||
Type mn (*values++);
|
||||
Type mx (mn);
|
||||
|
||||
while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
|
||||
{
|
||||
const Type& v = *values++;
|
||||
|
||||
if (mx < v) mx = v;
|
||||
if (v < mn) mn = v;
|
||||
}
|
||||
|
||||
lowest = mn;
|
||||
highest = mx;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** Constrains a value to keep it within a given range.
|
||||
|
||||
This will check that the specified value lies between the lower and upper bounds
|
||||
specified, and if not, will return the nearest value that would be in-range. Effectively,
|
||||
it's like calling bmax (lowerLimit, bmin (upperLimit, value)).
|
||||
|
||||
Note that it expects that lowerLimit <= upperLimit. If this isn't true,
|
||||
the results will be unpredictable.
|
||||
|
||||
@param lowerLimit the minimum value to return
|
||||
@param upperLimit the maximum value to return
|
||||
@param valueToConstrain the value to try to return
|
||||
@returns the closest value to valueToConstrain which lies between lowerLimit
|
||||
and upperLimit (inclusive)
|
||||
@see jlimit0To, bmin, bmax
|
||||
*/
|
||||
template <typename Type>
|
||||
inline Type blimit (const Type lowerLimit,
|
||||
const Type upperLimit,
|
||||
const Type valueToConstrain) noexcept
|
||||
{
|
||||
bassert (lowerLimit <= upperLimit); // if these are in the wrong order, results are unpredictable..
|
||||
|
||||
return (valueToConstrain < lowerLimit) ? lowerLimit
|
||||
: ((upperLimit < valueToConstrain) ? upperLimit
|
||||
: valueToConstrain);
|
||||
}
|
||||
|
||||
/** Returns true if a value is at least zero, and also below a specified upper limit.
|
||||
This is basically a quicker way to write:
|
||||
@code valueToTest >= 0 && valueToTest < upperLimit
|
||||
@endcode
|
||||
*/
|
||||
template <typename Type>
|
||||
inline bool isPositiveAndBelow (Type valueToTest, Type upperLimit) noexcept
|
||||
{
|
||||
bassert (Type() <= upperLimit); // makes no sense to call this if the upper limit is itself below zero..
|
||||
return Type() <= valueToTest && valueToTest < upperLimit;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool isPositiveAndBelow (const int valueToTest, const int upperLimit) noexcept
|
||||
{
|
||||
bassert (upperLimit >= 0); // makes no sense to call this if the upper limit is itself below zero..
|
||||
return static_cast <unsigned int> (valueToTest) < static_cast <unsigned int> (upperLimit);
|
||||
}
|
||||
|
||||
/** Returns true if a value is at least zero, and also less than or equal to a specified upper limit.
|
||||
This is basically a quicker way to write:
|
||||
@code valueToTest >= 0 && valueToTest <= upperLimit
|
||||
@endcode
|
||||
*/
|
||||
template <typename Type>
|
||||
inline bool isPositiveAndNotGreaterThan (Type valueToTest, Type upperLimit) noexcept
|
||||
{
|
||||
bassert (Type() <= upperLimit); // makes no sense to call this if the upper limit is itself below zero..
|
||||
return Type() <= valueToTest && valueToTest <= upperLimit;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool isPositiveAndNotGreaterThan (const int valueToTest, const int upperLimit) noexcept
|
||||
{
|
||||
bassert (upperLimit >= 0); // makes no sense to call this if the upper limit is itself below zero..
|
||||
return static_cast <unsigned int> (valueToTest) <= static_cast <unsigned int> (upperLimit);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Handy function to swap two values. */
|
||||
template <typename Type>
|
||||
inline void swapVariables (Type& variable1, Type& variable2)
|
||||
{
|
||||
std::swap (variable1, variable2);
|
||||
}
|
||||
|
||||
/** Handy function for getting the number of elements in a simple const C array.
|
||||
E.g.
|
||||
@code
|
||||
static int myArray[] = { 1, 2, 3 };
|
||||
|
||||
int numElements = numElementsInArray (myArray) // returns 3
|
||||
@endcode
|
||||
*/
|
||||
template <typename Type, int N>
|
||||
inline int numElementsInArray (Type (&array)[N])
|
||||
{
|
||||
(void) array; // (required to avoid a spurious warning in MS compilers)
|
||||
(void) sizeof (0[array]); // This line should cause an error if you pass an object with a user-defined subscript operator
|
||||
return N;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// Some useful maths functions that aren't always present with all compilers and build settings.
|
||||
|
||||
/** Using beast_hypot is easier than dealing with the different types of hypot function
|
||||
that are provided by the various platforms and compilers. */
|
||||
template <typename Type>
|
||||
inline Type beast_hypot (Type a, Type b) noexcept
|
||||
{
|
||||
#if BEAST_MSVC
|
||||
return static_cast <Type> (_hypot (a, b));
|
||||
#else
|
||||
return static_cast <Type> (hypot (a, b));
|
||||
#endif
|
||||
}
|
||||
|
||||
/** 64-bit abs function. */
|
||||
inline int64 abs64 (const int64 n) noexcept
|
||||
{
|
||||
return (n >= 0) ? n : -n;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** A predefined value for Pi, at double-precision.
|
||||
@see float_Pi
|
||||
*/
|
||||
const double double_Pi = 3.1415926535897932384626433832795;
|
||||
|
||||
/** A predefined value for Pi, at single-precision.
|
||||
@see double_Pi
|
||||
*/
|
||||
const float float_Pi = 3.14159265358979323846f;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** The isfinite() method seems to vary between platforms, so this is a
|
||||
platform-independent function for it.
|
||||
*/
|
||||
template <typename FloatingPointType>
|
||||
inline bool beast_isfinite (FloatingPointType value)
|
||||
{
|
||||
#if BEAST_WINDOWS
|
||||
return _finite (value);
|
||||
#elif BEAST_ANDROID
|
||||
return isfinite (value);
|
||||
#else
|
||||
return std::isfinite (value);
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#if BEAST_MSVC
|
||||
#pragma optimize ("t", off)
|
||||
#ifndef __INTEL_COMPILER
|
||||
#pragma float_control (precise, on, push)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** Fast floating-point-to-integer conversion.
|
||||
|
||||
This is faster than using the normal c++ cast to convert a float to an int, and
|
||||
it will round the value to the nearest integer, rather than rounding it down
|
||||
like the normal cast does.
|
||||
|
||||
Note that this routine gets its speed at the expense of some accuracy, and when
|
||||
rounding values whose floating point component is exactly 0.5, odd numbers and
|
||||
even numbers will be rounded up or down differently.
|
||||
*/
|
||||
template <typename FloatType>
|
||||
inline int roundToInt (const FloatType value) noexcept
|
||||
{
|
||||
#ifdef __INTEL_COMPILER
|
||||
#pragma float_control (precise, on, push)
|
||||
#endif
|
||||
|
||||
union { int asInt[2]; double asDouble; } n;
|
||||
n.asDouble = ((double) value) + 6755399441055744.0;
|
||||
|
||||
#if BEAST_BIG_ENDIAN
|
||||
return n.asInt [1];
|
||||
#else
|
||||
return n.asInt [0];
|
||||
#endif
|
||||
}
|
||||
|
||||
#if BEAST_MSVC
|
||||
#ifndef __INTEL_COMPILER
|
||||
#pragma float_control (pop)
|
||||
#endif
|
||||
#pragma optimize ("", on) // resets optimisations to the project defaults
|
||||
#endif
|
||||
|
||||
/** Fast floating-point-to-integer conversion.
|
||||
|
||||
This is a slightly slower and slightly more accurate version of roundDoubleToInt(). It works
|
||||
fine for values above zero, but negative numbers are rounded the wrong way.
|
||||
*/
|
||||
inline int roundToIntAccurate (const double value) noexcept
|
||||
{
|
||||
#ifdef __INTEL_COMPILER
|
||||
#pragma float_control (pop)
|
||||
#endif
|
||||
|
||||
return roundToInt (value + 1.5e-8);
|
||||
}
|
||||
|
||||
/** Fast floating-point-to-integer conversion.
|
||||
|
||||
This is faster than using the normal c++ cast to convert a double to an int, and
|
||||
it will round the value to the nearest integer, rather than rounding it down
|
||||
like the normal cast does.
|
||||
|
||||
Note that this routine gets its speed at the expense of some accuracy, and when
|
||||
rounding values whose floating point component is exactly 0.5, odd numbers and
|
||||
even numbers will be rounded up or down differently. For a more accurate conversion,
|
||||
see roundDoubleToIntAccurate().
|
||||
*/
|
||||
inline int roundDoubleToInt (const double value) noexcept
|
||||
{
|
||||
return roundToInt (value);
|
||||
}
|
||||
|
||||
/** Fast floating-point-to-integer conversion.
|
||||
|
||||
This is faster than using the normal c++ cast to convert a float to an int, and
|
||||
it will round the value to the nearest integer, rather than rounding it down
|
||||
like the normal cast does.
|
||||
|
||||
Note that this routine gets its speed at the expense of some accuracy, and when
|
||||
rounding values whose floating point component is exactly 0.5, odd numbers and
|
||||
even numbers will be rounded up or down differently.
|
||||
*/
|
||||
inline int roundFloatToInt (const float value) noexcept
|
||||
{
|
||||
return roundToInt (value);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if the specified integer is a power-of-two.
|
||||
*/
|
||||
template <typename IntegerType>
|
||||
bool isPowerOfTwo (IntegerType value)
|
||||
{
|
||||
return (value & (value - 1)) == 0;
|
||||
}
|
||||
|
||||
/** Returns the smallest power-of-two which is equal to or greater than the given integer.
|
||||
*/
|
||||
inline int nextPowerOfTwo (int n) noexcept
|
||||
{
|
||||
--n;
|
||||
n |= (n >> 1);
|
||||
n |= (n >> 2);
|
||||
n |= (n >> 4);
|
||||
n |= (n >> 8);
|
||||
n |= (n >> 16);
|
||||
return n + 1;
|
||||
}
|
||||
|
||||
/** Performs a modulo operation, but can cope with the dividend being negative.
|
||||
The divisor must be greater than zero.
|
||||
*/
|
||||
template <typename IntegerType>
|
||||
IntegerType negativeAwareModulo (IntegerType dividend, const IntegerType divisor) noexcept
|
||||
{
|
||||
bassert (divisor > 0);
|
||||
dividend %= divisor;
|
||||
return (dividend < 0) ? (dividend + divisor) : dividend;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#if (BEAST_INTEL && BEAST_32BIT) || defined (DOXYGEN)
|
||||
/** This macro can be applied to a float variable to check whether it contains a denormalised
|
||||
value, and to normalise it if necessary.
|
||||
On CPUs that aren't vulnerable to denormalisation problems, this will have no effect.
|
||||
*/
|
||||
#define BEAST_UNDENORMALISE(x) x += 1.0f; x -= 1.0f;
|
||||
#else
|
||||
#define BEAST_UNDENORMALISE(x)
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
/** This namespace contains a few template classes for helping work out class type variations.
|
||||
*/
|
||||
namespace TypeHelpers
|
||||
{
|
||||
#if BEAST_VC8_OR_EARLIER
|
||||
#define PARAMETER_TYPE(type) const type&
|
||||
#else
|
||||
/** The ParameterType struct is used to find the best type to use when passing some kind
|
||||
of object as a parameter.
|
||||
|
||||
Of course, this is only likely to be useful in certain esoteric template situations.
|
||||
|
||||
Because "typename TypeHelpers::ParameterType<SomeClass>::type" is a bit of a mouthful, there's
|
||||
a PARAMETER_TYPE(SomeClass) macro that you can use to get the same effect.
|
||||
|
||||
E.g. "myFunction (PARAMETER_TYPE (int), PARAMETER_TYPE (MyObject))"
|
||||
would evaluate to "myfunction (int, const MyObject&)", keeping any primitive types as
|
||||
pass-by-value, but passing objects as a const reference, to avoid copying.
|
||||
*/
|
||||
template <typename Type> struct ParameterType { typedef const Type& type; };
|
||||
|
||||
#if ! DOXYGEN
|
||||
template <typename Type> struct ParameterType <Type&> { typedef Type& type; };
|
||||
template <typename Type> struct ParameterType <Type*> { typedef Type* type; };
|
||||
template <> struct ParameterType <char> { typedef char type; };
|
||||
template <> struct ParameterType <unsigned char> { typedef unsigned char type; };
|
||||
template <> struct ParameterType <short> { typedef short type; };
|
||||
template <> struct ParameterType <unsigned short> { typedef unsigned short type; };
|
||||
template <> struct ParameterType <int> { typedef int type; };
|
||||
template <> struct ParameterType <unsigned int> { typedef unsigned int type; };
|
||||
template <> struct ParameterType <long> { typedef long type; };
|
||||
template <> struct ParameterType <unsigned long> { typedef unsigned long type; };
|
||||
template <> struct ParameterType <int64> { typedef int64 type; };
|
||||
template <> struct ParameterType <uint64> { typedef uint64 type; };
|
||||
template <> struct ParameterType <bool> { typedef bool type; };
|
||||
template <> struct ParameterType <float> { typedef float type; };
|
||||
template <> struct ParameterType <double> { typedef double type; };
|
||||
#endif
|
||||
|
||||
/** A helpful macro to simplify the use of the ParameterType template.
|
||||
@see ParameterType
|
||||
*/
|
||||
#define PARAMETER_TYPE(a) typename TypeHelpers::ParameterType<a>::type
|
||||
#endif
|
||||
|
||||
|
||||
/** These templates are designed to take a type, and if it's a double, they return a double
|
||||
type; for anything else, they return a float type.
|
||||
*/
|
||||
template <typename Type> struct SmallestFloatType { typedef float type; };
|
||||
template <> struct SmallestFloatType <double> { typedef double type; };
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
|
||||
#endif // BEAST_MATHSFUNCTIONS_BEASTHEADER
|
||||
171
modules/beast_core/maths/beast_Random.cpp
Normal file
171
modules/beast_core/maths/beast_Random.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
Random::Random (const int64 seedValue) noexcept
|
||||
: seed (seedValue)
|
||||
{
|
||||
}
|
||||
|
||||
Random::Random()
|
||||
: seed (1)
|
||||
{
|
||||
setSeedRandomly();
|
||||
}
|
||||
|
||||
Random::~Random() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
void Random::setSeed (const int64 newSeed) noexcept
|
||||
{
|
||||
seed = newSeed;
|
||||
}
|
||||
|
||||
void Random::combineSeed (const int64 seedValue) noexcept
|
||||
{
|
||||
seed ^= nextInt64() ^ seedValue;
|
||||
}
|
||||
|
||||
void Random::setSeedRandomly()
|
||||
{
|
||||
static int64 globalSeed = 0;
|
||||
|
||||
combineSeed (globalSeed ^ (int64) (pointer_sized_int) this);
|
||||
combineSeed (Time::getMillisecondCounter());
|
||||
combineSeed (Time::getHighResolutionTicks());
|
||||
combineSeed (Time::getHighResolutionTicksPerSecond());
|
||||
combineSeed (Time::currentTimeMillis());
|
||||
globalSeed ^= seed;
|
||||
}
|
||||
|
||||
Random& Random::getSystemRandom() noexcept
|
||||
{
|
||||
static Random sysRand;
|
||||
return sysRand;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
int Random::nextInt() noexcept
|
||||
{
|
||||
seed = (seed * literal64bit (0x5deece66d) + 11) & literal64bit (0xffffffffffff);
|
||||
|
||||
return (int) (seed >> 16);
|
||||
}
|
||||
|
||||
int Random::nextInt (const int maxValue) noexcept
|
||||
{
|
||||
bassert (maxValue > 0);
|
||||
return (int) ((((unsigned int) nextInt()) * (uint64) maxValue) >> 32);
|
||||
}
|
||||
|
||||
int64 Random::nextInt64() noexcept
|
||||
{
|
||||
return (((int64) nextInt()) << 32) | (int64) (uint64) (uint32) nextInt();
|
||||
}
|
||||
|
||||
bool Random::nextBool() noexcept
|
||||
{
|
||||
return (nextInt() & 0x40000000) != 0;
|
||||
}
|
||||
|
||||
float Random::nextFloat() noexcept
|
||||
{
|
||||
return static_cast <uint32> (nextInt()) / (float) 0xffffffff;
|
||||
}
|
||||
|
||||
double Random::nextDouble() noexcept
|
||||
{
|
||||
return static_cast <uint32> (nextInt()) / (double) 0xffffffff;
|
||||
}
|
||||
|
||||
BigInteger Random::nextLargeNumber (const BigInteger& maximumValue)
|
||||
{
|
||||
BigInteger n;
|
||||
|
||||
do
|
||||
{
|
||||
fillBitsRandomly (n, 0, maximumValue.getHighestBit() + 1);
|
||||
}
|
||||
while (n >= maximumValue);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void Random::fillBitsRandomly (BigInteger& arrayToChange, int startBit, int numBits)
|
||||
{
|
||||
arrayToChange.setBit (startBit + numBits - 1, true); // to force the array to pre-allocate space
|
||||
|
||||
while ((startBit & 31) != 0 && numBits > 0)
|
||||
{
|
||||
arrayToChange.setBit (startBit++, nextBool());
|
||||
--numBits;
|
||||
}
|
||||
|
||||
while (numBits >= 32)
|
||||
{
|
||||
arrayToChange.setBitRangeAsInt (startBit, 32, (unsigned int) nextInt());
|
||||
startBit += 32;
|
||||
numBits -= 32;
|
||||
}
|
||||
|
||||
while (--numBits >= 0)
|
||||
arrayToChange.setBit (startBit + numBits, nextBool());
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#if BEAST_UNIT_TESTS
|
||||
|
||||
class RandomTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
RandomTests() : UnitTest ("Random") {}
|
||||
|
||||
void runTest()
|
||||
{
|
||||
beginTest ("Random");
|
||||
|
||||
for (int j = 10; --j >= 0;)
|
||||
{
|
||||
Random r;
|
||||
r.setSeedRandomly();
|
||||
|
||||
for (int i = 20; --i >= 0;)
|
||||
{
|
||||
expect (r.nextDouble() >= 0.0 && r.nextDouble() < 1.0);
|
||||
expect (r.nextFloat() >= 0.0f && r.nextFloat() < 1.0f);
|
||||
expect (r.nextInt (5) >= 0 && r.nextInt (5) < 5);
|
||||
expect (r.nextInt (1) == 0);
|
||||
|
||||
int n = r.nextInt (50) + 1;
|
||||
expect (r.nextInt (n) >= 0 && r.nextInt (n) < n);
|
||||
|
||||
n = r.nextInt (0x7ffffffe) + 1;
|
||||
expect (r.nextInt (n) >= 0 && r.nextInt (n) < n);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static RandomTests randomTests;
|
||||
|
||||
#endif
|
||||
135
modules/beast_core/maths/beast_Random.h
Normal file
135
modules/beast_core/maths/beast_Random.h
Normal file
@@ -0,0 +1,135 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_RANDOM_BEASTHEADER
|
||||
#define BEAST_RANDOM_BEASTHEADER
|
||||
|
||||
#include "beast_BigInteger.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A random number generator.
|
||||
|
||||
You can create a Random object and use it to generate a sequence of random numbers.
|
||||
*/
|
||||
class BEAST_API Random
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a Random object based on a seed value.
|
||||
|
||||
For a given seed value, the subsequent numbers generated by this object
|
||||
will be predictable, so a good idea is to set this value based
|
||||
on the time, e.g.
|
||||
|
||||
new Random (Time::currentTimeMillis())
|
||||
*/
|
||||
explicit Random (int64 seedValue) noexcept;
|
||||
|
||||
/** Creates a Random object using a random seed value.
|
||||
Internally, this calls setSeedRandomly() to randomise the seed.
|
||||
*/
|
||||
Random();
|
||||
|
||||
/** Destructor. */
|
||||
~Random() noexcept;
|
||||
|
||||
/** Returns the next random 32 bit integer.
|
||||
|
||||
@returns a random integer from the full range 0x80000000 to 0x7fffffff
|
||||
*/
|
||||
int nextInt() noexcept;
|
||||
|
||||
/** Returns the next random number, limited to a given range.
|
||||
The maxValue parameter may not be negative, or zero.
|
||||
@returns a random integer between 0 (inclusive) and maxValue (exclusive).
|
||||
*/
|
||||
int nextInt (int maxValue) noexcept;
|
||||
|
||||
/** Returns the next 64-bit random number.
|
||||
|
||||
@returns a random integer from the full range 0x8000000000000000 to 0x7fffffffffffffff
|
||||
*/
|
||||
int64 nextInt64() noexcept;
|
||||
|
||||
/** Returns the next random floating-point number.
|
||||
|
||||
@returns a random value in the range 0 to 1.0
|
||||
*/
|
||||
float nextFloat() noexcept;
|
||||
|
||||
/** Returns the next random floating-point number.
|
||||
|
||||
@returns a random value in the range 0 to 1.0
|
||||
*/
|
||||
double nextDouble() noexcept;
|
||||
|
||||
/** Returns the next random boolean value.
|
||||
*/
|
||||
bool nextBool() noexcept;
|
||||
|
||||
/** Returns a BigInteger containing a random number.
|
||||
|
||||
@returns a random value in the range 0 to (maximumValue - 1).
|
||||
*/
|
||||
BigInteger nextLargeNumber (const BigInteger& maximumValue);
|
||||
|
||||
/** Sets a range of bits in a BigInteger to random values. */
|
||||
void fillBitsRandomly (BigInteger& arrayToChange, int startBit, int numBits);
|
||||
|
||||
//==============================================================================
|
||||
/** Resets this Random object to a given seed value. */
|
||||
void setSeed (int64 newSeed) noexcept;
|
||||
|
||||
/** Merges this object's seed with another value.
|
||||
This sets the seed to be a value created by combining the current seed and this
|
||||
new value.
|
||||
*/
|
||||
void combineSeed (int64 seedValue) noexcept;
|
||||
|
||||
/** Reseeds this generator using a value generated from various semi-random system
|
||||
properties like the current time, etc.
|
||||
|
||||
Because this function convolves the time with the last seed value, calling
|
||||
it repeatedly will increase the randomness of the final result.
|
||||
*/
|
||||
void setSeedRandomly();
|
||||
|
||||
/** The overhead of creating a new Random object is fairly small, but if you want to avoid
|
||||
it, you can call this method to get a global shared Random object.
|
||||
|
||||
It's not thread-safe though, so threads should use their own Random object, otherwise
|
||||
you run the risk of your random numbers becoming.. erm.. randomly corrupted..
|
||||
*/
|
||||
static Random& getSystemRandom() noexcept;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
int64 seed;
|
||||
|
||||
BEAST_LEAK_DETECTOR (Random)
|
||||
};
|
||||
|
||||
|
||||
#endif // BEAST_RANDOM_BEASTHEADER
|
||||
259
modules/beast_core/maths/beast_Range.h
Normal file
259
modules/beast_core/maths/beast_Range.h
Normal file
@@ -0,0 +1,259 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_RANGE_BEASTHEADER
|
||||
#define BEAST_RANGE_BEASTHEADER
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** A general-purpose range object, that simply represents any linear range with
|
||||
a start and end point.
|
||||
|
||||
The templated parameter is expected to be a primitive integer or floating point
|
||||
type, though class types could also be used if they behave in a number-like way.
|
||||
*/
|
||||
template <typename ValueType>
|
||||
class Range
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Constructs an empty range. */
|
||||
Range() noexcept : start(), end()
|
||||
{
|
||||
}
|
||||
|
||||
/** Constructs a range with given start and end values. */
|
||||
Range (const ValueType startValue, const ValueType endValue) noexcept
|
||||
: start (startValue), end (bmax (startValue, endValue))
|
||||
{
|
||||
}
|
||||
|
||||
/** Constructs a copy of another range. */
|
||||
Range (const Range& other) noexcept
|
||||
: start (other.start), end (other.end)
|
||||
{
|
||||
}
|
||||
|
||||
/** Copies another range object. */
|
||||
Range& operator= (Range other) noexcept
|
||||
{
|
||||
start = other.start;
|
||||
end = other.end;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Returns the range that lies between two positions (in either order). */
|
||||
static Range between (const ValueType position1, const ValueType position2) noexcept
|
||||
{
|
||||
return position1 < position2 ? Range (position1, position2)
|
||||
: Range (position2, position1);
|
||||
}
|
||||
|
||||
/** Returns a range with the specified start position and a length of zero. */
|
||||
static Range emptyRange (const ValueType start) noexcept
|
||||
{
|
||||
return Range (start, start);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the start of the range. */
|
||||
inline ValueType getStart() const noexcept { return start; }
|
||||
|
||||
/** Returns the length of the range. */
|
||||
inline ValueType getLength() const noexcept { return end - start; }
|
||||
|
||||
/** Returns the end of the range. */
|
||||
inline ValueType getEnd() const noexcept { return end; }
|
||||
|
||||
/** Returns true if the range has a length of zero. */
|
||||
inline bool isEmpty() const noexcept { return start == end; }
|
||||
|
||||
//==============================================================================
|
||||
/** Changes the start position of the range, leaving the end position unchanged.
|
||||
If the new start position is higher than the current end of the range, the end point
|
||||
will be pushed along to equal it, leaving an empty range at the new position.
|
||||
*/
|
||||
void setStart (const ValueType newStart) noexcept
|
||||
{
|
||||
start = newStart;
|
||||
if (end < newStart)
|
||||
end = newStart;
|
||||
}
|
||||
|
||||
/** Returns a range with the same end as this one, but a different start.
|
||||
If the new start position is higher than the current end of the range, the end point
|
||||
will be pushed along to equal it, returning an empty range at the new position.
|
||||
*/
|
||||
Range withStart (const ValueType newStart) const noexcept
|
||||
{
|
||||
return Range (newStart, bmax (newStart, end));
|
||||
}
|
||||
|
||||
/** Returns a range with the same length as this one, but moved to have the given start position. */
|
||||
Range movedToStartAt (const ValueType newStart) const noexcept
|
||||
{
|
||||
return Range (newStart, end + (newStart - start));
|
||||
}
|
||||
|
||||
/** Changes the end position of the range, leaving the start unchanged.
|
||||
If the new end position is below the current start of the range, the start point
|
||||
will be pushed back to equal the new end point.
|
||||
*/
|
||||
void setEnd (const ValueType newEnd) noexcept
|
||||
{
|
||||
end = newEnd;
|
||||
if (newEnd < start)
|
||||
start = newEnd;
|
||||
}
|
||||
|
||||
/** Returns a range with the same start position as this one, but a different end.
|
||||
If the new end position is below the current start of the range, the start point
|
||||
will be pushed back to equal the new end point.
|
||||
*/
|
||||
Range withEnd (const ValueType newEnd) const noexcept
|
||||
{
|
||||
return Range (bmin (start, newEnd), newEnd);
|
||||
}
|
||||
|
||||
/** Returns a range with the same length as this one, but moved to have the given end position. */
|
||||
Range movedToEndAt (const ValueType newEnd) const noexcept
|
||||
{
|
||||
return Range (start + (newEnd - end), newEnd);
|
||||
}
|
||||
|
||||
/** Changes the length of the range.
|
||||
Lengths less than zero are treated as zero.
|
||||
*/
|
||||
void setLength (const ValueType newLength) noexcept
|
||||
{
|
||||
end = start + bmax (ValueType(), newLength);
|
||||
}
|
||||
|
||||
/** Returns a range with the same start as this one, but a different length.
|
||||
Lengths less than zero are treated as zero.
|
||||
*/
|
||||
Range withLength (const ValueType newLength) const noexcept
|
||||
{
|
||||
return Range (start, start + newLength);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Adds an amount to the start and end of the range. */
|
||||
inline Range operator+= (const ValueType amountToAdd) noexcept
|
||||
{
|
||||
start += amountToAdd;
|
||||
end += amountToAdd;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Subtracts an amount from the start and end of the range. */
|
||||
inline Range operator-= (const ValueType amountToSubtract) noexcept
|
||||
{
|
||||
start -= amountToSubtract;
|
||||
end -= amountToSubtract;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Returns a range that is equal to this one with an amount added to its
|
||||
start and end.
|
||||
*/
|
||||
Range operator+ (const ValueType amountToAdd) const noexcept
|
||||
{
|
||||
return Range (start + amountToAdd, end + amountToAdd);
|
||||
}
|
||||
|
||||
/** Returns a range that is equal to this one with the specified amount
|
||||
subtracted from its start and end. */
|
||||
Range operator- (const ValueType amountToSubtract) const noexcept
|
||||
{
|
||||
return Range (start - amountToSubtract, end - amountToSubtract);
|
||||
}
|
||||
|
||||
bool operator== (Range other) const noexcept { return start == other.start && end == other.end; }
|
||||
bool operator!= (Range other) const noexcept { return start != other.start || end != other.end; }
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if the given position lies inside this range. */
|
||||
bool contains (const ValueType position) const noexcept
|
||||
{
|
||||
return start <= position && position < end;
|
||||
}
|
||||
|
||||
/** Returns the nearest value to the one supplied, which lies within the range. */
|
||||
ValueType clipValue (const ValueType value) const noexcept
|
||||
{
|
||||
return blimit (start, end, value);
|
||||
}
|
||||
|
||||
/** Returns true if the given range lies entirely inside this range. */
|
||||
bool contains (Range other) const noexcept
|
||||
{
|
||||
return start <= other.start && end >= other.end;
|
||||
}
|
||||
|
||||
/** Returns true if the given range intersects this one. */
|
||||
bool intersects (Range other) const noexcept
|
||||
{
|
||||
return other.start < end && start < other.end;
|
||||
}
|
||||
|
||||
/** Returns the range that is the intersection of the two ranges, or an empty range
|
||||
with an undefined start position if they don't overlap. */
|
||||
Range getIntersectionWith (Range other) const noexcept
|
||||
{
|
||||
return Range (bmax (start, other.start),
|
||||
bmin (end, other.end));
|
||||
}
|
||||
|
||||
/** Returns the smallest range that contains both this one and the other one. */
|
||||
Range getUnionWith (Range other) const noexcept
|
||||
{
|
||||
return Range (bmin (start, other.start),
|
||||
bmax (end, other.end));
|
||||
}
|
||||
|
||||
/** Returns a given range, after moving it forwards or backwards to fit it
|
||||
within this range.
|
||||
|
||||
If the supplied range has a greater length than this one, the return value
|
||||
will be this range.
|
||||
|
||||
Otherwise, if the supplied range is smaller than this one, the return value
|
||||
will be the new range, shifted forwards or backwards so that it doesn't extend
|
||||
beyond this one, but keeping its original length.
|
||||
*/
|
||||
Range constrainRange (Range rangeToConstrain) const noexcept
|
||||
{
|
||||
const ValueType otherLen = rangeToConstrain.getLength();
|
||||
return getLength() <= otherLen
|
||||
? *this
|
||||
: rangeToConstrain.movedToStartAt (blimit (start, end - otherLen, rangeToConstrain.getStart()));
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
ValueType start, end;
|
||||
};
|
||||
|
||||
|
||||
#endif // BEAST_RANGE_BEASTHEADER
|
||||
388
modules/beast_core/memory/beast_Atomic.h
Normal file
388
modules/beast_core/memory/beast_Atomic.h
Normal file
@@ -0,0 +1,388 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_ATOMIC_BEASTHEADER
|
||||
#define BEAST_ATOMIC_BEASTHEADER
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Simple class to hold a primitive value and perform atomic operations on it.
|
||||
|
||||
The type used must be a 32 or 64 bit primitive, like an int, pointer, etc.
|
||||
There are methods to perform most of the basic atomic operations.
|
||||
*/
|
||||
template <typename Type>
|
||||
class Atomic
|
||||
{
|
||||
public:
|
||||
/** Creates a new value, initialised to zero. */
|
||||
inline Atomic() noexcept
|
||||
: value (0)
|
||||
{
|
||||
}
|
||||
|
||||
/** Creates a new value, with a given initial value. */
|
||||
inline Atomic (const Type initialValue) noexcept
|
||||
: value (initialValue)
|
||||
{
|
||||
}
|
||||
|
||||
/** Copies another value (atomically). */
|
||||
inline Atomic (const Atomic& other) noexcept
|
||||
: value (other.get())
|
||||
{
|
||||
}
|
||||
|
||||
/** Destructor. */
|
||||
inline ~Atomic() noexcept
|
||||
{
|
||||
// This class can only be used for types which are 32 or 64 bits in size.
|
||||
static_bassert (sizeof (Type) == 4 || sizeof (Type) == 8);
|
||||
}
|
||||
|
||||
/** Atomically reads and returns the current value. */
|
||||
Type get() const noexcept;
|
||||
|
||||
/** Copies another value onto this one (atomically). */
|
||||
inline Atomic& operator= (const Atomic& other) noexcept { exchange (other.get()); return *this; }
|
||||
|
||||
/** Copies another value onto this one (atomically). */
|
||||
inline Atomic& operator= (const Type newValue) noexcept { exchange (newValue); return *this; }
|
||||
|
||||
/** Atomically sets the current value. */
|
||||
void set (Type newValue) noexcept { exchange (newValue); }
|
||||
|
||||
/** Atomically sets the current value, returning the value that was replaced. */
|
||||
Type exchange (Type value) noexcept;
|
||||
|
||||
/** Atomically adds a number to this value, returning the new value. */
|
||||
Type operator+= (Type amountToAdd) noexcept;
|
||||
|
||||
/** Atomically subtracts a number from this value, returning the new value. */
|
||||
Type operator-= (Type amountToSubtract) noexcept;
|
||||
|
||||
/** Atomically increments this value, returning the new value. */
|
||||
Type operator++() noexcept;
|
||||
|
||||
/** Atomically decrements this value, returning the new value. */
|
||||
Type operator--() noexcept;
|
||||
|
||||
/** Atomically compares this value with a target value, and if it is equal, sets
|
||||
this to be equal to a new value.
|
||||
|
||||
This operation is the atomic equivalent of doing this:
|
||||
@code
|
||||
bool compareAndSetBool (Type newValue, Type valueToCompare)
|
||||
{
|
||||
if (get() == valueToCompare)
|
||||
{
|
||||
set (newValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@endcode
|
||||
|
||||
@returns true if the comparison was true and the value was replaced; false if
|
||||
the comparison failed and the value was left unchanged.
|
||||
@see compareAndSetValue
|
||||
*/
|
||||
bool compareAndSetBool (Type newValue, Type valueToCompare) noexcept;
|
||||
|
||||
/** Atomically compares this value with a target value, and if it is equal, sets
|
||||
this to be equal to a new value.
|
||||
|
||||
This operation is the atomic equivalent of doing this:
|
||||
@code
|
||||
Type compareAndSetValue (Type newValue, Type valueToCompare)
|
||||
{
|
||||
Type oldValue = get();
|
||||
if (oldValue == valueToCompare)
|
||||
set (newValue);
|
||||
|
||||
return oldValue;
|
||||
}
|
||||
@endcode
|
||||
|
||||
@returns the old value before it was changed.
|
||||
@see compareAndSetBool
|
||||
*/
|
||||
Type compareAndSetValue (Type newValue, Type valueToCompare) noexcept;
|
||||
|
||||
/** Implements a memory read/write barrier. */
|
||||
static void memoryBarrier() noexcept;
|
||||
|
||||
//==============================================================================
|
||||
#if BEAST_64BIT
|
||||
BEAST_ALIGN (8)
|
||||
#else
|
||||
BEAST_ALIGN (4)
|
||||
#endif
|
||||
|
||||
/** The raw value that this class operates on.
|
||||
This is exposed publically in case you need to manipulate it directly
|
||||
for performance reasons.
|
||||
*/
|
||||
volatile Type value;
|
||||
|
||||
private:
|
||||
static inline Type castFrom32Bit (int32 value) noexcept { return *(Type*) &value; }
|
||||
static inline Type castFrom64Bit (int64 value) noexcept { return *(Type*) &value; }
|
||||
static inline int32 castTo32Bit (Type value) noexcept { return *(int32*) &value; }
|
||||
static inline int64 castTo64Bit (Type value) noexcept { return *(int64*) &value; }
|
||||
|
||||
Type operator++ (int); // better to just use pre-increment with atomics..
|
||||
Type operator-- (int);
|
||||
|
||||
/** This templated negate function will negate pointers as well as integers */
|
||||
template <typename ValueType>
|
||||
inline ValueType negateValue (ValueType n) noexcept
|
||||
{
|
||||
return sizeof (ValueType) == 1 ? (ValueType) -(signed char) n
|
||||
: (sizeof (ValueType) == 2 ? (ValueType) -(short) n
|
||||
: (sizeof (ValueType) == 4 ? (ValueType) -(int) n
|
||||
: ((ValueType) -(int64) n)));
|
||||
}
|
||||
|
||||
/** This templated negate function will negate pointers as well as integers */
|
||||
template <typename PointerType>
|
||||
inline PointerType* negateValue (PointerType* n) noexcept
|
||||
{
|
||||
return reinterpret_cast <PointerType*> (-reinterpret_cast <pointer_sized_int> (n));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/*
|
||||
The following code is in the header so that the atomics can be inlined where possible...
|
||||
*/
|
||||
#if BEAST_IOS || (BEAST_MAC && (BEAST_PPC || BEAST_CLANG || __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2)))
|
||||
#define BEAST_ATOMICS_MAC 1 // Older OSX builds using gcc4.1 or earlier
|
||||
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
|
||||
#define BEAST_MAC_ATOMICS_VOLATILE
|
||||
#else
|
||||
#define BEAST_MAC_ATOMICS_VOLATILE volatile
|
||||
#endif
|
||||
|
||||
#if BEAST_PPC || BEAST_IOS
|
||||
// None of these atomics are available for PPC or for iOS 3.1 or earlier!!
|
||||
template <typename Type> static Type OSAtomicAdd64Barrier (Type b, BEAST_MAC_ATOMICS_VOLATILE Type* a) noexcept { jassertfalse; return *a += b; }
|
||||
template <typename Type> static Type OSAtomicIncrement64Barrier (BEAST_MAC_ATOMICS_VOLATILE Type* a) noexcept { jassertfalse; return ++*a; }
|
||||
template <typename Type> static Type OSAtomicDecrement64Barrier (BEAST_MAC_ATOMICS_VOLATILE Type* a) noexcept { jassertfalse; return --*a; }
|
||||
template <typename Type> static bool OSAtomicCompareAndSwap64Barrier (Type old, Type newValue, BEAST_MAC_ATOMICS_VOLATILE Type* value) noexcept
|
||||
{ jassertfalse; if (old == *value) { *value = newValue; return true; } return false; }
|
||||
#define BEAST_64BIT_ATOMICS_UNAVAILABLE 1
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#elif BEAST_GCC
|
||||
#define BEAST_ATOMICS_GCC 1 // GCC with intrinsics
|
||||
|
||||
#if BEAST_IOS || BEAST_ANDROID // (64-bit ops will compile but not link on these mobile OSes)
|
||||
#define BEAST_64BIT_ATOMICS_UNAVAILABLE 1
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#else
|
||||
#define BEAST_ATOMICS_WINDOWS 1 // Windows with intrinsics
|
||||
|
||||
#if BEAST_USE_INTRINSICS
|
||||
#ifndef __INTEL_COMPILER
|
||||
#pragma intrinsic (_InterlockedExchange, _InterlockedIncrement, _InterlockedDecrement, _InterlockedCompareExchange, \
|
||||
_InterlockedCompareExchange64, _InterlockedExchangeAdd, _ReadWriteBarrier)
|
||||
#endif
|
||||
#define beast_InterlockedExchange(a, b) _InterlockedExchange(a, b)
|
||||
#define beast_InterlockedIncrement(a) _InterlockedIncrement(a)
|
||||
#define beast_InterlockedDecrement(a) _InterlockedDecrement(a)
|
||||
#define beast_InterlockedExchangeAdd(a, b) _InterlockedExchangeAdd(a, b)
|
||||
#define beast_InterlockedCompareExchange(a, b, c) _InterlockedCompareExchange(a, b, c)
|
||||
#define beast_InterlockedCompareExchange64(a, b, c) _InterlockedCompareExchange64(a, b, c)
|
||||
#define beast_MemoryBarrier _ReadWriteBarrier
|
||||
#else
|
||||
long beast_InterlockedExchange (volatile long* a, long b) noexcept;
|
||||
long beast_InterlockedIncrement (volatile long* a) noexcept;
|
||||
long beast_InterlockedDecrement (volatile long* a) noexcept;
|
||||
long beast_InterlockedExchangeAdd (volatile long* a, long b) noexcept;
|
||||
long beast_InterlockedCompareExchange (volatile long* a, long b, long c) noexcept;
|
||||
__int64 beast_InterlockedCompareExchange64 (volatile __int64* a, __int64 b, __int64 c) noexcept;
|
||||
inline void beast_MemoryBarrier() noexcept { long x = 0; beast_InterlockedIncrement (&x); }
|
||||
#endif
|
||||
|
||||
#if BEAST_64BIT
|
||||
#ifndef __INTEL_COMPILER
|
||||
#pragma intrinsic (_InterlockedExchangeAdd64, _InterlockedExchange64, _InterlockedIncrement64, _InterlockedDecrement64)
|
||||
#endif
|
||||
#define beast_InterlockedExchangeAdd64(a, b) _InterlockedExchangeAdd64(a, b)
|
||||
#define beast_InterlockedExchange64(a, b) _InterlockedExchange64(a, b)
|
||||
#define beast_InterlockedIncrement64(a) _InterlockedIncrement64(a)
|
||||
#define beast_InterlockedDecrement64(a) _InterlockedDecrement64(a)
|
||||
#else
|
||||
// None of these atomics are available in a 32-bit Windows build!!
|
||||
template <typename Type> static Type beast_InterlockedExchangeAdd64 (volatile Type* a, Type b) noexcept { jassertfalse; Type old = *a; *a += b; return old; }
|
||||
template <typename Type> static Type beast_InterlockedExchange64 (volatile Type* a, Type b) noexcept { jassertfalse; Type old = *a; *a = b; return old; }
|
||||
template <typename Type> static Type beast_InterlockedIncrement64 (volatile Type* a) noexcept { jassertfalse; return ++*a; }
|
||||
template <typename Type> static Type beast_InterlockedDecrement64 (volatile Type* a) noexcept { jassertfalse; return --*a; }
|
||||
#define BEAST_64BIT_ATOMICS_UNAVAILABLE 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if BEAST_MSVC
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4311) // (truncation warning)
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::get() const noexcept
|
||||
{
|
||||
#if BEAST_ATOMICS_MAC
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((int32) OSAtomicAdd32Barrier ((int32_t) 0, (BEAST_MAC_ATOMICS_VOLATILE int32_t*) &value))
|
||||
: castFrom64Bit ((int64) OSAtomicAdd64Barrier ((int64_t) 0, (BEAST_MAC_ATOMICS_VOLATILE int64_t*) &value));
|
||||
#elif BEAST_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((int32) beast_InterlockedExchangeAdd ((volatile long*) &value, (long) 0))
|
||||
: castFrom64Bit ((int64) beast_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) 0));
|
||||
#elif BEAST_ATOMICS_GCC
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_add_and_fetch ((volatile int32*) &value, 0))
|
||||
: castFrom64Bit ((int64) __sync_add_and_fetch ((volatile int64*) &value, 0));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::exchange (const Type newValue) noexcept
|
||||
{
|
||||
#if BEAST_ATOMICS_MAC || BEAST_ATOMICS_GCC
|
||||
Type currentVal = value;
|
||||
while (! compareAndSetBool (newValue, currentVal)) { currentVal = value; }
|
||||
return currentVal;
|
||||
#elif BEAST_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((int32) beast_InterlockedExchange ((volatile long*) &value, (long) castTo32Bit (newValue)))
|
||||
: castFrom64Bit ((int64) beast_InterlockedExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue)));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::operator+= (const Type amountToAdd) noexcept
|
||||
{
|
||||
#if BEAST_ATOMICS_MAC
|
||||
return sizeof (Type) == 4 ? (Type) OSAtomicAdd32Barrier ((int32_t) castTo32Bit (amountToAdd), (BEAST_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||
: (Type) OSAtomicAdd64Barrier ((int64_t) amountToAdd, (BEAST_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||
#elif BEAST_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? (Type) (beast_InterlockedExchangeAdd ((volatile long*) &value, (long) amountToAdd) + (long) amountToAdd)
|
||||
: (Type) (beast_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) amountToAdd) + (__int64) amountToAdd);
|
||||
#elif BEAST_ATOMICS_GCC
|
||||
return (Type) __sync_add_and_fetch (&value, amountToAdd);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::operator-= (const Type amountToSubtract) noexcept
|
||||
{
|
||||
return operator+= (negateValue (amountToSubtract));
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::operator++() noexcept
|
||||
{
|
||||
#if BEAST_ATOMICS_MAC
|
||||
return sizeof (Type) == 4 ? (Type) OSAtomicIncrement32Barrier ((BEAST_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||
: (Type) OSAtomicIncrement64Barrier ((BEAST_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||
#elif BEAST_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? (Type) beast_InterlockedIncrement ((volatile long*) &value)
|
||||
: (Type) beast_InterlockedIncrement64 ((volatile __int64*) &value);
|
||||
#elif BEAST_ATOMICS_GCC
|
||||
return (Type) __sync_add_and_fetch (&value, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::operator--() noexcept
|
||||
{
|
||||
#if BEAST_ATOMICS_MAC
|
||||
return sizeof (Type) == 4 ? (Type) OSAtomicDecrement32Barrier ((BEAST_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||
: (Type) OSAtomicDecrement64Barrier ((BEAST_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||
#elif BEAST_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? (Type) beast_InterlockedDecrement ((volatile long*) &value)
|
||||
: (Type) beast_InterlockedDecrement64 ((volatile __int64*) &value);
|
||||
#elif BEAST_ATOMICS_GCC
|
||||
return (Type) __sync_add_and_fetch (&value, -1);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline bool Atomic<Type>::compareAndSetBool (const Type newValue, const Type valueToCompare) noexcept
|
||||
{
|
||||
#if BEAST_ATOMICS_MAC
|
||||
return sizeof (Type) == 4 ? OSAtomicCompareAndSwap32Barrier ((int32_t) castTo32Bit (valueToCompare), (int32_t) castTo32Bit (newValue), (BEAST_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||
: OSAtomicCompareAndSwap64Barrier ((int64_t) castTo64Bit (valueToCompare), (int64_t) castTo64Bit (newValue), (BEAST_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||
#elif BEAST_ATOMICS_WINDOWS
|
||||
return compareAndSetValue (newValue, valueToCompare) == valueToCompare;
|
||||
#elif BEAST_ATOMICS_GCC
|
||||
return sizeof (Type) == 4 ? __sync_bool_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue))
|
||||
: __sync_bool_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::compareAndSetValue (const Type newValue, const Type valueToCompare) noexcept
|
||||
{
|
||||
#if BEAST_ATOMICS_MAC
|
||||
for (;;) // Annoying workaround for only having a bool CAS operation..
|
||||
{
|
||||
if (compareAndSetBool (newValue, valueToCompare))
|
||||
return valueToCompare;
|
||||
|
||||
const Type result = value;
|
||||
if (result != valueToCompare)
|
||||
return result;
|
||||
}
|
||||
|
||||
#elif BEAST_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((int32) beast_InterlockedCompareExchange ((volatile long*) &value, (long) castTo32Bit (newValue), (long) castTo32Bit (valueToCompare)))
|
||||
: castFrom64Bit ((int64) beast_InterlockedCompareExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue), (__int64) castTo64Bit (valueToCompare)));
|
||||
#elif BEAST_ATOMICS_GCC
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_val_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue)))
|
||||
: castFrom64Bit ((int64) __sync_val_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue)));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline void Atomic<Type>::memoryBarrier() noexcept
|
||||
{
|
||||
#if BEAST_ATOMICS_MAC
|
||||
OSMemoryBarrier();
|
||||
#elif BEAST_ATOMICS_GCC
|
||||
__sync_synchronize();
|
||||
#elif BEAST_ATOMICS_WINDOWS
|
||||
beast_MemoryBarrier();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if BEAST_MSVC
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif // BEAST_ATOMIC_BEASTHEADER
|
||||
181
modules/beast_core/memory/beast_ByteOrder.h
Normal file
181
modules/beast_core/memory/beast_ByteOrder.h
Normal file
@@ -0,0 +1,181 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_BYTEORDER_BEASTHEADER
|
||||
#define BEAST_BYTEORDER_BEASTHEADER
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** Contains static methods for converting the byte order between different
|
||||
endiannesses.
|
||||
*/
|
||||
class BEAST_API ByteOrder
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Swaps the upper and lower bytes of a 16-bit integer. */
|
||||
static uint16 swap (uint16 value);
|
||||
|
||||
/** Reverses the order of the 4 bytes in a 32-bit integer. */
|
||||
static uint32 swap (uint32 value);
|
||||
|
||||
/** Reverses the order of the 8 bytes in a 64-bit integer. */
|
||||
static uint64 swap (uint64 value);
|
||||
|
||||
//==============================================================================
|
||||
/** Swaps the byte order of a 16-bit int if the CPU is big-endian */
|
||||
static uint16 swapIfBigEndian (uint16 value);
|
||||
|
||||
/** Swaps the byte order of a 32-bit int if the CPU is big-endian */
|
||||
static uint32 swapIfBigEndian (uint32 value);
|
||||
|
||||
/** Swaps the byte order of a 64-bit int if the CPU is big-endian */
|
||||
static uint64 swapIfBigEndian (uint64 value);
|
||||
|
||||
/** Swaps the byte order of a 16-bit int if the CPU is little-endian */
|
||||
static uint16 swapIfLittleEndian (uint16 value);
|
||||
|
||||
/** Swaps the byte order of a 32-bit int if the CPU is little-endian */
|
||||
static uint32 swapIfLittleEndian (uint32 value);
|
||||
|
||||
/** Swaps the byte order of a 64-bit int if the CPU is little-endian */
|
||||
static uint64 swapIfLittleEndian (uint64 value);
|
||||
|
||||
//==============================================================================
|
||||
/** Turns 4 bytes into a little-endian integer. */
|
||||
static uint32 littleEndianInt (const void* bytes);
|
||||
|
||||
/** Turns 2 bytes into a little-endian integer. */
|
||||
static uint16 littleEndianShort (const void* bytes);
|
||||
|
||||
/** Turns 4 bytes into a big-endian integer. */
|
||||
static uint32 bigEndianInt (const void* bytes);
|
||||
|
||||
/** Turns 2 bytes into a big-endian integer. */
|
||||
static uint16 bigEndianShort (const void* bytes);
|
||||
|
||||
//==============================================================================
|
||||
/** Converts 3 little-endian bytes into a signed 24-bit value (which is sign-extended to 32 bits). */
|
||||
static int littleEndian24Bit (const char* bytes);
|
||||
|
||||
/** Converts 3 big-endian bytes into a signed 24-bit value (which is sign-extended to 32 bits). */
|
||||
static int bigEndian24Bit (const char* bytes);
|
||||
|
||||
/** Copies a 24-bit number to 3 little-endian bytes. */
|
||||
static void littleEndian24BitToChars (int value, char* destBytes);
|
||||
|
||||
/** Copies a 24-bit number to 3 big-endian bytes. */
|
||||
static void bigEndian24BitToChars (int value, char* destBytes);
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if the current CPU is big-endian. */
|
||||
static bool isBigEndian();
|
||||
|
||||
private:
|
||||
ByteOrder();
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE (ByteOrder)
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
#if BEAST_USE_INTRINSICS && ! defined (__INTEL_COMPILER)
|
||||
#pragma intrinsic (_byteswap_ulong)
|
||||
#endif
|
||||
|
||||
inline uint16 ByteOrder::swap (uint16 n)
|
||||
{
|
||||
#if BEAST_USE_INTRINSICSxxx // agh - the MS compiler has an internal error when you try to use this intrinsic!
|
||||
return static_cast <uint16> (_byteswap_ushort (n));
|
||||
#else
|
||||
return static_cast <uint16> ((n << 8) | (n >> 8));
|
||||
#endif
|
||||
}
|
||||
|
||||
inline uint32 ByteOrder::swap (uint32 n)
|
||||
{
|
||||
#if BEAST_MAC || BEAST_IOS
|
||||
return OSSwapInt32 (n);
|
||||
#elif BEAST_GCC && BEAST_INTEL && ! BEAST_NO_INLINE_ASM
|
||||
asm("bswap %%eax" : "=a"(n) : "a"(n));
|
||||
return n;
|
||||
#elif BEAST_USE_INTRINSICS
|
||||
return _byteswap_ulong (n);
|
||||
#elif BEAST_MSVC && ! BEAST_NO_INLINE_ASM
|
||||
__asm {
|
||||
mov eax, n
|
||||
bswap eax
|
||||
mov n, eax
|
||||
}
|
||||
return n;
|
||||
#elif BEAST_ANDROID
|
||||
return bswap_32 (n);
|
||||
#else
|
||||
return (n << 24) | (n >> 24) | ((n & 0xff00) << 8) | ((n & 0xff0000) >> 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline uint64 ByteOrder::swap (uint64 value)
|
||||
{
|
||||
#if BEAST_MAC || BEAST_IOS
|
||||
return OSSwapInt64 (value);
|
||||
#elif BEAST_USE_INTRINSICS
|
||||
return _byteswap_uint64 (value);
|
||||
#else
|
||||
return (((int64) swap ((uint32) value)) << 32) | swap ((uint32) (value >> 32));
|
||||
#endif
|
||||
}
|
||||
|
||||
#if BEAST_LITTLE_ENDIAN
|
||||
inline uint16 ByteOrder::swapIfBigEndian (const uint16 v) { return v; }
|
||||
inline uint32 ByteOrder::swapIfBigEndian (const uint32 v) { return v; }
|
||||
inline uint64 ByteOrder::swapIfBigEndian (const uint64 v) { return v; }
|
||||
inline uint16 ByteOrder::swapIfLittleEndian (const uint16 v) { return swap (v); }
|
||||
inline uint32 ByteOrder::swapIfLittleEndian (const uint32 v) { return swap (v); }
|
||||
inline uint64 ByteOrder::swapIfLittleEndian (const uint64 v) { return swap (v); }
|
||||
inline uint32 ByteOrder::littleEndianInt (const void* const bytes) { return *static_cast <const uint32*> (bytes); }
|
||||
inline uint16 ByteOrder::littleEndianShort (const void* const bytes) { return *static_cast <const uint16*> (bytes); }
|
||||
inline uint32 ByteOrder::bigEndianInt (const void* const bytes) { return swap (*static_cast <const uint32*> (bytes)); }
|
||||
inline uint16 ByteOrder::bigEndianShort (const void* const bytes) { return swap (*static_cast <const uint16*> (bytes)); }
|
||||
inline bool ByteOrder::isBigEndian() { return false; }
|
||||
#else
|
||||
inline uint16 ByteOrder::swapIfBigEndian (const uint16 v) { return swap (v); }
|
||||
inline uint32 ByteOrder::swapIfBigEndian (const uint32 v) { return swap (v); }
|
||||
inline uint64 ByteOrder::swapIfBigEndian (const uint64 v) { return swap (v); }
|
||||
inline uint16 ByteOrder::swapIfLittleEndian (const uint16 v) { return v; }
|
||||
inline uint32 ByteOrder::swapIfLittleEndian (const uint32 v) { return v; }
|
||||
inline uint64 ByteOrder::swapIfLittleEndian (const uint64 v) { return v; }
|
||||
inline uint32 ByteOrder::littleEndianInt (const void* const bytes) { return swap (*static_cast <const uint32*> (bytes)); }
|
||||
inline uint16 ByteOrder::littleEndianShort (const void* const bytes) { return swap (*static_cast <const uint16*> (bytes)); }
|
||||
inline uint32 ByteOrder::bigEndianInt (const void* const bytes) { return *static_cast <const uint32*> (bytes); }
|
||||
inline uint16 ByteOrder::bigEndianShort (const void* const bytes) { return *static_cast <const uint16*> (bytes); }
|
||||
inline bool ByteOrder::isBigEndian() { return true; }
|
||||
#endif
|
||||
|
||||
inline int ByteOrder::littleEndian24Bit (const char* const bytes) { return (((int) bytes[2]) << 16) | (((int) (uint8) bytes[1]) << 8) | ((int) (uint8) bytes[0]); }
|
||||
inline int ByteOrder::bigEndian24Bit (const char* const bytes) { return (((int) bytes[0]) << 16) | (((int) (uint8) bytes[1]) << 8) | ((int) (uint8) bytes[2]); }
|
||||
inline void ByteOrder::littleEndian24BitToChars (const int value, char* const destBytes) { destBytes[0] = (char)(value & 0xff); destBytes[1] = (char)((value >> 8) & 0xff); destBytes[2] = (char)((value >> 16) & 0xff); }
|
||||
inline void ByteOrder::bigEndian24BitToChars (const int value, char* const destBytes) { destBytes[0] = (char)((value >> 16) & 0xff); destBytes[1] = (char)((value >> 8) & 0xff); destBytes[2] = (char)(value & 0xff); }
|
||||
|
||||
|
||||
#endif // BEAST_BYTEORDER_BEASTHEADER
|
||||
303
modules/beast_core/memory/beast_HeapBlock.h
Normal file
303
modules/beast_core/memory/beast_HeapBlock.h
Normal file
@@ -0,0 +1,303 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_HEAPBLOCK_BEASTHEADER
|
||||
#define BEAST_HEAPBLOCK_BEASTHEADER
|
||||
|
||||
#ifndef DOXYGEN
|
||||
namespace HeapBlockHelper
|
||||
{
|
||||
template <bool shouldThrow>
|
||||
struct ThrowOnFail { static void check (void*) {} };
|
||||
|
||||
template<>
|
||||
struct ThrowOnFail <true> { static void check (void* data) { if (data == nullptr) throw std::bad_alloc(); } };
|
||||
}
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Very simple container class to hold a pointer to some data on the heap.
|
||||
|
||||
When you need to allocate some heap storage for something, always try to use
|
||||
this class instead of allocating the memory directly using malloc/free.
|
||||
|
||||
A HeapBlock<char> object can be treated in pretty much exactly the same way
|
||||
as an char*, but as long as you allocate it on the stack or as a class member,
|
||||
it's almost impossible for it to leak memory.
|
||||
|
||||
It also makes your code much more concise and readable than doing the same thing
|
||||
using direct allocations,
|
||||
|
||||
E.g. instead of this:
|
||||
@code
|
||||
int* temp = (int*) malloc (1024 * sizeof (int));
|
||||
memcpy (temp, xyz, 1024 * sizeof (int));
|
||||
free (temp);
|
||||
temp = (int*) calloc (2048 * sizeof (int));
|
||||
temp[0] = 1234;
|
||||
memcpy (foobar, temp, 2048 * sizeof (int));
|
||||
free (temp);
|
||||
@endcode
|
||||
|
||||
..you could just write this:
|
||||
@code
|
||||
HeapBlock <int> temp (1024);
|
||||
memcpy (temp, xyz, 1024 * sizeof (int));
|
||||
temp.calloc (2048);
|
||||
temp[0] = 1234;
|
||||
memcpy (foobar, temp, 2048 * sizeof (int));
|
||||
@endcode
|
||||
|
||||
The class is extremely lightweight, containing only a pointer to the
|
||||
data, and exposes malloc/realloc/calloc/free methods that do the same jobs
|
||||
as their less object-oriented counterparts. Despite adding safety, you probably
|
||||
won't sacrifice any performance by using this in place of normal pointers.
|
||||
|
||||
The throwOnFailure template parameter can be set to true if you'd like the class
|
||||
to throw a std::bad_alloc exception when an allocation fails. If this is false,
|
||||
then a failed allocation will just leave the heapblock with a null pointer (assuming
|
||||
that the system's malloc() function doesn't throw).
|
||||
|
||||
@see Array, OwnedArray, MemoryBlock
|
||||
*/
|
||||
template <class ElementType, bool throwOnFailure = false>
|
||||
class HeapBlock
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a HeapBlock which is initially just a null pointer.
|
||||
|
||||
After creation, you can resize the array using the malloc(), calloc(),
|
||||
or realloc() methods.
|
||||
*/
|
||||
HeapBlock() noexcept : data (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
/** Creates a HeapBlock containing a number of elements.
|
||||
|
||||
The contents of the block are undefined, as it will have been created by a
|
||||
malloc call.
|
||||
|
||||
If you want an array of zero values, you can use the calloc() method or the
|
||||
other constructor that takes an InitialisationState parameter.
|
||||
*/
|
||||
explicit HeapBlock (const size_t numElements)
|
||||
: data (static_cast <ElementType*> (std::malloc (numElements * sizeof (ElementType))))
|
||||
{
|
||||
throwOnAllocationFailure();
|
||||
}
|
||||
|
||||
/** Creates a HeapBlock containing a number of elements.
|
||||
|
||||
The initialiseToZero parameter determines whether the new memory should be cleared,
|
||||
or left uninitialised.
|
||||
*/
|
||||
HeapBlock (const size_t numElements, const bool initialiseToZero)
|
||||
: data (static_cast <ElementType*> (initialiseToZero
|
||||
? std::calloc (numElements, sizeof (ElementType))
|
||||
: std::malloc (numElements * sizeof (ElementType))))
|
||||
{
|
||||
throwOnAllocationFailure();
|
||||
}
|
||||
|
||||
/** Destructor.
|
||||
This will free the data, if any has been allocated.
|
||||
*/
|
||||
~HeapBlock()
|
||||
{
|
||||
std::free (data);
|
||||
}
|
||||
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
HeapBlock (HeapBlock&& other) noexcept
|
||||
: data (other.data)
|
||||
{
|
||||
other.data = nullptr;
|
||||
}
|
||||
|
||||
HeapBlock& operator= (HeapBlock&& other) noexcept
|
||||
{
|
||||
std::swap (data, other.data);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a raw pointer to the allocated data.
|
||||
This may be a null pointer if the data hasn't yet been allocated, or if it has been
|
||||
freed by calling the free() method.
|
||||
*/
|
||||
inline operator ElementType*() const noexcept { return data; }
|
||||
|
||||
/** Returns a raw pointer to the allocated data.
|
||||
This may be a null pointer if the data hasn't yet been allocated, or if it has been
|
||||
freed by calling the free() method.
|
||||
*/
|
||||
inline ElementType* getData() const noexcept { return data; }
|
||||
|
||||
/** Returns a void pointer to the allocated data.
|
||||
This may be a null pointer if the data hasn't yet been allocated, or if it has been
|
||||
freed by calling the free() method.
|
||||
*/
|
||||
inline operator void*() const noexcept { return static_cast <void*> (data); }
|
||||
|
||||
/** Returns a void pointer to the allocated data.
|
||||
This may be a null pointer if the data hasn't yet been allocated, or if it has been
|
||||
freed by calling the free() method.
|
||||
*/
|
||||
inline operator const void*() const noexcept { return static_cast <const void*> (data); }
|
||||
|
||||
/** Lets you use indirect calls to the first element in the array.
|
||||
Obviously this will cause problems if the array hasn't been initialised, because it'll
|
||||
be referencing a null pointer.
|
||||
*/
|
||||
inline ElementType* operator->() const noexcept { return data; }
|
||||
|
||||
/** Returns a reference to one of the data elements.
|
||||
Obviously there's no bounds-checking here, as this object is just a dumb pointer and
|
||||
has no idea of the size it currently has allocated.
|
||||
*/
|
||||
template <typename IndexType>
|
||||
inline ElementType& operator[] (IndexType index) const noexcept { return data [index]; }
|
||||
|
||||
/** Returns a pointer to a data element at an offset from the start of the array.
|
||||
This is the same as doing pointer arithmetic on the raw pointer itself.
|
||||
*/
|
||||
template <typename IndexType>
|
||||
inline ElementType* operator+ (IndexType index) const noexcept { return data + index; }
|
||||
|
||||
//==============================================================================
|
||||
/** Compares the pointer with another pointer.
|
||||
This can be handy for checking whether this is a null pointer.
|
||||
*/
|
||||
inline bool operator== (const ElementType* const otherPointer) const noexcept { return otherPointer == data; }
|
||||
|
||||
/** Compares the pointer with another pointer.
|
||||
This can be handy for checking whether this is a null pointer.
|
||||
*/
|
||||
inline bool operator!= (const ElementType* const otherPointer) const noexcept { return otherPointer != data; }
|
||||
|
||||
//==============================================================================
|
||||
/** Allocates a specified amount of memory.
|
||||
|
||||
This uses the normal malloc to allocate an amount of memory for this object.
|
||||
Any previously allocated memory will be freed by this method.
|
||||
|
||||
The number of bytes allocated will be (newNumElements * elementSize). Normally
|
||||
you wouldn't need to specify the second parameter, but it can be handy if you need
|
||||
to allocate a size in bytes rather than in terms of the number of elements.
|
||||
|
||||
The data that is allocated will be freed when this object is deleted, or when you
|
||||
call free() or any of the allocation methods.
|
||||
*/
|
||||
void malloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType))
|
||||
{
|
||||
std::free (data);
|
||||
data = static_cast <ElementType*> (std::malloc (newNumElements * elementSize));
|
||||
throwOnAllocationFailure();
|
||||
}
|
||||
|
||||
/** Allocates a specified amount of memory and clears it.
|
||||
This does the same job as the malloc() method, but clears the memory that it allocates.
|
||||
*/
|
||||
void calloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType))
|
||||
{
|
||||
std::free (data);
|
||||
data = static_cast <ElementType*> (std::calloc (newNumElements, elementSize));
|
||||
throwOnAllocationFailure();
|
||||
}
|
||||
|
||||
/** Allocates a specified amount of memory and optionally clears it.
|
||||
This does the same job as either malloc() or calloc(), depending on the
|
||||
initialiseToZero parameter.
|
||||
*/
|
||||
void allocate (const size_t newNumElements, bool initialiseToZero)
|
||||
{
|
||||
std::free (data);
|
||||
data = static_cast <ElementType*> (initialiseToZero
|
||||
? std::calloc (newNumElements, sizeof (ElementType))
|
||||
: std::malloc (newNumElements * sizeof (ElementType)));
|
||||
throwOnAllocationFailure();
|
||||
}
|
||||
|
||||
/** Re-allocates a specified amount of memory.
|
||||
|
||||
The semantics of this method are the same as malloc() and calloc(), but it
|
||||
uses realloc() to keep as much of the existing data as possible.
|
||||
*/
|
||||
void realloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType))
|
||||
{
|
||||
data = static_cast <ElementType*> (data == nullptr ? std::malloc (newNumElements * elementSize)
|
||||
: std::realloc (data, newNumElements * elementSize));
|
||||
throwOnAllocationFailure();
|
||||
}
|
||||
|
||||
/** Frees any currently-allocated data.
|
||||
This will free the data and reset this object to be a null pointer.
|
||||
*/
|
||||
void free()
|
||||
{
|
||||
std::free (data);
|
||||
data = nullptr;
|
||||
}
|
||||
|
||||
/** Swaps this object's data with the data of another HeapBlock.
|
||||
The two objects simply exchange their data pointers.
|
||||
*/
|
||||
template <bool otherBlockThrows>
|
||||
void swapWith (HeapBlock <ElementType, otherBlockThrows>& other) noexcept
|
||||
{
|
||||
std::swap (data, other.data);
|
||||
}
|
||||
|
||||
/** This fills the block with zeros, up to the number of elements specified.
|
||||
Since the block has no way of knowing its own size, you must make sure that the number of
|
||||
elements you specify doesn't exceed the allocated size.
|
||||
*/
|
||||
void clear (size_t numElements) noexcept
|
||||
{
|
||||
zeromem (data, sizeof (ElementType) * numElements);
|
||||
}
|
||||
|
||||
/** This typedef can be used to get the type of the heapblock's elements. */
|
||||
typedef ElementType Type;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
ElementType* data;
|
||||
|
||||
void throwOnAllocationFailure() const
|
||||
{
|
||||
HeapBlockHelper::ThrowOnFail<throwOnFailure>::check (data);
|
||||
}
|
||||
|
||||
#if ! (defined (BEAST_DLL) || defined (BEAST_DLL_BUILD))
|
||||
BEAST_DECLARE_NON_COPYABLE (HeapBlock)
|
||||
BEAST_PREVENT_HEAP_ALLOCATION // Creating a 'new HeapBlock' would be missing the point!
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#endif // BEAST_HEAPBLOCK_BEASTHEADER
|
||||
144
modules/beast_core/memory/beast_LeakedObjectDetector.h
Normal file
144
modules/beast_core/memory/beast_LeakedObjectDetector.h
Normal file
@@ -0,0 +1,144 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_LEAKEDOBJECTDETECTOR_BEASTHEADER
|
||||
#define BEAST_LEAKEDOBJECTDETECTOR_BEASTHEADER
|
||||
|
||||
#include "../text/beast_String.h"
|
||||
#include "beast_Atomic.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Embedding an instance of this class inside another class can be used as a low-overhead
|
||||
way of detecting leaked instances.
|
||||
|
||||
This class keeps an internal static count of the number of instances that are
|
||||
active, so that when the app is shutdown and the static destructors are called,
|
||||
it can check whether there are any left-over instances that may have been leaked.
|
||||
|
||||
To use it, use the BEAST_LEAK_DETECTOR macro as a simple way to put one in your
|
||||
class declaration. Have a look through the beast codebase for examples, it's used
|
||||
in most of the classes.
|
||||
*/
|
||||
template <class OwnerClass>
|
||||
class LeakedObjectDetector
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
LeakedObjectDetector() noexcept { ++(getCounter().numObjects); }
|
||||
LeakedObjectDetector (const LeakedObjectDetector&) noexcept { ++(getCounter().numObjects); }
|
||||
|
||||
~LeakedObjectDetector()
|
||||
{
|
||||
if (--(getCounter().numObjects) < 0)
|
||||
{
|
||||
DBG ("*** Dangling pointer deletion! Class: " << getLeakedObjectClassName());
|
||||
|
||||
/** If you hit this, then you've managed to delete more instances of this class than you've
|
||||
created.. That indicates that you're deleting some dangling pointers.
|
||||
|
||||
Note that although this assertion will have been triggered during a destructor, it might
|
||||
not be this particular deletion that's at fault - the incorrect one may have happened
|
||||
at an earlier point in the program, and simply not been detected until now.
|
||||
|
||||
Most errors like this are caused by using old-fashioned, non-RAII techniques for
|
||||
your object management. Tut, tut. Always, always use ScopedPointers, OwnedArrays,
|
||||
ReferenceCountedObjects, etc, and avoid the 'delete' operator at all costs!
|
||||
*/
|
||||
jassertfalse;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class LeakCounter
|
||||
{
|
||||
public:
|
||||
LeakCounter() noexcept {}
|
||||
|
||||
~LeakCounter()
|
||||
{
|
||||
if (numObjects.value > 0)
|
||||
{
|
||||
DBG ("*** Leaked objects detected: " << numObjects.value << " instance(s) of class " << getLeakedObjectClassName());
|
||||
|
||||
/** If you hit this, then you've leaked one or more objects of the type specified by
|
||||
the 'OwnerClass' template parameter - the name should have been printed by the line above.
|
||||
|
||||
If you're leaking, it's probably because you're using old-fashioned, non-RAII techniques for
|
||||
your object management. Tut, tut. Always, always use ScopedPointers, OwnedArrays,
|
||||
ReferenceCountedObjects, etc, and avoid the 'delete' operator at all costs!
|
||||
*/
|
||||
jassertfalse;
|
||||
}
|
||||
}
|
||||
|
||||
Atomic<int> numObjects;
|
||||
};
|
||||
|
||||
static const char* getLeakedObjectClassName()
|
||||
{
|
||||
return OwnerClass::getLeakedObjectClassName();
|
||||
}
|
||||
|
||||
static LeakCounter& getCounter() noexcept
|
||||
{
|
||||
static LeakCounter counter;
|
||||
return counter;
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
#if DOXYGEN || ! defined (BEAST_LEAK_DETECTOR)
|
||||
#if (DOXYGEN || BEAST_CHECK_MEMORY_LEAKS)
|
||||
/** This macro lets you embed a leak-detecting object inside a class.
|
||||
|
||||
To use it, simply declare a BEAST_LEAK_DETECTOR(YourClassName) inside a private section
|
||||
of the class declaration. E.g.
|
||||
|
||||
@code
|
||||
class MyClass
|
||||
{
|
||||
public:
|
||||
MyClass();
|
||||
void blahBlah();
|
||||
|
||||
private:
|
||||
BEAST_LEAK_DETECTOR (MyClass)
|
||||
};
|
||||
@endcode
|
||||
|
||||
@see BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR, LeakedObjectDetector
|
||||
*/
|
||||
#define BEAST_LEAK_DETECTOR(OwnerClass) \
|
||||
friend class beast::LeakedObjectDetector<OwnerClass>; \
|
||||
static const char* getLeakedObjectClassName() noexcept { return #OwnerClass; } \
|
||||
beast::LeakedObjectDetector<OwnerClass> BEAST_JOIN_MACRO (leakDetector, __LINE__);
|
||||
#else
|
||||
#define BEAST_LEAK_DETECTOR(OwnerClass)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#endif // BEAST_LEAKEDOBJECTDETECTOR_BEASTHEADER
|
||||
121
modules/beast_core/memory/beast_Memory.h
Normal file
121
modules/beast_core/memory/beast_Memory.h
Normal file
@@ -0,0 +1,121 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_MEMORY_BEASTHEADER
|
||||
#define BEAST_MEMORY_BEASTHEADER
|
||||
|
||||
//==============================================================================
|
||||
/** Fills a block of memory with zeros. */
|
||||
inline void zeromem (void* memory, size_t numBytes) noexcept { memset (memory, 0, numBytes); }
|
||||
|
||||
/** Overwrites a structure or object with zeros. */
|
||||
template <typename Type>
|
||||
inline void zerostruct (Type& structure) noexcept { memset (&structure, 0, sizeof (structure)); }
|
||||
|
||||
/** Delete an object pointer, and sets the pointer to null.
|
||||
|
||||
Remember that it's not good c++ practice to use delete directly - always try to use a ScopedPointer
|
||||
or other automatic lifetime-management system rather than resorting to deleting raw pointers!
|
||||
*/
|
||||
template <typename Type>
|
||||
inline void deleteAndZero (Type& pointer) { delete pointer; pointer = nullptr; }
|
||||
|
||||
/** A handy function which adds a number of bytes to any type of pointer and returns the result.
|
||||
This can be useful to avoid casting pointers to a char* and back when you want to move them by
|
||||
a specific number of bytes,
|
||||
*/
|
||||
template <typename Type, typename IntegerType>
|
||||
inline Type* addBytesToPointer (Type* pointer, IntegerType bytes) noexcept { return (Type*) (((char*) pointer) + bytes); }
|
||||
|
||||
/** A handy function which returns the difference between any two pointers, in bytes.
|
||||
The address of the second pointer is subtracted from the first, and the difference in bytes is returned.
|
||||
*/
|
||||
template <typename Type1, typename Type2>
|
||||
inline int getAddressDifference (Type1* pointer1, Type2* pointer2) noexcept { return (int) (((const char*) pointer1) - (const char*) pointer2); }
|
||||
|
||||
/** If a pointer is non-null, this returns a new copy of the object that it points to, or safely returns
|
||||
nullptr if the pointer is null.
|
||||
*/
|
||||
template <class Type>
|
||||
inline Type* createCopyIfNotNull (const Type* pointer) { return pointer != nullptr ? new Type (*pointer) : nullptr; }
|
||||
|
||||
//==============================================================================
|
||||
#if BEAST_MAC || BEAST_IOS || DOXYGEN
|
||||
|
||||
/** A handy C++ wrapper that creates and deletes an NSAutoreleasePool object using RAII.
|
||||
You should use the BEAST_AUTORELEASEPOOL macro to create a local auto-release pool on the stack.
|
||||
*/
|
||||
class BEAST_API ScopedAutoReleasePool
|
||||
{
|
||||
public:
|
||||
ScopedAutoReleasePool();
|
||||
~ScopedAutoReleasePool();
|
||||
|
||||
private:
|
||||
void* pool;
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE (ScopedAutoReleasePool)
|
||||
};
|
||||
|
||||
/** A macro that can be used to easily declare a local ScopedAutoReleasePool
|
||||
object for RAII-based obj-C autoreleasing.
|
||||
Because this may use the \@autoreleasepool syntax, you must follow the macro with
|
||||
a set of braces to mark the scope of the pool.
|
||||
*/
|
||||
#if (BEAST_COMPILER_SUPPORTS_ARC && defined (__OBJC__)) || DOXYGEN
|
||||
#define BEAST_AUTORELEASEPOOL @autoreleasepool
|
||||
#else
|
||||
#define BEAST_AUTORELEASEPOOL const beast::ScopedAutoReleasePool BEAST_JOIN_MACRO (autoReleasePool_, __LINE__);
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define BEAST_AUTORELEASEPOOL
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
/* In a Windows DLL build, we'll expose some malloc/free functions that live inside the DLL, and use these for
|
||||
allocating all the objects - that way all beast objects in the DLL and in the host will live in the same heap,
|
||||
avoiding problems when an object is created in one module and passed across to another where it is deleted.
|
||||
By piggy-backing on the BEAST_LEAK_DETECTOR macro, these allocators can be injected into most beast classes.
|
||||
*/
|
||||
#if BEAST_MSVC && (defined (BEAST_DLL) || defined (BEAST_DLL_BUILD)) && ! (BEAST_DISABLE_DLL_ALLOCATORS || DOXYGEN)
|
||||
extern BEAST_API void* beastDLL_malloc (size_t);
|
||||
extern BEAST_API void beastDLL_free (void*);
|
||||
|
||||
#define BEAST_LEAK_DETECTOR(OwnerClass) public:\
|
||||
static void* operator new (size_t sz) { return beast::beastDLL_malloc (sz); } \
|
||||
static void* operator new (size_t, void* p) { return p; } \
|
||||
static void operator delete (void* p) { beast::beastDLL_free (p); } \
|
||||
static void operator delete (void*, void*) {}
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
/** (Deprecated) This was a Windows-specific way of checking for object leaks - now please
|
||||
use the BEAST_LEAK_DETECTOR instead.
|
||||
*/
|
||||
#ifndef beast_UseDebuggingNewOperator
|
||||
#define beast_UseDebuggingNewOperator
|
||||
#endif
|
||||
|
||||
|
||||
#endif // BEAST_MEMORY_BEASTHEADER
|
||||
416
modules/beast_core/memory/beast_MemoryBlock.cpp
Normal file
416
modules/beast_core/memory/beast_MemoryBlock.cpp
Normal file
@@ -0,0 +1,416 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
MemoryBlock::MemoryBlock() noexcept
|
||||
: size (0)
|
||||
{
|
||||
}
|
||||
|
||||
MemoryBlock::MemoryBlock (const size_t initialSize, const bool initialiseToZero)
|
||||
{
|
||||
if (initialSize > 0)
|
||||
{
|
||||
size = initialSize;
|
||||
data.allocate (initialSize, initialiseToZero);
|
||||
}
|
||||
else
|
||||
{
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
MemoryBlock::MemoryBlock (const MemoryBlock& other)
|
||||
: size (other.size)
|
||||
{
|
||||
if (size > 0)
|
||||
{
|
||||
bassert (other.data != nullptr);
|
||||
data.malloc (size);
|
||||
memcpy (data, other.data, size);
|
||||
}
|
||||
}
|
||||
|
||||
MemoryBlock::MemoryBlock (const void* const dataToInitialiseFrom, const size_t sizeInBytes)
|
||||
: size (sizeInBytes)
|
||||
{
|
||||
bassert (((ssize_t) sizeInBytes) >= 0);
|
||||
|
||||
if (size > 0)
|
||||
{
|
||||
bassert (dataToInitialiseFrom != nullptr); // non-zero size, but a zero pointer passed-in?
|
||||
|
||||
data.malloc (size);
|
||||
|
||||
if (dataToInitialiseFrom != nullptr)
|
||||
memcpy (data, dataToInitialiseFrom, size);
|
||||
}
|
||||
}
|
||||
|
||||
MemoryBlock::~MemoryBlock() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
MemoryBlock& MemoryBlock::operator= (const MemoryBlock& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
setSize (other.size, false);
|
||||
memcpy (data, other.data, size);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
MemoryBlock::MemoryBlock (MemoryBlock&& other) noexcept
|
||||
: data (static_cast <HeapBlock <char>&&> (other.data)),
|
||||
size (other.size)
|
||||
{
|
||||
}
|
||||
|
||||
MemoryBlock& MemoryBlock::operator= (MemoryBlock&& other) noexcept
|
||||
{
|
||||
data = static_cast <HeapBlock <char>&&> (other.data);
|
||||
size = other.size;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//==============================================================================
|
||||
bool MemoryBlock::operator== (const MemoryBlock& other) const noexcept
|
||||
{
|
||||
return matches (other.data, other.size);
|
||||
}
|
||||
|
||||
bool MemoryBlock::operator!= (const MemoryBlock& other) const noexcept
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
bool MemoryBlock::matches (const void* dataToCompare, size_t dataSize) const noexcept
|
||||
{
|
||||
return size == dataSize
|
||||
&& memcmp (data, dataToCompare, size) == 0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// this will resize the block to this size
|
||||
void MemoryBlock::setSize (const size_t newSize, const bool initialiseToZero)
|
||||
{
|
||||
if (size != newSize)
|
||||
{
|
||||
if (newSize <= 0)
|
||||
{
|
||||
data.free();
|
||||
size = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (data != nullptr)
|
||||
{
|
||||
data.realloc (newSize);
|
||||
|
||||
if (initialiseToZero && (newSize > size))
|
||||
zeromem (data + size, newSize - size);
|
||||
}
|
||||
else
|
||||
{
|
||||
data.allocate (newSize, initialiseToZero);
|
||||
}
|
||||
|
||||
size = newSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryBlock::ensureSize (const size_t minimumSize, const bool initialiseToZero)
|
||||
{
|
||||
if (size < minimumSize)
|
||||
setSize (minimumSize, initialiseToZero);
|
||||
}
|
||||
|
||||
void MemoryBlock::swapWith (MemoryBlock& other) noexcept
|
||||
{
|
||||
std::swap (size, other.size);
|
||||
data.swapWith (other.data);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void MemoryBlock::fillWith (const uint8 value) noexcept
|
||||
{
|
||||
memset (data, (int) value, size);
|
||||
}
|
||||
|
||||
void MemoryBlock::append (const void* const srcData, const size_t numBytes)
|
||||
{
|
||||
if (numBytes > 0)
|
||||
{
|
||||
bassert (srcData != nullptr); // this must not be null!
|
||||
const size_t oldSize = size;
|
||||
setSize (size + numBytes);
|
||||
memcpy (data + oldSize, srcData, numBytes);
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryBlock::replaceWith (const void* const srcData, const size_t numBytes)
|
||||
{
|
||||
if (numBytes > 0)
|
||||
{
|
||||
bassert (srcData != nullptr); // this must not be null!
|
||||
setSize (numBytes);
|
||||
memcpy (data, srcData, numBytes);
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryBlock::insert (const void* const srcData, const size_t numBytes, size_t insertPosition)
|
||||
{
|
||||
if (numBytes > 0)
|
||||
{
|
||||
bassert (srcData != nullptr); // this must not be null!
|
||||
insertPosition = bmin (size, insertPosition);
|
||||
const size_t trailingDataSize = size - insertPosition;
|
||||
setSize (size + numBytes, false);
|
||||
|
||||
if (trailingDataSize > 0)
|
||||
memmove (data + insertPosition + numBytes,
|
||||
data + insertPosition,
|
||||
trailingDataSize);
|
||||
|
||||
memcpy (data + insertPosition, srcData, numBytes);
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryBlock::removeSection (const size_t startByte, const size_t numBytesToRemove)
|
||||
{
|
||||
if (startByte + numBytesToRemove >= size)
|
||||
{
|
||||
setSize (startByte);
|
||||
}
|
||||
else if (numBytesToRemove > 0)
|
||||
{
|
||||
memmove (data + startByte,
|
||||
data + startByte + numBytesToRemove,
|
||||
size - (startByte + numBytesToRemove));
|
||||
|
||||
setSize (size - numBytesToRemove);
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryBlock::copyFrom (const void* const src, int offset, size_t num) noexcept
|
||||
{
|
||||
const char* d = static_cast<const char*> (src);
|
||||
|
||||
if (offset < 0)
|
||||
{
|
||||
d -= offset;
|
||||
num -= offset;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if (offset + num > size)
|
||||
num = size - offset;
|
||||
|
||||
if (num > 0)
|
||||
memcpy (data + offset, d, num);
|
||||
}
|
||||
|
||||
void MemoryBlock::copyTo (void* const dst, int offset, size_t num) const noexcept
|
||||
{
|
||||
char* d = static_cast<char*> (dst);
|
||||
|
||||
if (offset < 0)
|
||||
{
|
||||
zeromem (d, (size_t) -offset);
|
||||
d -= offset;
|
||||
|
||||
num += offset;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if (offset + num > size)
|
||||
{
|
||||
const size_t newNum = size - offset;
|
||||
zeromem (d + newNum, num - newNum);
|
||||
num = newNum;
|
||||
}
|
||||
|
||||
if (num > 0)
|
||||
memcpy (d, data + offset, num);
|
||||
}
|
||||
|
||||
String MemoryBlock::toString() const
|
||||
{
|
||||
return String (CharPointer_UTF8 (data), size);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
int MemoryBlock::getBitRange (const size_t bitRangeStart, size_t numBits) const noexcept
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
size_t byte = bitRangeStart >> 3;
|
||||
int offsetInByte = (int) bitRangeStart & 7;
|
||||
size_t bitsSoFar = 0;
|
||||
|
||||
while (numBits > 0 && (size_t) byte < size)
|
||||
{
|
||||
const int bitsThisTime = bmin ((int) numBits, 8 - offsetInByte);
|
||||
const int mask = (0xff >> (8 - bitsThisTime)) << offsetInByte;
|
||||
|
||||
res |= (((data[byte] & mask) >> offsetInByte) << bitsSoFar);
|
||||
|
||||
bitsSoFar += bitsThisTime;
|
||||
numBits -= bitsThisTime;
|
||||
++byte;
|
||||
offsetInByte = 0;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void MemoryBlock::setBitRange (const size_t bitRangeStart, size_t numBits, int bitsToSet) noexcept
|
||||
{
|
||||
size_t byte = bitRangeStart >> 3;
|
||||
int offsetInByte = (int) bitRangeStart & 7;
|
||||
unsigned int mask = ~((((unsigned int) 0xffffffff) << (32 - numBits)) >> (32 - numBits));
|
||||
|
||||
while (numBits > 0 && (size_t) byte < size)
|
||||
{
|
||||
const int bitsThisTime = bmin ((int) numBits, 8 - offsetInByte);
|
||||
|
||||
const unsigned int tempMask = (mask << offsetInByte) | ~((((unsigned int) 0xffffffff) >> offsetInByte) << offsetInByte);
|
||||
const unsigned int tempBits = (unsigned int) bitsToSet << offsetInByte;
|
||||
|
||||
data[byte] = (char) ((data[byte] & tempMask) | tempBits);
|
||||
|
||||
++byte;
|
||||
numBits -= bitsThisTime;
|
||||
bitsToSet >>= bitsThisTime;
|
||||
mask >>= bitsThisTime;
|
||||
offsetInByte = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void MemoryBlock::loadFromHexString (const String& hex)
|
||||
{
|
||||
ensureSize ((size_t) hex.length() >> 1);
|
||||
char* dest = data;
|
||||
String::CharPointerType t (hex.getCharPointer());
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int byte = 0;
|
||||
|
||||
for (int loop = 2; --loop >= 0;)
|
||||
{
|
||||
byte <<= 4;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
const beast_wchar c = t.getAndAdvance();
|
||||
|
||||
if (c >= '0' && c <= '9')
|
||||
{
|
||||
byte |= c - '0';
|
||||
break;
|
||||
}
|
||||
else if (c >= 'a' && c <= 'z')
|
||||
{
|
||||
byte |= c - ('a' - 10);
|
||||
break;
|
||||
}
|
||||
else if (c >= 'A' && c <= 'Z')
|
||||
{
|
||||
byte |= c - ('A' - 10);
|
||||
break;
|
||||
}
|
||||
else if (c == 0)
|
||||
{
|
||||
setSize (static_cast <size_t> (dest - data));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*dest++ = (char) byte;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
const char* const MemoryBlock::encodingTable = ".ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+";
|
||||
|
||||
String MemoryBlock::toBase64Encoding() const
|
||||
{
|
||||
const size_t numChars = ((size << 3) + 5) / 6;
|
||||
|
||||
String destString ((unsigned int) size); // store the length, followed by a '.', and then the data.
|
||||
const int initialLen = destString.length();
|
||||
destString.preallocateBytes (sizeof (String::CharPointerType::CharType) * (size_t) (initialLen + 2 + numChars));
|
||||
|
||||
String::CharPointerType d (destString.getCharPointer());
|
||||
d += initialLen;
|
||||
d.write ('.');
|
||||
|
||||
for (size_t i = 0; i < numChars; ++i)
|
||||
d.write ((beast_wchar) (uint8) encodingTable [getBitRange (i * 6, 6)]);
|
||||
|
||||
d.writeNull();
|
||||
return destString;
|
||||
}
|
||||
|
||||
bool MemoryBlock::fromBase64Encoding (const String& s)
|
||||
{
|
||||
const int startPos = s.indexOfChar ('.') + 1;
|
||||
|
||||
if (startPos <= 0)
|
||||
return false;
|
||||
|
||||
const int numBytesNeeded = s.substring (0, startPos - 1).getIntValue();
|
||||
|
||||
setSize ((size_t) numBytesNeeded, true);
|
||||
|
||||
const int numChars = s.length() - startPos;
|
||||
|
||||
String::CharPointerType srcChars (s.getCharPointer());
|
||||
srcChars += startPos;
|
||||
int pos = 0;
|
||||
|
||||
for (int i = 0; i < numChars; ++i)
|
||||
{
|
||||
const char c = (char) srcChars.getAndAdvance();
|
||||
|
||||
for (int j = 0; j < 64; ++j)
|
||||
{
|
||||
if (encodingTable[j] == c)
|
||||
{
|
||||
setBitRange ((size_t) pos, 6, j);
|
||||
pos += 6;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
255
modules/beast_core/memory/beast_MemoryBlock.h
Normal file
255
modules/beast_core/memory/beast_MemoryBlock.h
Normal file
@@ -0,0 +1,255 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_MEMORYBLOCK_BEASTHEADER
|
||||
#define BEAST_MEMORYBLOCK_BEASTHEADER
|
||||
|
||||
#include "../text/beast_String.h"
|
||||
#include "../memory/beast_HeapBlock.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A class to hold a resizable block of raw data.
|
||||
|
||||
*/
|
||||
class BEAST_API MemoryBlock
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Create an uninitialised block with 0 size. */
|
||||
MemoryBlock() noexcept;
|
||||
|
||||
/** Creates a memory block with a given initial size.
|
||||
|
||||
@param initialSize the size of block to create
|
||||
@param initialiseToZero whether to clear the memory or just leave it uninitialised
|
||||
*/
|
||||
MemoryBlock (const size_t initialSize,
|
||||
bool initialiseToZero = false);
|
||||
|
||||
/** Creates a copy of another memory block. */
|
||||
MemoryBlock (const MemoryBlock& other);
|
||||
|
||||
/** Creates a memory block using a copy of a block of data.
|
||||
|
||||
@param dataToInitialiseFrom some data to copy into this block
|
||||
@param sizeInBytes how much space to use
|
||||
*/
|
||||
MemoryBlock (const void* dataToInitialiseFrom, size_t sizeInBytes);
|
||||
|
||||
/** Destructor. */
|
||||
~MemoryBlock() noexcept;
|
||||
|
||||
/** Copies another memory block onto this one.
|
||||
|
||||
This block will be resized and copied to exactly match the other one.
|
||||
*/
|
||||
MemoryBlock& operator= (const MemoryBlock& other);
|
||||
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
MemoryBlock (MemoryBlock&& other) noexcept;
|
||||
MemoryBlock& operator= (MemoryBlock&& other) noexcept;
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
/** Compares two memory blocks.
|
||||
|
||||
@returns true only if the two blocks are the same size and have identical contents.
|
||||
*/
|
||||
bool operator== (const MemoryBlock& other) const noexcept;
|
||||
|
||||
/** Compares two memory blocks.
|
||||
|
||||
@returns true if the two blocks are different sizes or have different contents.
|
||||
*/
|
||||
bool operator!= (const MemoryBlock& other) const noexcept;
|
||||
|
||||
/** Returns true if the data in this MemoryBlock matches the raw bytes passed-in.
|
||||
*/
|
||||
bool matches (const void* data, size_t dataSize) const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a void pointer to the data.
|
||||
|
||||
Note that the pointer returned will probably become invalid when the
|
||||
block is resized.
|
||||
*/
|
||||
void* getData() const noexcept { return data; }
|
||||
|
||||
/** Returns a byte from the memory block.
|
||||
|
||||
This returns a reference, so you can also use it to set a byte.
|
||||
*/
|
||||
template <typename Type>
|
||||
char& operator[] (const Type offset) const noexcept { return data [offset]; }
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the block's current allocated size, in bytes. */
|
||||
size_t getSize() const noexcept { return size; }
|
||||
|
||||
/** Resizes the memory block.
|
||||
|
||||
This will try to keep as much of the block's current content as it can,
|
||||
and can optionally be made to clear any new space that gets allocated at
|
||||
the end of the block.
|
||||
|
||||
@param newSize the new desired size for the block
|
||||
@param initialiseNewSpaceToZero if the block gets enlarged, this determines
|
||||
whether to clear the new section or just leave it
|
||||
uninitialised
|
||||
@see ensureSize
|
||||
*/
|
||||
void setSize (const size_t newSize,
|
||||
bool initialiseNewSpaceToZero = false);
|
||||
|
||||
/** Increases the block's size only if it's smaller than a given size.
|
||||
|
||||
@param minimumSize if the block is already bigger than this size, no action
|
||||
will be taken; otherwise it will be increased to this size
|
||||
@param initialiseNewSpaceToZero if the block gets enlarged, this determines
|
||||
whether to clear the new section or just leave it
|
||||
uninitialised
|
||||
@see setSize
|
||||
*/
|
||||
void ensureSize (const size_t minimumSize,
|
||||
bool initialiseNewSpaceToZero = false);
|
||||
|
||||
//==============================================================================
|
||||
/** Fills the entire memory block with a repeated byte value.
|
||||
|
||||
This is handy for clearing a block of memory to zero.
|
||||
*/
|
||||
void fillWith (uint8 valueToUse) noexcept;
|
||||
|
||||
/** Adds another block of data to the end of this one.
|
||||
The data pointer must not be null. This block's size will be increased accordingly.
|
||||
*/
|
||||
void append (const void* data, size_t numBytes);
|
||||
|
||||
/** Resizes this block to the given size and fills its contents from the supplied buffer.
|
||||
The data pointer must not be null.
|
||||
*/
|
||||
void replaceWith (const void* data, size_t numBytes);
|
||||
|
||||
/** Inserts some data into the block.
|
||||
The dataToInsert pointer must not be null. This block's size will be increased accordingly.
|
||||
If the insert position lies outside the valid range of the block, it will be clipped to
|
||||
within the range before being used.
|
||||
*/
|
||||
void insert (const void* dataToInsert, size_t numBytesToInsert, size_t insertPosition);
|
||||
|
||||
/** Chops out a section of the block.
|
||||
|
||||
This will remove a section of the memory block and close the gap around it,
|
||||
shifting any subsequent data downwards and reducing the size of the block.
|
||||
|
||||
If the range specified goes beyond the size of the block, it will be clipped.
|
||||
*/
|
||||
void removeSection (size_t startByte, size_t numBytesToRemove);
|
||||
|
||||
//==============================================================================
|
||||
/** Copies data into this MemoryBlock from a memory address.
|
||||
|
||||
@param srcData the memory location of the data to copy into this block
|
||||
@param destinationOffset the offset in this block at which the data being copied should begin
|
||||
@param numBytes how much to copy in (if this goes beyond the size of the memory block,
|
||||
it will be clipped so not to do anything nasty)
|
||||
*/
|
||||
void copyFrom (const void* srcData,
|
||||
int destinationOffset,
|
||||
size_t numBytes) noexcept;
|
||||
|
||||
/** Copies data from this MemoryBlock to a memory address.
|
||||
|
||||
@param destData the memory location to write to
|
||||
@param sourceOffset the offset within this block from which the copied data will be read
|
||||
@param numBytes how much to copy (if this extends beyond the limits of the memory block,
|
||||
zeros will be used for that portion of the data)
|
||||
*/
|
||||
void copyTo (void* destData,
|
||||
int sourceOffset,
|
||||
size_t numBytes) const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Exchanges the contents of this and another memory block.
|
||||
No actual copying is required for this, so it's very fast.
|
||||
*/
|
||||
void swapWith (MemoryBlock& other) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Attempts to parse the contents of the block as a zero-terminated UTF8 string. */
|
||||
String toString() const;
|
||||
|
||||
//==============================================================================
|
||||
/** Parses a string of hexadecimal numbers and writes this data into the memory block.
|
||||
|
||||
The block will be resized to the number of valid bytes read from the string.
|
||||
Non-hex characters in the string will be ignored.
|
||||
|
||||
@see String::toHexString()
|
||||
*/
|
||||
void loadFromHexString (const String& sourceHexString);
|
||||
|
||||
//==============================================================================
|
||||
/** Sets a number of bits in the memory block, treating it as a long binary sequence. */
|
||||
void setBitRange (size_t bitRangeStart,
|
||||
size_t numBits,
|
||||
int binaryNumberToApply) noexcept;
|
||||
|
||||
/** Reads a number of bits from the memory block, treating it as one long binary sequence */
|
||||
int getBitRange (size_t bitRangeStart,
|
||||
size_t numBitsToRead) const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a string of characters that represent the binary contents of this block.
|
||||
|
||||
Uses a 64-bit encoding system to allow binary data to be turned into a string
|
||||
of simple non-extended characters, e.g. for storage in XML.
|
||||
|
||||
@see fromBase64Encoding
|
||||
*/
|
||||
String toBase64Encoding() const;
|
||||
|
||||
/** Takes a string of encoded characters and turns it into binary data.
|
||||
|
||||
The string passed in must have been created by to64BitEncoding(), and this
|
||||
block will be resized to recreate the original data block.
|
||||
|
||||
@see toBase64Encoding
|
||||
*/
|
||||
bool fromBase64Encoding (const String& encodedString);
|
||||
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
HeapBlock <char> data;
|
||||
size_t size;
|
||||
static const char* const encodingTable;
|
||||
|
||||
BEAST_LEAK_DETECTOR (MemoryBlock)
|
||||
};
|
||||
|
||||
|
||||
#endif // BEAST_MEMORYBLOCK_BEASTHEADER
|
||||
183
modules/beast_core/memory/beast_OptionalScopedPointer.h
Normal file
183
modules/beast_core/memory/beast_OptionalScopedPointer.h
Normal file
@@ -0,0 +1,183 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_OPTIONALSCOPEDPOINTER_BEASTHEADER
|
||||
#define BEAST_OPTIONALSCOPEDPOINTER_BEASTHEADER
|
||||
|
||||
#include "beast_ScopedPointer.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Holds a pointer to an object which can optionally be deleted when this pointer
|
||||
goes out of scope.
|
||||
|
||||
This acts in many ways like a ScopedPointer, but allows you to specify whether or
|
||||
not the object is deleted.
|
||||
|
||||
@see ScopedPointer
|
||||
*/
|
||||
template <class ObjectType>
|
||||
class OptionalScopedPointer
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an empty OptionalScopedPointer. */
|
||||
OptionalScopedPointer() : shouldDelete (false) {}
|
||||
|
||||
/** Creates an OptionalScopedPointer to point to a given object, and specifying whether
|
||||
the OptionalScopedPointer will delete it.
|
||||
|
||||
If takeOwnership is true, then the OptionalScopedPointer will act like a ScopedPointer,
|
||||
deleting the object when it is itself deleted. If this parameter is false, then the
|
||||
OptionalScopedPointer just holds a normal pointer to the object, and won't delete it.
|
||||
*/
|
||||
OptionalScopedPointer (ObjectType* objectToHold, bool takeOwnership)
|
||||
: object (objectToHold), shouldDelete (takeOwnership)
|
||||
{
|
||||
}
|
||||
|
||||
/** Takes ownership of the object that another OptionalScopedPointer holds.
|
||||
|
||||
Like a normal ScopedPointer, the objectToTransferFrom object will become null,
|
||||
as ownership of the managed object is transferred to this object.
|
||||
|
||||
The flag to indicate whether or not to delete the managed object is also
|
||||
copied from the source object.
|
||||
*/
|
||||
OptionalScopedPointer (OptionalScopedPointer& objectToTransferFrom)
|
||||
: object (objectToTransferFrom.release()),
|
||||
shouldDelete (objectToTransferFrom.shouldDelete)
|
||||
{
|
||||
}
|
||||
|
||||
/** Takes ownership of the object that another OptionalScopedPointer holds.
|
||||
|
||||
Like a normal ScopedPointer, the objectToTransferFrom object will become null,
|
||||
as ownership of the managed object is transferred to this object.
|
||||
|
||||
The ownership flag that says whether or not to delete the managed object is also
|
||||
copied from the source object.
|
||||
*/
|
||||
OptionalScopedPointer& operator= (OptionalScopedPointer& objectToTransferFrom)
|
||||
{
|
||||
if (object != objectToTransferFrom.object)
|
||||
{
|
||||
clear();
|
||||
object = objectToTransferFrom.object;
|
||||
}
|
||||
|
||||
shouldDelete = objectToTransferFrom.shouldDelete;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** The destructor may or may not delete the object that is being held, depending on the
|
||||
takeOwnership flag that was specified when the object was first passed into an
|
||||
OptionalScopedPointer constructor.
|
||||
*/
|
||||
~OptionalScopedPointer()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the object that this pointer is managing. */
|
||||
inline operator ObjectType*() const noexcept { return object; }
|
||||
|
||||
/** Returns the object that this pointer is managing. */
|
||||
inline ObjectType* get() const noexcept { return object; }
|
||||
|
||||
/** Returns the object that this pointer is managing. */
|
||||
inline ObjectType& operator*() const noexcept { return *object; }
|
||||
|
||||
/** Lets you access methods and properties of the object that this pointer is holding. */
|
||||
inline ObjectType* operator->() const noexcept { return object; }
|
||||
|
||||
//==============================================================================
|
||||
/** Removes the current object from this OptionalScopedPointer without deleting it.
|
||||
This will return the current object, and set this OptionalScopedPointer to a null pointer.
|
||||
*/
|
||||
ObjectType* release() noexcept { return object.release(); }
|
||||
|
||||
/** Resets this pointer to null, possibly deleting the object that it holds, if it has
|
||||
ownership of it.
|
||||
*/
|
||||
void clear()
|
||||
{
|
||||
if (! shouldDelete)
|
||||
object.release();
|
||||
}
|
||||
|
||||
/** Makes this OptionalScopedPointer point at a new object, specifying whether the
|
||||
OptionalScopedPointer will take ownership of the object.
|
||||
|
||||
If takeOwnership is true, then the OptionalScopedPointer will act like a ScopedPointer,
|
||||
deleting the object when it is itself deleted. If this parameter is false, then the
|
||||
OptionalScopedPointer just holds a normal pointer to the object, and won't delete it.
|
||||
*/
|
||||
void set (ObjectType* newObject, bool takeOwnership)
|
||||
{
|
||||
if (object != newObject)
|
||||
{
|
||||
clear();
|
||||
object = newObject;
|
||||
}
|
||||
|
||||
shouldDelete = takeOwnership;
|
||||
}
|
||||
|
||||
/** Makes this OptionalScopedPointer point at a new object, and take ownership of that object. */
|
||||
void setOwned (ObjectType* newObject)
|
||||
{
|
||||
set (newObject, true);
|
||||
}
|
||||
|
||||
/** Makes this OptionalScopedPointer point at a new object, but will not take ownership of that object. */
|
||||
void setNonOwned (ObjectType* newObject)
|
||||
{
|
||||
set (newObject, false);
|
||||
}
|
||||
|
||||
/** Returns true if the target object will be deleted when this pointer
|
||||
object is deleted.
|
||||
*/
|
||||
bool willDeleteObject() const noexcept { return shouldDelete; }
|
||||
|
||||
//==============================================================================
|
||||
/** Swaps this object with another OptionalScopedPointer.
|
||||
The two objects simply exchange their states.
|
||||
*/
|
||||
void swapWith (OptionalScopedPointer<ObjectType>& other) noexcept
|
||||
{
|
||||
object.swapWith (other.object);
|
||||
std::swap (shouldDelete, other.shouldDelete);
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
ScopedPointer<ObjectType> object;
|
||||
bool shouldDelete;
|
||||
};
|
||||
|
||||
|
||||
#endif // BEAST_OPTIONALSCOPEDPOINTER_BEASTHEADER
|
||||
395
modules/beast_core/memory/beast_ReferenceCountedObject.h
Normal file
395
modules/beast_core/memory/beast_ReferenceCountedObject.h
Normal file
@@ -0,0 +1,395 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_REFERENCECOUNTEDOBJECT_BEASTHEADER
|
||||
#define BEAST_REFERENCECOUNTEDOBJECT_BEASTHEADER
|
||||
|
||||
#include "beast_Atomic.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Adds reference-counting to an object.
|
||||
|
||||
To add reference-counting to a class, derive it from this class, and
|
||||
use the ReferenceCountedObjectPtr class to point to it.
|
||||
|
||||
e.g. @code
|
||||
class MyClass : public ReferenceCountedObject
|
||||
{
|
||||
void foo();
|
||||
|
||||
// This is a neat way of declaring a typedef for a pointer class,
|
||||
// rather than typing out the full templated name each time..
|
||||
typedef ReferenceCountedObjectPtr<MyClass> Ptr;
|
||||
};
|
||||
|
||||
MyClass::Ptr p = new MyClass();
|
||||
MyClass::Ptr p2 = p;
|
||||
p = nullptr;
|
||||
p2->foo();
|
||||
@endcode
|
||||
|
||||
Once a new ReferenceCountedObject has been assigned to a pointer, be
|
||||
careful not to delete the object manually.
|
||||
|
||||
This class uses an Atomic<int> value to hold the reference count, so that it
|
||||
the pointers can be passed between threads safely. For a faster but non-thread-safe
|
||||
version, use SingleThreadedReferenceCountedObject instead.
|
||||
|
||||
@see ReferenceCountedObjectPtr, ReferenceCountedArray, SingleThreadedReferenceCountedObject
|
||||
*/
|
||||
class BEAST_API ReferenceCountedObject
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Increments the object's reference count.
|
||||
|
||||
This is done automatically by the smart pointer, but is public just
|
||||
in case it's needed for nefarious purposes.
|
||||
*/
|
||||
inline void incReferenceCount() noexcept
|
||||
{
|
||||
++refCount;
|
||||
}
|
||||
|
||||
/** Decreases the object's reference count.
|
||||
|
||||
If the count gets to zero, the object will be deleted.
|
||||
*/
|
||||
inline void decReferenceCount() noexcept
|
||||
{
|
||||
bassert (getReferenceCount() > 0);
|
||||
|
||||
if (--refCount == 0)
|
||||
delete this;
|
||||
}
|
||||
|
||||
/** Returns the object's current reference count. */
|
||||
inline int getReferenceCount() const noexcept { return refCount.get(); }
|
||||
|
||||
|
||||
protected:
|
||||
//==============================================================================
|
||||
/** Creates the reference-counted object (with an initial ref count of zero). */
|
||||
ReferenceCountedObject()
|
||||
{
|
||||
}
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~ReferenceCountedObject()
|
||||
{
|
||||
// it's dangerous to delete an object that's still referenced by something else!
|
||||
bassert (getReferenceCount() == 0);
|
||||
}
|
||||
|
||||
/** Resets the reference count to zero without deleting the object.
|
||||
You should probably never need to use this!
|
||||
*/
|
||||
void resetReferenceCount() noexcept
|
||||
{
|
||||
refCount = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
Atomic <int> refCount;
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE (ReferenceCountedObject)
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Adds reference-counting to an object.
|
||||
|
||||
This is effectively a version of the ReferenceCountedObject class, but which
|
||||
uses a non-atomic counter, and so is not thread-safe (but which will be more
|
||||
efficient).
|
||||
For more details on how to use it, see the ReferenceCountedObject class notes.
|
||||
|
||||
@see ReferenceCountedObject, ReferenceCountedObjectPtr, ReferenceCountedArray
|
||||
*/
|
||||
class BEAST_API SingleThreadedReferenceCountedObject
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Increments the object's reference count.
|
||||
|
||||
This is done automatically by the smart pointer, but is public just
|
||||
in case it's needed for nefarious purposes.
|
||||
*/
|
||||
inline void incReferenceCount() noexcept
|
||||
{
|
||||
++refCount;
|
||||
}
|
||||
|
||||
/** Decreases the object's reference count.
|
||||
|
||||
If the count gets to zero, the object will be deleted.
|
||||
*/
|
||||
inline void decReferenceCount() noexcept
|
||||
{
|
||||
bassert (getReferenceCount() > 0);
|
||||
|
||||
if (--refCount == 0)
|
||||
delete this;
|
||||
}
|
||||
|
||||
/** Returns the object's current reference count. */
|
||||
inline int getReferenceCount() const noexcept { return refCount; }
|
||||
|
||||
|
||||
protected:
|
||||
//==============================================================================
|
||||
/** Creates the reference-counted object (with an initial ref count of zero). */
|
||||
SingleThreadedReferenceCountedObject() : refCount (0) {}
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~SingleThreadedReferenceCountedObject()
|
||||
{
|
||||
// it's dangerous to delete an object that's still referenced by something else!
|
||||
bassert (getReferenceCount() == 0);
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
int refCount;
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE (SingleThreadedReferenceCountedObject)
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A smart-pointer class which points to a reference-counted object.
|
||||
|
||||
The template parameter specifies the class of the object you want to point to - the easiest
|
||||
way to make a class reference-countable is to simply make it inherit from ReferenceCountedObject,
|
||||
but if you need to, you could roll your own reference-countable class by implementing a pair of
|
||||
mathods called incReferenceCount() and decReferenceCount().
|
||||
|
||||
When using this class, you'll probably want to create a typedef to abbreviate the full
|
||||
templated name - e.g.
|
||||
@code typedef ReferenceCountedObjectPtr<MyClass> MyClassPtr;@endcode
|
||||
|
||||
@see ReferenceCountedObject, ReferenceCountedObjectArray
|
||||
*/
|
||||
template <class ReferenceCountedObjectClass>
|
||||
class ReferenceCountedObjectPtr
|
||||
{
|
||||
public:
|
||||
/** The class being referenced by this pointer. */
|
||||
typedef ReferenceCountedObjectClass ReferencedType;
|
||||
|
||||
//==============================================================================
|
||||
/** Creates a pointer to a null object. */
|
||||
inline ReferenceCountedObjectPtr() noexcept
|
||||
: referencedObject (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
/** Creates a pointer to an object.
|
||||
|
||||
This will increment the object's reference-count if it is non-null.
|
||||
*/
|
||||
inline ReferenceCountedObjectPtr (ReferenceCountedObjectClass* const refCountedObject) noexcept
|
||||
: referencedObject (refCountedObject)
|
||||
{
|
||||
if (refCountedObject != nullptr)
|
||||
refCountedObject->incReferenceCount();
|
||||
}
|
||||
|
||||
/** Copies another pointer.
|
||||
This will increment the object's reference-count (if it is non-null).
|
||||
*/
|
||||
inline ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr& other) noexcept
|
||||
: referencedObject (other.referencedObject)
|
||||
{
|
||||
if (referencedObject != nullptr)
|
||||
referencedObject->incReferenceCount();
|
||||
}
|
||||
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
/** Takes-over the object from another pointer. */
|
||||
inline ReferenceCountedObjectPtr (ReferenceCountedObjectPtr&& other) noexcept
|
||||
: referencedObject (other.referencedObject)
|
||||
{
|
||||
other.referencedObject = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Copies another pointer.
|
||||
This will increment the object's reference-count (if it is non-null).
|
||||
*/
|
||||
template <class DerivedClass>
|
||||
inline ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr<DerivedClass>& other) noexcept
|
||||
: referencedObject (static_cast <ReferenceCountedObjectClass*> (other.get()))
|
||||
{
|
||||
if (referencedObject != nullptr)
|
||||
referencedObject->incReferenceCount();
|
||||
}
|
||||
|
||||
/** Changes this pointer to point at a different object.
|
||||
|
||||
The reference count of the old object is decremented, and it might be
|
||||
deleted if it hits zero. The new object's count is incremented.
|
||||
*/
|
||||
ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr& other)
|
||||
{
|
||||
return operator= (other.referencedObject);
|
||||
}
|
||||
|
||||
/** Changes this pointer to point at a different object.
|
||||
|
||||
The reference count of the old object is decremented, and it might be
|
||||
deleted if it hits zero. The new object's count is incremented.
|
||||
*/
|
||||
template <class DerivedClass>
|
||||
ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr<DerivedClass>& other)
|
||||
{
|
||||
return operator= (static_cast <ReferenceCountedObjectClass*> (other.get()));
|
||||
}
|
||||
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
/** Takes-over the object from another pointer. */
|
||||
ReferenceCountedObjectPtr& operator= (ReferenceCountedObjectPtr&& other)
|
||||
{
|
||||
std::swap (referencedObject, other.referencedObject);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Changes this pointer to point at a different object.
|
||||
|
||||
The reference count of the old object is decremented, and it might be
|
||||
deleted if it hits zero. The new object's count is incremented.
|
||||
*/
|
||||
ReferenceCountedObjectPtr& operator= (ReferenceCountedObjectClass* const newObject)
|
||||
{
|
||||
if (referencedObject != newObject)
|
||||
{
|
||||
if (newObject != nullptr)
|
||||
newObject->incReferenceCount();
|
||||
|
||||
ReferenceCountedObjectClass* const oldObject = referencedObject;
|
||||
referencedObject = newObject;
|
||||
|
||||
if (oldObject != nullptr)
|
||||
oldObject->decReferenceCount();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Destructor.
|
||||
|
||||
This will decrement the object's reference-count, and may delete it if it
|
||||
gets to zero.
|
||||
*/
|
||||
inline ~ReferenceCountedObjectPtr()
|
||||
{
|
||||
if (referencedObject != nullptr)
|
||||
referencedObject->decReferenceCount();
|
||||
}
|
||||
|
||||
/** Returns the object that this pointer references.
|
||||
The pointer returned may be zero, of course.
|
||||
*/
|
||||
inline operator ReferenceCountedObjectClass*() const noexcept
|
||||
{
|
||||
return referencedObject;
|
||||
}
|
||||
|
||||
// the -> operator is called on the referenced object
|
||||
inline ReferenceCountedObjectClass* operator->() const noexcept
|
||||
{
|
||||
return referencedObject;
|
||||
}
|
||||
|
||||
/** Returns the object that this pointer references.
|
||||
The pointer returned may be zero, of course.
|
||||
*/
|
||||
inline ReferenceCountedObjectClass* get() const noexcept
|
||||
{
|
||||
return referencedObject;
|
||||
}
|
||||
|
||||
/** Returns the object that this pointer references.
|
||||
The pointer returned may be zero, of course.
|
||||
*/
|
||||
inline ReferenceCountedObjectClass* getObject() const noexcept
|
||||
{
|
||||
return referencedObject;
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
ReferenceCountedObjectClass* referencedObject;
|
||||
};
|
||||
|
||||
|
||||
/** Compares two ReferenceCountedObjectPointers. */
|
||||
template <class ReferenceCountedObjectClass>
|
||||
bool operator== (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, ReferenceCountedObjectClass* const object2) noexcept
|
||||
{
|
||||
return object1.get() == object2;
|
||||
}
|
||||
|
||||
/** Compares two ReferenceCountedObjectPointers. */
|
||||
template <class ReferenceCountedObjectClass>
|
||||
bool operator== (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
|
||||
{
|
||||
return object1.get() == object2.get();
|
||||
}
|
||||
|
||||
/** Compares two ReferenceCountedObjectPointers. */
|
||||
template <class ReferenceCountedObjectClass>
|
||||
bool operator== (ReferenceCountedObjectClass* object1, ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
|
||||
{
|
||||
return object1 == object2.get();
|
||||
}
|
||||
|
||||
/** Compares two ReferenceCountedObjectPointers. */
|
||||
template <class ReferenceCountedObjectClass>
|
||||
bool operator!= (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, const ReferenceCountedObjectClass* object2) noexcept
|
||||
{
|
||||
return object1.get() != object2;
|
||||
}
|
||||
|
||||
/** Compares two ReferenceCountedObjectPointers. */
|
||||
template <class ReferenceCountedObjectClass>
|
||||
bool operator!= (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
|
||||
{
|
||||
return object1.get() != object2.get();
|
||||
}
|
||||
|
||||
/** Compares two ReferenceCountedObjectPointers. */
|
||||
template <class ReferenceCountedObjectClass>
|
||||
bool operator!= (ReferenceCountedObjectClass* object1, ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
|
||||
{
|
||||
return object1 != object2.get();
|
||||
}
|
||||
|
||||
|
||||
#endif // BEAST_REFERENCECOUNTEDOBJECT_BEASTHEADER
|
||||
@@ -1,41 +1,132 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_SCOPEDPOINTER_BEASTHEADER
|
||||
#define BEAST_SCOPEDPOINTER_BEASTHEADER
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
This class holds a pointer which is automatically deleted when this object goes
|
||||
out of scope.
|
||||
|
||||
Once a pointer has been passed to a ScopedPointer, it will make sure that the pointer
|
||||
gets deleted when the ScopedPointer is deleted. Using the ScopedPointer on the stack or
|
||||
as member variables is a good way to use RAII to avoid accidentally leaking dynamically
|
||||
created objects.
|
||||
|
||||
A ScopedPointer can be used in pretty much the same way that you'd use a normal pointer
|
||||
to an object. If you use the assignment operator to assign a different object to a
|
||||
ScopedPointer, the old one will be automatically deleted.
|
||||
|
||||
Important note: The class is designed to hold a pointer to an object, NOT to an array!
|
||||
It calls delete on its payload, not delete[], so do not give it an array to hold! For
|
||||
that kind of purpose, you should be using HeapBlock or Array instead.
|
||||
|
||||
A const ScopedPointer is guaranteed not to lose ownership of its object or change the
|
||||
object to which it points during its lifetime. This means that making a copy of a const
|
||||
ScopedPointer is impossible, as that would involve the new copy taking ownership from the
|
||||
old one.
|
||||
|
||||
If you need to get a pointer out of a ScopedPointer without it being deleted, you
|
||||
can use the release() method.
|
||||
|
||||
Something to note is the main difference between this class and the std::auto_ptr class,
|
||||
which is that ScopedPointer provides a cast-to-object operator, wheras std::auto_ptr
|
||||
requires that you always call get() to retrieve the pointer. The advantages of providing
|
||||
the cast is that you don't need to call get(), so can use the ScopedPointer in pretty much
|
||||
exactly the same way as a raw pointer. The disadvantage is that the compiler is free to
|
||||
use the cast in unexpected and sometimes dangerous ways - in particular, it becomes difficult
|
||||
to return a ScopedPointer as the result of a function. To avoid this causing errors,
|
||||
ScopedPointer contains an overloaded constructor that should cause a syntax error in these
|
||||
circumstances, but it does mean that instead of returning a ScopedPointer from a function,
|
||||
you'd need to return a raw pointer (or use a std::auto_ptr instead).
|
||||
*/
|
||||
template <class ObjectType>
|
||||
class ScopedPointer
|
||||
{
|
||||
public:
|
||||
inline ScopedPointer() : object (0)
|
||||
//==============================================================================
|
||||
/** Creates a ScopedPointer containing a null pointer. */
|
||||
inline ScopedPointer() noexcept : object (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
inline ScopedPointer (ObjectType* const objectToTakePossessionOf)
|
||||
/** Creates a ScopedPointer that owns the specified object. */
|
||||
inline ScopedPointer (ObjectType* const objectToTakePossessionOf) noexcept
|
||||
: object (objectToTakePossessionOf)
|
||||
{
|
||||
}
|
||||
|
||||
ScopedPointer (ScopedPointer& objectToTransferFrom)
|
||||
/** Creates a ScopedPointer that takes its pointer from another ScopedPointer.
|
||||
|
||||
Because a pointer can only belong to one ScopedPointer, this transfers
|
||||
the pointer from the other object to this one, and the other object is reset to
|
||||
be a null pointer.
|
||||
*/
|
||||
ScopedPointer (ScopedPointer& objectToTransferFrom) noexcept
|
||||
: object (objectToTransferFrom.object)
|
||||
{
|
||||
objectToTransferFrom.object = 0;
|
||||
objectToTransferFrom.object = nullptr;
|
||||
}
|
||||
|
||||
/** Destructor.
|
||||
This will delete the object that this ScopedPointer currently refers to.
|
||||
*/
|
||||
inline ~ScopedPointer() { delete object; }
|
||||
|
||||
/** Changes this ScopedPointer to point to a new object.
|
||||
|
||||
Because a pointer can only belong to one ScopedPointer, this transfers
|
||||
the pointer from the other object to this one, and the other object is reset to
|
||||
be a null pointer.
|
||||
|
||||
If this ScopedPointer already points to an object, that object
|
||||
will first be deleted.
|
||||
*/
|
||||
ScopedPointer& operator= (ScopedPointer& objectToTransferFrom)
|
||||
{
|
||||
if (this != objectToTransferFrom.getAddress())
|
||||
{
|
||||
// Two ScopedPointers should never be able to refer to the same object - if
|
||||
// this happens, you must have done something dodgy!
|
||||
bassert (object == nullptr || object != objectToTransferFrom.object);
|
||||
|
||||
ObjectType* const oldObject = object;
|
||||
object = objectToTransferFrom.object;
|
||||
objectToTransferFrom.object = 0;
|
||||
objectToTransferFrom.object = nullptr;
|
||||
delete oldObject;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Changes this ScopedPointer to point to a new object.
|
||||
|
||||
If this ScopedPointer already points to an object, that object
|
||||
will first be deleted.
|
||||
|
||||
The pointer that you pass in may be a nullptr.
|
||||
*/
|
||||
ScopedPointer& operator= (ObjectType* const newObjectToTakePossessionOf)
|
||||
{
|
||||
if (object != newObjectToTakePossessionOf)
|
||||
@@ -48,39 +139,110 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline operator ObjectType*() const { return object; }
|
||||
inline ObjectType* get() const { return object; }
|
||||
inline ObjectType& operator*() const { return *object; }
|
||||
inline ObjectType* operator->() const { return object; }
|
||||
|
||||
ObjectType* release() { ObjectType* const o = object; object = 0; return o; }
|
||||
|
||||
void swapWith (ScopedPointer <ObjectType>& other)
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
ScopedPointer (ScopedPointer&& other) noexcept
|
||||
: object (other.object)
|
||||
{
|
||||
other.object = nullptr;
|
||||
}
|
||||
|
||||
ScopedPointer& operator= (ScopedPointer&& other) noexcept
|
||||
{
|
||||
object = other.object;
|
||||
other.object = nullptr;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the object that this ScopedPointer refers to. */
|
||||
inline operator ObjectType*() const noexcept { return object; }
|
||||
|
||||
/** Returns the object that this ScopedPointer refers to. */
|
||||
inline ObjectType* get() const noexcept { return object; }
|
||||
|
||||
/** Returns the object that this ScopedPointer refers to. */
|
||||
inline ObjectType& operator*() const noexcept { return *object; }
|
||||
|
||||
/** Lets you access methods and properties of the object that this ScopedPointer refers to. */
|
||||
inline ObjectType* operator->() const noexcept { return object; }
|
||||
|
||||
//==============================================================================
|
||||
/** Removes the current object from this ScopedPointer without deleting it.
|
||||
This will return the current object, and set the ScopedPointer to a null pointer.
|
||||
*/
|
||||
ObjectType* release() noexcept { ObjectType* const o = object; object = nullptr; return o; }
|
||||
|
||||
//==============================================================================
|
||||
/** Swaps this object with that of another ScopedPointer.
|
||||
The two objects simply exchange their pointers.
|
||||
*/
|
||||
void swapWith (ScopedPointer <ObjectType>& other) noexcept
|
||||
{
|
||||
// Two ScopedPointers should never be able to refer to the same object - if
|
||||
// this happens, you must have done something dodgy!
|
||||
bassert (object != other.object || this == other.getAddress());
|
||||
|
||||
std::swap (object, other.object);
|
||||
}
|
||||
|
||||
/** If the pointer is non-null, this will attempt to return a new copy of the object that is pointed to.
|
||||
If the pointer is null, this will safely return a nullptr.
|
||||
*/
|
||||
inline ObjectType* createCopy() const { return createCopyIfNotNull (object); }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
ObjectType* object;
|
||||
|
||||
const ScopedPointer* getAddress() const { return this; }
|
||||
// (Required as an alternative to the overloaded & operator).
|
||||
const ScopedPointer* getAddress() const noexcept { return this; }
|
||||
|
||||
#ifndef _MSC_VER
|
||||
ScopedPointer (const ScopedPointer&);
|
||||
ScopedPointer& operator= (const ScopedPointer&);
|
||||
#if ! BEAST_MSVC // (MSVC can't deal with multiple copy constructors)
|
||||
/* The copy constructors are private to stop people accidentally copying a const ScopedPointer
|
||||
(the compiler would let you do so by implicitly casting the source to its raw object pointer).
|
||||
|
||||
A side effect of this is that in a compiler that doesn't support C++11, you may hit an
|
||||
error when you write something like this:
|
||||
|
||||
ScopedPointer<MyClass> m = new MyClass(); // Compile error: copy constructor is private.
|
||||
|
||||
Even though the compiler would normally ignore the assignment here, it can't do so when the
|
||||
copy constructor is private. It's very easy to fix though - just write it like this:
|
||||
|
||||
ScopedPointer<MyClass> m (new MyClass()); // Compiles OK
|
||||
|
||||
It's probably best to use the latter form when writing your object declarations anyway, as
|
||||
this is a better representation of the code that you actually want the compiler to produce.
|
||||
*/
|
||||
BEAST_DECLARE_NON_COPYABLE (ScopedPointer)
|
||||
#endif
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Compares a ScopedPointer with another pointer.
|
||||
This can be handy for checking whether this is a null pointer.
|
||||
*/
|
||||
template <class ObjectType>
|
||||
bool operator== (const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2)
|
||||
bool operator== (const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) noexcept
|
||||
{
|
||||
return static_cast <ObjectType*> (pointer1) == pointer2;
|
||||
}
|
||||
|
||||
/** Compares a ScopedPointer with another pointer.
|
||||
This can be handy for checking whether this is a null pointer.
|
||||
*/
|
||||
template <class ObjectType>
|
||||
bool operator!= (const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2)
|
||||
bool operator!= (const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) noexcept
|
||||
{
|
||||
return static_cast <ObjectType*> (pointer1) != pointer2;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#ifndef DOXYGEN
|
||||
// NB: This is just here to prevent any silly attempts to call deleteAndZero() on a ScopedPointer.
|
||||
template <typename Type>
|
||||
void deleteAndZero (ScopedPointer<Type>&) { static_bassert (sizeof (Type) == 12345); }
|
||||
#endif
|
||||
|
||||
#endif // BEAST_SCOPEDPOINTER_BEASTHEADER
|
||||
|
||||
287
modules/beast_core/memory/beast_Singleton.h
Normal file
287
modules/beast_core/memory/beast_Singleton.h
Normal file
@@ -0,0 +1,287 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_SINGLETON_BEASTHEADER
|
||||
#define BEAST_SINGLETON_BEASTHEADER
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Macro to declare member variables and methods for a singleton class.
|
||||
|
||||
To use this, add the line beast_DeclareSingleton (MyClass, doNotRecreateAfterDeletion)
|
||||
to the class's definition.
|
||||
|
||||
Then put a macro beast_ImplementSingleton (MyClass) along with the class's
|
||||
implementation code.
|
||||
|
||||
It's also a very good idea to also add the call clearSingletonInstance() in your class's
|
||||
destructor, in case it is deleted by other means than deleteInstance()
|
||||
|
||||
Clients can then call the static method MyClass::getInstance() to get a pointer
|
||||
to the singleton, or MyClass::getInstanceWithoutCreating() which will return 0 if
|
||||
no instance currently exists.
|
||||
|
||||
e.g. @code
|
||||
|
||||
class MySingleton
|
||||
{
|
||||
public:
|
||||
MySingleton()
|
||||
{
|
||||
}
|
||||
|
||||
~MySingleton()
|
||||
{
|
||||
// this ensures that no dangling pointers are left when the
|
||||
// singleton is deleted.
|
||||
clearSingletonInstance();
|
||||
}
|
||||
|
||||
beast_DeclareSingleton (MySingleton, false)
|
||||
};
|
||||
|
||||
beast_ImplementSingleton (MySingleton)
|
||||
|
||||
|
||||
// example of usage:
|
||||
MySingleton* m = MySingleton::getInstance(); // creates the singleton if there isn't already one.
|
||||
|
||||
...
|
||||
|
||||
MySingleton::deleteInstance(); // safely deletes the singleton (if it's been created).
|
||||
|
||||
@endcode
|
||||
|
||||
If doNotRecreateAfterDeletion = true, it won't allow the object to be created more
|
||||
than once during the process's lifetime - i.e. after you've created and deleted the
|
||||
object, getInstance() will refuse to create another one. This can be useful to stop
|
||||
objects being accidentally re-created during your app's shutdown code.
|
||||
|
||||
If you know that your object will only be created and deleted by a single thread, you
|
||||
can use the slightly more efficient beast_DeclareSingleton_SingleThreaded() macro instead
|
||||
of this one.
|
||||
|
||||
@see beast_ImplementSingleton, beast_DeclareSingleton_SingleThreaded
|
||||
*/
|
||||
#define beast_DeclareSingleton(classname, doNotRecreateAfterDeletion) \
|
||||
\
|
||||
static classname* _singletonInstance; \
|
||||
static beast::CriticalSection _singletonLock; \
|
||||
\
|
||||
static classname* BEAST_CALLTYPE getInstance() \
|
||||
{ \
|
||||
if (_singletonInstance == nullptr) \
|
||||
{\
|
||||
const beast::ScopedLock sl (_singletonLock); \
|
||||
\
|
||||
if (_singletonInstance == nullptr) \
|
||||
{ \
|
||||
static bool alreadyInside = false; \
|
||||
static bool createdOnceAlready = false; \
|
||||
\
|
||||
const bool problem = alreadyInside || ((doNotRecreateAfterDeletion) && createdOnceAlready); \
|
||||
bassert (! problem); \
|
||||
if (! problem) \
|
||||
{ \
|
||||
createdOnceAlready = true; \
|
||||
alreadyInside = true; \
|
||||
classname* newObject = new classname(); /* (use a stack variable to avoid setting the newObject value before the class has finished its constructor) */ \
|
||||
alreadyInside = false; \
|
||||
\
|
||||
_singletonInstance = newObject; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
return _singletonInstance; \
|
||||
} \
|
||||
\
|
||||
static inline classname* BEAST_CALLTYPE getInstanceWithoutCreating() noexcept\
|
||||
{ \
|
||||
return _singletonInstance; \
|
||||
} \
|
||||
\
|
||||
static void BEAST_CALLTYPE deleteInstance() \
|
||||
{ \
|
||||
const beast::ScopedLock sl (_singletonLock); \
|
||||
if (_singletonInstance != nullptr) \
|
||||
{ \
|
||||
classname* const old = _singletonInstance; \
|
||||
_singletonInstance = nullptr; \
|
||||
delete old; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
void clearSingletonInstance() noexcept\
|
||||
{ \
|
||||
if (_singletonInstance == this) \
|
||||
_singletonInstance = nullptr; \
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** This is a counterpart to the beast_DeclareSingleton macro.
|
||||
|
||||
After adding the beast_DeclareSingleton to the class definition, this macro has
|
||||
to be used in the cpp file.
|
||||
*/
|
||||
#define beast_ImplementSingleton(classname) \
|
||||
\
|
||||
classname* classname::_singletonInstance = nullptr; \
|
||||
beast::CriticalSection classname::_singletonLock;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Macro to declare member variables and methods for a singleton class.
|
||||
|
||||
This is exactly the same as beast_DeclareSingleton, but doesn't use a critical
|
||||
section to make access to it thread-safe. If you know that your object will
|
||||
only ever be created or deleted by a single thread, then this is a
|
||||
more efficient version to use.
|
||||
|
||||
If doNotRecreateAfterDeletion = true, it won't allow the object to be created more
|
||||
than once during the process's lifetime - i.e. after you've created and deleted the
|
||||
object, getInstance() will refuse to create another one. This can be useful to stop
|
||||
objects being accidentally re-created during your app's shutdown code.
|
||||
|
||||
See the documentation for beast_DeclareSingleton for more information about
|
||||
how to use it, the only difference being that you have to use
|
||||
beast_ImplementSingleton_SingleThreaded instead of beast_ImplementSingleton.
|
||||
|
||||
@see beast_ImplementSingleton_SingleThreaded, beast_DeclareSingleton, beast_DeclareSingleton_SingleThreaded_Minimal
|
||||
*/
|
||||
#define beast_DeclareSingleton_SingleThreaded(classname, doNotRecreateAfterDeletion) \
|
||||
\
|
||||
static classname* _singletonInstance; \
|
||||
\
|
||||
static classname* getInstance() \
|
||||
{ \
|
||||
if (_singletonInstance == nullptr) \
|
||||
{ \
|
||||
static bool alreadyInside = false; \
|
||||
static bool createdOnceAlready = false; \
|
||||
\
|
||||
const bool problem = alreadyInside || ((doNotRecreateAfterDeletion) && createdOnceAlready); \
|
||||
bassert (! problem); \
|
||||
if (! problem) \
|
||||
{ \
|
||||
createdOnceAlready = true; \
|
||||
alreadyInside = true; \
|
||||
classname* newObject = new classname(); /* (use a stack variable to avoid setting the newObject value before the class has finished its constructor) */ \
|
||||
alreadyInside = false; \
|
||||
\
|
||||
_singletonInstance = newObject; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
return _singletonInstance; \
|
||||
} \
|
||||
\
|
||||
static inline classname* getInstanceWithoutCreating() noexcept\
|
||||
{ \
|
||||
return _singletonInstance; \
|
||||
} \
|
||||
\
|
||||
static void deleteInstance() \
|
||||
{ \
|
||||
if (_singletonInstance != nullptr) \
|
||||
{ \
|
||||
classname* const old = _singletonInstance; \
|
||||
_singletonInstance = nullptr; \
|
||||
delete old; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
void clearSingletonInstance() noexcept\
|
||||
{ \
|
||||
if (_singletonInstance == this) \
|
||||
_singletonInstance = nullptr; \
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Macro to declare member variables and methods for a singleton class.
|
||||
|
||||
This is like beast_DeclareSingleton_SingleThreaded, but doesn't do any checking
|
||||
for recursion or repeated instantiation. It's intended for use as a lightweight
|
||||
version of a singleton, where you're using it in very straightforward
|
||||
circumstances and don't need the extra checking.
|
||||
|
||||
Beast use the normal beast_ImplementSingleton_SingleThreaded as the counterpart
|
||||
to this declaration, as you would with beast_DeclareSingleton_SingleThreaded.
|
||||
|
||||
See the documentation for beast_DeclareSingleton for more information about
|
||||
how to use it, the only difference being that you have to use
|
||||
beast_ImplementSingleton_SingleThreaded instead of beast_ImplementSingleton.
|
||||
|
||||
@see beast_ImplementSingleton_SingleThreaded, beast_DeclareSingleton
|
||||
*/
|
||||
#define beast_DeclareSingleton_SingleThreaded_Minimal(classname) \
|
||||
\
|
||||
static classname* _singletonInstance; \
|
||||
\
|
||||
static classname* getInstance() \
|
||||
{ \
|
||||
if (_singletonInstance == nullptr) \
|
||||
_singletonInstance = new classname(); \
|
||||
\
|
||||
return _singletonInstance; \
|
||||
} \
|
||||
\
|
||||
static inline classname* getInstanceWithoutCreating() noexcept\
|
||||
{ \
|
||||
return _singletonInstance; \
|
||||
} \
|
||||
\
|
||||
static void deleteInstance() \
|
||||
{ \
|
||||
if (_singletonInstance != nullptr) \
|
||||
{ \
|
||||
classname* const old = _singletonInstance; \
|
||||
_singletonInstance = nullptr; \
|
||||
delete old; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
void clearSingletonInstance() noexcept\
|
||||
{ \
|
||||
if (_singletonInstance == this) \
|
||||
_singletonInstance = nullptr; \
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** This is a counterpart to the beast_DeclareSingleton_SingleThreaded macro.
|
||||
|
||||
After adding beast_DeclareSingleton_SingleThreaded or beast_DeclareSingleton_SingleThreaded_Minimal
|
||||
to the class definition, this macro has to be used somewhere in the cpp file.
|
||||
*/
|
||||
#define beast_ImplementSingleton_SingleThreaded(classname) \
|
||||
\
|
||||
classname* classname::_singletonInstance = nullptr;
|
||||
|
||||
|
||||
|
||||
#endif // BEAST_SINGLETON_BEASTHEADER
|
||||
209
modules/beast_core/memory/beast_WeakReference.h
Normal file
209
modules/beast_core/memory/beast_WeakReference.h
Normal file
@@ -0,0 +1,209 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_WEAKREFERENCE_BEASTHEADER
|
||||
#define BEAST_WEAKREFERENCE_BEASTHEADER
|
||||
|
||||
#include "beast_ReferenceCountedObject.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
This class acts as a pointer which will automatically become null if the object
|
||||
to which it points is deleted.
|
||||
|
||||
To accomplish this, the source object needs to cooperate by performing a couple of simple tasks.
|
||||
It must embed a WeakReference::Master object, which stores a shared pointer object, and must clear
|
||||
this master pointer in its destructor.
|
||||
|
||||
E.g.
|
||||
@code
|
||||
class MyObject
|
||||
{
|
||||
public:
|
||||
MyObject()
|
||||
{
|
||||
// If you're planning on using your WeakReferences in a multi-threaded situation, you may choose
|
||||
// to create a WeakReference to the object here in the constructor, which will pre-initialise the
|
||||
// embedded object, avoiding an (extremely unlikely) race condition that could occur if multiple
|
||||
// threads overlap while creating the first WeakReference to it.
|
||||
}
|
||||
|
||||
~MyObject()
|
||||
{
|
||||
// This will zero all the references - you need to call this in your destructor.
|
||||
masterReference.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
// You need to embed a variable of this type, with the name "masterReference" inside your object. If the
|
||||
// variable is not public, you should make your class a friend of WeakReference<MyObject> so that the
|
||||
// WeakReference class can access it.
|
||||
WeakReference<MyObject>::Master masterReference;
|
||||
friend class WeakReference<MyObject>;
|
||||
};
|
||||
|
||||
// Here's an example of using a pointer..
|
||||
|
||||
MyObject* n = new MyObject();
|
||||
WeakReference<MyObject> myObjectRef = n;
|
||||
|
||||
MyObject* pointer1 = myObjectRef; // returns a valid pointer to 'n'
|
||||
delete n;
|
||||
MyObject* pointer2 = myObjectRef; // returns a null pointer
|
||||
@endcode
|
||||
|
||||
@see WeakReference::Master
|
||||
*/
|
||||
template <class ObjectType, class ReferenceCountingType = ReferenceCountedObject>
|
||||
class WeakReference
|
||||
{
|
||||
public:
|
||||
/** Creates a null SafePointer. */
|
||||
inline WeakReference() noexcept {}
|
||||
|
||||
/** Creates a WeakReference that points at the given object. */
|
||||
WeakReference (ObjectType* const object) : holder (getRef (object)) {}
|
||||
|
||||
/** Creates a copy of another WeakReference. */
|
||||
WeakReference (const WeakReference& other) noexcept : holder (other.holder) {}
|
||||
|
||||
/** Copies another pointer to this one. */
|
||||
WeakReference& operator= (const WeakReference& other) { holder = other.holder; return *this; }
|
||||
|
||||
/** Copies another pointer to this one. */
|
||||
WeakReference& operator= (ObjectType* const newObject) { holder = getRef (newObject); return *this; }
|
||||
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
WeakReference (WeakReference&& other) noexcept : holder (static_cast <SharedRef&&> (other.holder)) {}
|
||||
WeakReference& operator= (WeakReference&& other) noexcept { holder = static_cast <SharedRef&&> (other.holder); return *this; }
|
||||
#endif
|
||||
|
||||
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
|
||||
ObjectType* get() const noexcept { return holder != nullptr ? holder->get() : nullptr; }
|
||||
|
||||
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
|
||||
operator ObjectType*() const noexcept { return get(); }
|
||||
|
||||
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
|
||||
ObjectType* operator->() noexcept { return get(); }
|
||||
|
||||
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
|
||||
const ObjectType* operator->() const noexcept { return get(); }
|
||||
|
||||
/** This returns true if this reference has been pointing at an object, but that object has
|
||||
since been deleted.
|
||||
|
||||
If this reference was only ever pointing at a null pointer, this will return false. Using
|
||||
operator=() to make this refer to a different object will reset this flag to match the status
|
||||
of the reference from which you're copying.
|
||||
*/
|
||||
bool wasObjectDeleted() const noexcept { return holder != nullptr && holder->get() == nullptr; }
|
||||
|
||||
bool operator== (ObjectType* const object) const noexcept { return get() == object; }
|
||||
bool operator!= (ObjectType* const object) const noexcept { return get() != object; }
|
||||
|
||||
//==============================================================================
|
||||
/** This class is used internally by the WeakReference class - don't use it directly
|
||||
in your code!
|
||||
@see WeakReference
|
||||
*/
|
||||
class SharedPointer : public ReferenceCountingType
|
||||
{
|
||||
public:
|
||||
explicit SharedPointer (ObjectType* const obj) noexcept : owner (obj) {}
|
||||
|
||||
inline ObjectType* get() const noexcept { return owner; }
|
||||
void clearPointer() noexcept { owner = nullptr; }
|
||||
|
||||
private:
|
||||
ObjectType* volatile owner;
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE (SharedPointer)
|
||||
};
|
||||
|
||||
typedef ReferenceCountedObjectPtr<SharedPointer> SharedRef;
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
This class is embedded inside an object to which you want to attach WeakReference pointers.
|
||||
See the WeakReference class notes for an example of how to use this class.
|
||||
@see WeakReference
|
||||
*/
|
||||
class Master
|
||||
{
|
||||
public:
|
||||
Master() noexcept {}
|
||||
|
||||
~Master()
|
||||
{
|
||||
// You must remember to call clear() in your source object's destructor! See the notes
|
||||
// for the WeakReference class for an example of how to do this.
|
||||
bassert (sharedPointer == nullptr || sharedPointer->get() == nullptr);
|
||||
}
|
||||
|
||||
/** The first call to this method will create an internal object that is shared by all weak
|
||||
references to the object.
|
||||
*/
|
||||
SharedPointer* getSharedPointer (ObjectType* const object)
|
||||
{
|
||||
if (sharedPointer == nullptr)
|
||||
{
|
||||
sharedPointer = new SharedPointer (object);
|
||||
}
|
||||
else
|
||||
{
|
||||
// You're trying to create a weak reference to an object that has already been deleted!!
|
||||
bassert (sharedPointer->get() != nullptr);
|
||||
}
|
||||
|
||||
return sharedPointer;
|
||||
}
|
||||
|
||||
/** The object that owns this master pointer should call this before it gets destroyed,
|
||||
to zero all the references to this object that may be out there. See the WeakReference
|
||||
class notes for an example of how to do this.
|
||||
*/
|
||||
void clear()
|
||||
{
|
||||
if (sharedPointer != nullptr)
|
||||
sharedPointer->clearPointer();
|
||||
}
|
||||
|
||||
private:
|
||||
SharedRef sharedPointer;
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE (Master)
|
||||
};
|
||||
|
||||
private:
|
||||
SharedRef holder;
|
||||
|
||||
static inline SharedPointer* getRef (ObjectType* const o)
|
||||
{
|
||||
return (o != nullptr) ? o->masterReference.getSharedPointer (o) : nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif // BEAST_WEAKREFERENCE_BEASTHEADER
|
||||
81
modules/beast_core/misc/beast_Result.cpp
Normal file
81
modules/beast_core/misc/beast_Result.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
Result::Result (const String& message) noexcept
|
||||
: errorMessage (message)
|
||||
{
|
||||
}
|
||||
|
||||
Result::Result (const Result& other)
|
||||
: errorMessage (other.errorMessage)
|
||||
{
|
||||
}
|
||||
|
||||
Result& Result::operator= (const Result& other)
|
||||
{
|
||||
errorMessage = other.errorMessage;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
Result::Result (Result&& other) noexcept
|
||||
: errorMessage (static_cast <String&&> (other.errorMessage))
|
||||
{
|
||||
}
|
||||
|
||||
Result& Result::operator= (Result&& other) noexcept
|
||||
{
|
||||
errorMessage = static_cast <String&&> (other.errorMessage);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool Result::operator== (const Result& other) const noexcept
|
||||
{
|
||||
return errorMessage == other.errorMessage;
|
||||
}
|
||||
|
||||
bool Result::operator!= (const Result& other) const noexcept
|
||||
{
|
||||
return errorMessage != other.errorMessage;
|
||||
}
|
||||
|
||||
Result Result::ok() noexcept
|
||||
{
|
||||
return Result (String::empty);
|
||||
}
|
||||
|
||||
Result Result::fail (const String& errorMessage) noexcept
|
||||
{
|
||||
return Result (errorMessage.isEmpty() ? "Unknown Error" : errorMessage);
|
||||
}
|
||||
|
||||
const String& Result::getErrorMessage() const noexcept
|
||||
{
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
bool Result::wasOk() const noexcept { return errorMessage.isEmpty(); }
|
||||
Result::operator bool() const noexcept { return errorMessage.isEmpty(); }
|
||||
bool Result::failed() const noexcept { return errorMessage.isNotEmpty(); }
|
||||
bool Result::operator!() const noexcept { return errorMessage.isNotEmpty(); }
|
||||
119
modules/beast_core/misc/beast_Result.h
Normal file
119
modules/beast_core/misc/beast_Result.h
Normal file
@@ -0,0 +1,119 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_RESULT_BEASTHEADER
|
||||
#define BEAST_RESULT_BEASTHEADER
|
||||
|
||||
#include "../text/beast_String.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Represents the 'success' or 'failure' of an operation, and holds an associated
|
||||
error message to describe the error when there's a failure.
|
||||
|
||||
E.g.
|
||||
@code
|
||||
Result myOperation()
|
||||
{
|
||||
if (doSomeKindOfFoobar())
|
||||
return Result::ok();
|
||||
else
|
||||
return Result::fail ("foobar didn't work!");
|
||||
}
|
||||
|
||||
const Result result (myOperation());
|
||||
|
||||
if (result.wasOk())
|
||||
{
|
||||
...it's all good...
|
||||
}
|
||||
else
|
||||
{
|
||||
warnUserAboutFailure ("The foobar operation failed! Error message was: "
|
||||
+ result.getErrorMessage());
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
class BEAST_API Result
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates and returns a 'successful' result. */
|
||||
static Result ok() noexcept;
|
||||
|
||||
/** Creates a 'failure' result.
|
||||
If you pass a blank error message in here, a default "Unknown Error" message
|
||||
will be used instead.
|
||||
*/
|
||||
static Result fail (const String& errorMessage) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if this result indicates a success. */
|
||||
bool wasOk() const noexcept;
|
||||
|
||||
/** Returns true if this result indicates a failure.
|
||||
You can use getErrorMessage() to retrieve the error message associated
|
||||
with the failure.
|
||||
*/
|
||||
bool failed() const noexcept;
|
||||
|
||||
/** Returns true if this result indicates a success.
|
||||
This is equivalent to calling wasOk().
|
||||
*/
|
||||
operator bool() const noexcept;
|
||||
|
||||
/** Returns true if this result indicates a failure.
|
||||
This is equivalent to calling failed().
|
||||
*/
|
||||
bool operator!() const noexcept;
|
||||
|
||||
/** Returns the error message that was set when this result was created.
|
||||
For a successful result, this will be an empty string;
|
||||
*/
|
||||
const String& getErrorMessage() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
Result (const Result& other);
|
||||
Result& operator= (const Result& other);
|
||||
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
Result (Result&& other) noexcept;
|
||||
Result& operator= (Result&& other) noexcept;
|
||||
#endif
|
||||
|
||||
bool operator== (const Result& other) const noexcept;
|
||||
bool operator!= (const Result& other) const noexcept;
|
||||
|
||||
private:
|
||||
String errorMessage;
|
||||
|
||||
explicit Result (const String&) noexcept;
|
||||
|
||||
// These casts are private to prevent people trying to use the Result object in numeric contexts
|
||||
operator int() const;
|
||||
operator void*() const;
|
||||
};
|
||||
|
||||
|
||||
#endif // BEAST_RESULT_BEASTHEADER
|
||||
109
modules/beast_core/misc/beast_Uuid.cpp
Normal file
109
modules/beast_core/misc/beast_Uuid.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
namespace
|
||||
{
|
||||
int64 getRandomSeedFromMACAddresses()
|
||||
{
|
||||
Array<MACAddress> result;
|
||||
MACAddress::findAllAddresses (result);
|
||||
|
||||
Random r;
|
||||
for (int i = 0; i < result.size(); ++i)
|
||||
r.combineSeed (result[i].toInt64());
|
||||
|
||||
return r.nextInt64();
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Uuid::Uuid()
|
||||
{
|
||||
// The normal random seeding is pretty good, but we'll throw some MAC addresses
|
||||
// into the mix too, to make it very very unlikely that two UUIDs will ever be the same..
|
||||
|
||||
static Random r1 (getRandomSeedFromMACAddresses());
|
||||
Random r2;
|
||||
|
||||
for (size_t i = 0; i < sizeof (uuid); ++i)
|
||||
uuid[i] = (uint8) (r1.nextInt() ^ r2.nextInt());
|
||||
}
|
||||
|
||||
Uuid::~Uuid() noexcept {}
|
||||
|
||||
Uuid::Uuid (const Uuid& other) noexcept
|
||||
{
|
||||
memcpy (uuid, other.uuid, sizeof (uuid));
|
||||
}
|
||||
|
||||
Uuid& Uuid::operator= (const Uuid& other) noexcept
|
||||
{
|
||||
memcpy (uuid, other.uuid, sizeof (uuid));
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Uuid::operator== (const Uuid& other) const noexcept { return memcmp (uuid, other.uuid, sizeof (uuid)) == 0; }
|
||||
bool Uuid::operator!= (const Uuid& other) const noexcept { return ! operator== (other); }
|
||||
|
||||
bool Uuid::isNull() const noexcept
|
||||
{
|
||||
for (size_t i = 0; i < sizeof (uuid); ++i)
|
||||
if (uuid[i] != 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
String Uuid::toString() const
|
||||
{
|
||||
return String::toHexString (uuid, sizeof (uuid), 0);
|
||||
}
|
||||
|
||||
Uuid::Uuid (const String& uuidString)
|
||||
{
|
||||
operator= (uuidString);
|
||||
}
|
||||
|
||||
Uuid& Uuid::operator= (const String& uuidString)
|
||||
{
|
||||
MemoryBlock mb;
|
||||
mb.loadFromHexString (uuidString);
|
||||
mb.ensureSize (sizeof (uuid), true);
|
||||
mb.copyTo (uuid, 0, sizeof (uuid));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Uuid::Uuid (const uint8* const rawData)
|
||||
{
|
||||
operator= (rawData);
|
||||
}
|
||||
|
||||
Uuid& Uuid::operator= (const uint8* const rawData) noexcept
|
||||
{
|
||||
if (rawData != nullptr)
|
||||
memcpy (uuid, rawData, sizeof (uuid));
|
||||
else
|
||||
zeromem (uuid, sizeof (uuid));
|
||||
|
||||
return *this;
|
||||
}
|
||||
109
modules/beast_core/misc/beast_Uuid.h
Normal file
109
modules/beast_core/misc/beast_Uuid.h
Normal file
@@ -0,0 +1,109 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_UUID_BEASTHEADER
|
||||
#define BEAST_UUID_BEASTHEADER
|
||||
|
||||
#include "../text/beast_String.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A universally unique 128-bit identifier.
|
||||
|
||||
This class generates very random unique numbers based on the system time
|
||||
and MAC addresses if any are available. It's extremely unlikely that two identical
|
||||
UUIDs would ever be created by chance.
|
||||
|
||||
The class includes methods for saving the ID as a string or as raw binary data.
|
||||
*/
|
||||
class BEAST_API Uuid
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a new unique ID. */
|
||||
Uuid();
|
||||
|
||||
/** Destructor. */
|
||||
~Uuid() noexcept;
|
||||
|
||||
/** Creates a copy of another UUID. */
|
||||
Uuid (const Uuid& other) noexcept;
|
||||
|
||||
/** Copies another UUID. */
|
||||
Uuid& operator= (const Uuid& other) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if the ID is zero. */
|
||||
bool isNull() const noexcept;
|
||||
|
||||
bool operator== (const Uuid& other) const noexcept;
|
||||
bool operator!= (const Uuid& other) const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a stringified version of this UUID.
|
||||
|
||||
A Uuid object can later be reconstructed from this string using operator= or
|
||||
the constructor that takes a string parameter.
|
||||
|
||||
@returns a 32 character hex string.
|
||||
*/
|
||||
String toString() const;
|
||||
|
||||
/** Creates an ID from an encoded string version.
|
||||
@see toString
|
||||
*/
|
||||
Uuid (const String& uuidString);
|
||||
|
||||
/** Copies from a stringified UUID.
|
||||
The string passed in should be one that was created with the toString() method.
|
||||
*/
|
||||
Uuid& operator= (const String& uuidString);
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a pointer to the internal binary representation of the ID.
|
||||
|
||||
This is an array of 16 bytes. To reconstruct a Uuid from its data, use
|
||||
the constructor or operator= method that takes an array of uint8s.
|
||||
*/
|
||||
const uint8* getRawData() const noexcept { return uuid; }
|
||||
|
||||
/** Creates a UUID from a 16-byte array.
|
||||
@see getRawData
|
||||
*/
|
||||
Uuid (const uint8* rawData);
|
||||
|
||||
/** Sets this UUID from 16-bytes of raw data. */
|
||||
Uuid& operator= (const uint8* rawData) noexcept;
|
||||
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
uint8 uuid[16];
|
||||
|
||||
BEAST_LEAK_DETECTOR (Uuid)
|
||||
};
|
||||
|
||||
|
||||
#endif // BEAST_UUID_BEASTHEADER
|
||||
119
modules/beast_core/misc/beast_WindowsRegistry.h
Normal file
119
modules/beast_core/misc/beast_WindowsRegistry.h
Normal file
@@ -0,0 +1,119 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_WINDOWSREGISTRY_BEASTHEADER
|
||||
#define BEAST_WINDOWSREGISTRY_BEASTHEADER
|
||||
|
||||
#if BEAST_WINDOWS || DOXYGEN
|
||||
|
||||
/**
|
||||
Contains some static helper functions for manipulating the MS Windows registry
|
||||
(Only available on Windows, of course!)
|
||||
*/
|
||||
class WindowsRegistry
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Returns a string from the registry.
|
||||
The path is a string for the entire path of a value in the registry,
|
||||
e.g. "HKEY_CURRENT_USER\Software\foo\bar"
|
||||
*/
|
||||
static String getValue (const String& regValuePath,
|
||||
const String& defaultValue = String::empty);
|
||||
|
||||
/** Returns a string from the WOW64 registry.
|
||||
The path is a string for the entire path of a value in the registry,
|
||||
e.g. "HKEY_CURRENT_USER\Software\foo\bar"
|
||||
*/
|
||||
static String getValueWow64 (const String& regValuePath,
|
||||
const String& defaultValue = String::empty);
|
||||
|
||||
/** Reads a binary block from the registry.
|
||||
The path is a string for the entire path of a value in the registry,
|
||||
e.g. "HKEY_CURRENT_USER\Software\foo\bar"
|
||||
@returns a DWORD indicating the type of the key.
|
||||
*/
|
||||
static uint32 getBinaryValue (const String& regValuePath, MemoryBlock& resultData);
|
||||
|
||||
/** Sets a registry value as a string.
|
||||
This will take care of creating any groups needed to get to the given registry value.
|
||||
*/
|
||||
static bool setValue (const String& regValuePath, const String& value);
|
||||
|
||||
/** Sets a registry value as a DWORD.
|
||||
This will take care of creating any groups needed to get to the given registry value.
|
||||
*/
|
||||
static bool setValue (const String& regValuePath, uint32 value);
|
||||
|
||||
/** Sets a registry value as a QWORD.
|
||||
This will take care of creating any groups needed to get to the given registry value.
|
||||
*/
|
||||
static bool setValue (const String& regValuePath, uint64 value);
|
||||
|
||||
/** Sets a registry value as a binary block.
|
||||
This will take care of creating any groups needed to get to the given registry value.
|
||||
*/
|
||||
static bool setValue (const String& regValuePath, const MemoryBlock& value);
|
||||
|
||||
/** Returns true if the given value exists in the registry. */
|
||||
static bool valueExists (const String& regValuePath);
|
||||
|
||||
/** Returns true if the given value exists in the registry. */
|
||||
static bool valueExistsWow64 (const String& regValuePath);
|
||||
|
||||
/** Deletes a registry value. */
|
||||
static void deleteValue (const String& regValuePath);
|
||||
|
||||
/** Deletes a registry key (which is registry-talk for 'folder'). */
|
||||
static void deleteKey (const String& regKeyPath);
|
||||
|
||||
/** Creates a file association in the registry.
|
||||
|
||||
This lets you set the executable that should be launched by a given file extension.
|
||||
@param fileExtension the file extension to associate, including the
|
||||
initial dot, e.g. ".txt"
|
||||
@param symbolicDescription a space-free short token to identify the file type
|
||||
@param fullDescription a human-readable description of the file type
|
||||
@param targetExecutable the executable that should be launched
|
||||
@param iconResourceNumber the icon that gets displayed for the file type will be
|
||||
found by looking up this resource number in the
|
||||
executable. Pass 0 here to not use an icon
|
||||
@param registerForCurrentUserOnly if false, this will try to register the association
|
||||
for all users (you might not have permission to do this
|
||||
unless running in an installer). If true, it will register the
|
||||
association in HKEY_CURRENT_USER.
|
||||
*/
|
||||
static bool registerFileAssociation (const String& fileExtension,
|
||||
const String& symbolicDescription,
|
||||
const String& fullDescription,
|
||||
const File& targetExecutable,
|
||||
int iconResourceNumber,
|
||||
bool registerForCurrentUserOnly);
|
||||
|
||||
private:
|
||||
WindowsRegistry();
|
||||
BEAST_DECLARE_NON_COPYABLE (WindowsRegistry)
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // BEAST_WINDOWSREGISTRY_BEASTHEADER
|
||||
220
modules/beast_core/native/beast_BasicNativeHeaders.h
Normal file
220
modules/beast_core/native/beast_BasicNativeHeaders.h
Normal file
@@ -0,0 +1,220 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_BASICNATIVEHEADERS_BEASTHEADER
|
||||
#define BEAST_BASICNATIVEHEADERS_BEASTHEADER
|
||||
|
||||
#include "../system/beast_TargetPlatform.h"
|
||||
#undef T
|
||||
|
||||
//==============================================================================
|
||||
#if BEAST_MAC || BEAST_IOS
|
||||
|
||||
#if BEAST_IOS
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <CoreData/CoreData.h>
|
||||
#import <MobileCoreServices/MobileCoreServices.h>
|
||||
#include <sys/fcntl.h>
|
||||
#else
|
||||
#define Point CarbonDummyPointName
|
||||
#define Component CarbonDummyCompName
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <CoreAudio/HostTime.h>
|
||||
#undef Point
|
||||
#undef Component
|
||||
#include <sys/dir.h>
|
||||
#endif
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/stat.h>
|
||||
#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>
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <mach/mach_time.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <objc/runtime.h>
|
||||
#include <objc/objc.h>
|
||||
#include <objc/message.h>
|
||||
|
||||
//==============================================================================
|
||||
#elif BEAST_WINDOWS
|
||||
#if BEAST_MSVC
|
||||
#ifndef _CPPRTTI
|
||||
#error "You're compiling without RTTI enabled! This is needed for a lot of BEAST classes, please update your compiler settings!"
|
||||
#endif
|
||||
|
||||
#ifndef _CPPUNWIND
|
||||
#error "You're compiling without exceptions enabled! This is needed for a lot of BEAST classes, please update your compiler settings!"
|
||||
#endif
|
||||
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable : 4100 4201 4514 4312 4995)
|
||||
#endif
|
||||
|
||||
#define STRICT 1
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#ifndef _WIN32_WINNT
|
||||
#if BEAST_MINGW
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#else
|
||||
#define _WIN32_WINNT 0x0600
|
||||
#endif
|
||||
#endif
|
||||
#define _UNICODE 1
|
||||
#define UNICODE 1
|
||||
#ifndef _WIN32_IE
|
||||
#define _WIN32_IE 0x0400
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
#include <tchar.h>
|
||||
#include <stddef.h>
|
||||
#include <ctime>
|
||||
#include <wininet.h>
|
||||
#include <nb30.h>
|
||||
#include <iphlpapi.h>
|
||||
#include <mapi.h>
|
||||
#include <float.h>
|
||||
#include <process.h>
|
||||
#include <shlobj.h>
|
||||
#include <shlwapi.h>
|
||||
#include <mmsystem.h>
|
||||
|
||||
#if BEAST_MINGW
|
||||
#include <basetyps.h>
|
||||
#else
|
||||
#include <crtdbg.h>
|
||||
#include <comutil.h>
|
||||
#endif
|
||||
|
||||
#undef PACKED
|
||||
|
||||
#if BEAST_MSVC
|
||||
#pragma warning (pop)
|
||||
#pragma warning (4: 4511 4512 4100 /*4365*/) // (enable some warnings that are turned off in VC8)
|
||||
#endif
|
||||
|
||||
#if BEAST_MSVC && ! BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||
#pragma comment (lib, "kernel32.lib")
|
||||
#pragma comment (lib, "user32.lib")
|
||||
#pragma comment (lib, "wininet.lib")
|
||||
#pragma comment (lib, "advapi32.lib")
|
||||
#pragma comment (lib, "ws2_32.lib")
|
||||
#pragma comment (lib, "version.lib")
|
||||
#pragma comment (lib, "shlwapi.lib")
|
||||
#pragma comment (lib, "winmm.lib")
|
||||
|
||||
#ifdef _NATIVE_WCHAR_T_DEFINED
|
||||
#ifdef _DEBUG
|
||||
#pragma comment (lib, "comsuppwd.lib")
|
||||
#else
|
||||
#pragma comment (lib, "comsuppw.lib")
|
||||
#endif
|
||||
#else
|
||||
#ifdef _DEBUG
|
||||
#pragma comment (lib, "comsuppd.lib")
|
||||
#else
|
||||
#pragma comment (lib, "comsupp.lib")
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Used with DynamicLibrary to simplify importing functions from a win32 DLL.
|
||||
|
||||
dll: the DynamicLibrary object
|
||||
functionName: function to import
|
||||
localFunctionName: name you want to use to actually call it (must be different)
|
||||
returnType: the return type
|
||||
params: list of params (bracketed)
|
||||
*/
|
||||
#define BEAST_LOAD_WINAPI_FUNCTION(dll, functionName, localFunctionName, returnType, params) \
|
||||
typedef returnType (WINAPI *type##localFunctionName) params; \
|
||||
type##localFunctionName localFunctionName = (type##localFunctionName) dll.getFunction (#functionName);
|
||||
|
||||
//==============================================================================
|
||||
#elif BEAST_LINUX
|
||||
#include <sched.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/time.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/dir.h>
|
||||
#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>
|
||||
#include <fcntl.h>
|
||||
#include <dlfcn.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <signal.h>
|
||||
#include <stddef.h>
|
||||
|
||||
//==============================================================================
|
||||
#elif BEAST_ANDROID
|
||||
#include <jni.h>
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#include <sys/time.h>
|
||||
#include <utime.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <dlfcn.h>
|
||||
#include <sys/stat.h>
|
||||
#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>
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
// Need to clear various moronic redefinitions made by system headers..
|
||||
#undef max
|
||||
#undef min
|
||||
#undef direct
|
||||
#undef check
|
||||
|
||||
#endif // BEAST_BASICNATIVEHEADERS_BEASTHEADER
|
||||
236
modules/beast_core/native/beast_android_Files.cpp
Normal file
236
modules/beast_core/native/beast_android_Files.cpp
Normal file
@@ -0,0 +1,236 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
bool File::copyInternal (const File& dest) const
|
||||
{
|
||||
FileInputStream in (*this);
|
||||
|
||||
if (dest.deleteFile())
|
||||
{
|
||||
{
|
||||
FileOutputStream out (dest);
|
||||
|
||||
if (out.failedToOpen())
|
||||
return false;
|
||||
|
||||
if (out.writeFromInputStream (in, -1) == getSize())
|
||||
return true;
|
||||
}
|
||||
|
||||
dest.deleteFile();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void File::findFileSystemRoots (Array<File>& destArray)
|
||||
{
|
||||
destArray.add (File ("/"));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool File::isOnCDRomDrive() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool File::isOnHardDisk() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool File::isOnRemovableDrive() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool File::isHidden() const
|
||||
{
|
||||
return getFileName().startsWithChar ('.');
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
namespace
|
||||
{
|
||||
File beast_readlink (const String& file, const File& defaultFile)
|
||||
{
|
||||
const int size = 8192;
|
||||
HeapBlock<char> buffer;
|
||||
buffer.malloc (size + 4);
|
||||
|
||||
const size_t numBytes = readlink (file.toUTF8(), buffer, size);
|
||||
|
||||
if (numBytes > 0 && numBytes <= size)
|
||||
return File (file).getSiblingFile (String::fromUTF8 (buffer, (int) numBytes));
|
||||
|
||||
return defaultFile;
|
||||
}
|
||||
}
|
||||
|
||||
File File::getLinkedTarget() const
|
||||
{
|
||||
return beast_readlink (getFullPathName().toUTF8(), *this);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
File File::getSpecialLocation (const SpecialLocationType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case userHomeDirectory:
|
||||
case userDocumentsDirectory:
|
||||
case userMusicDirectory:
|
||||
case userMoviesDirectory:
|
||||
case userPicturesDirectory:
|
||||
case userApplicationDataDirectory:
|
||||
case userDesktopDirectory:
|
||||
return File (android.appDataDir);
|
||||
|
||||
case commonApplicationDataDirectory:
|
||||
return File (android.appDataDir);
|
||||
|
||||
case globalApplicationsDirectory:
|
||||
return File ("/system/app");
|
||||
|
||||
case tempDirectory:
|
||||
//return File (AndroidStatsHelpers::getSystemProperty ("java.io.tmpdir"));
|
||||
return File (android.appDataDir).getChildFile (".temp");
|
||||
|
||||
case invokedExecutableFile:
|
||||
case currentExecutableFile:
|
||||
case currentApplicationFile:
|
||||
case hostApplicationPath:
|
||||
return beast_getExecutableFile();
|
||||
|
||||
default:
|
||||
jassertfalse; // unknown type?
|
||||
break;
|
||||
}
|
||||
|
||||
return File::nonexistent;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String File::getVersion() const
|
||||
{
|
||||
return String::empty;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool File::moveToTrash() const
|
||||
{
|
||||
if (! exists())
|
||||
return true;
|
||||
|
||||
// TODO
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class DirectoryIterator::NativeIterator::Pimpl
|
||||
{
|
||||
public:
|
||||
Pimpl (const File& directory, const String& wildCard_)
|
||||
: parentDir (File::addTrailingSeparator (directory.getFullPathName())),
|
||||
wildCard (wildCard_),
|
||||
dir (opendir (directory.getFullPathName().toUTF8()))
|
||||
{
|
||||
}
|
||||
|
||||
~Pimpl()
|
||||
{
|
||||
if (dir != 0)
|
||||
closedir (dir);
|
||||
}
|
||||
|
||||
bool next (String& filenameFound,
|
||||
bool* const isDir, bool* const isHidden, int64* const fileSize,
|
||||
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||
{
|
||||
if (dir != 0)
|
||||
{
|
||||
const char* wildcardUTF8 = nullptr;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
struct dirent* const de = readdir (dir);
|
||||
|
||||
if (de == nullptr)
|
||||
break;
|
||||
|
||||
if (wildcardUTF8 == nullptr)
|
||||
wildcardUTF8 = wildCard.toUTF8();
|
||||
|
||||
if (fnmatch (wildcardUTF8, de->d_name, FNM_CASEFOLD) == 0)
|
||||
{
|
||||
filenameFound = CharPointer_UTF8 (de->d_name);
|
||||
|
||||
updateStatInfoForFile (parentDir + filenameFound, isDir, fileSize, modTime, creationTime, isReadOnly);
|
||||
|
||||
if (isHidden != 0)
|
||||
*isHidden = filenameFound.startsWithChar ('.');
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
String parentDir, wildCard;
|
||||
DIR* dir;
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE (Pimpl)
|
||||
};
|
||||
|
||||
|
||||
DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildCard)
|
||||
: pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildCard))
|
||||
{
|
||||
}
|
||||
|
||||
DirectoryIterator::NativeIterator::~NativeIterator()
|
||||
{
|
||||
}
|
||||
|
||||
bool DirectoryIterator::NativeIterator::next (String& filenameFound,
|
||||
bool* const isDir, bool* const isHidden, int64* const fileSize,
|
||||
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||
{
|
||||
return pimpl->next (filenameFound, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
bool Process::openDocument (const String& fileName, const String& parameters)
|
||||
{
|
||||
const LocalRef<jstring> t (javaString (fileName));
|
||||
android.activity.callVoidMethod (BeastAppActivity.launchURL, t.get());
|
||||
}
|
||||
|
||||
void File::revealToUser() const
|
||||
{
|
||||
}
|
||||
402
modules/beast_core/native/beast_android_JNIHelpers.h
Normal file
402
modules/beast_core/native/beast_android_JNIHelpers.h
Normal file
@@ -0,0 +1,402 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_ANDROID_JNIHELPERS_BEASTHEADER
|
||||
#define BEAST_ANDROID_JNIHELPERS_BEASTHEADER
|
||||
|
||||
#if ! (defined (BEAST_ANDROID_ACTIVITY_CLASSNAME) && defined (BEAST_ANDROID_ACTIVITY_CLASSPATH))
|
||||
#error "The BEAST_ANDROID_ACTIVITY_CLASSNAME and BEAST_ANDROID_ACTIVITY_CLASSPATH macros must be set!"
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
extern JNIEnv* getEnv() noexcept;
|
||||
|
||||
//==============================================================================
|
||||
class GlobalRef
|
||||
{
|
||||
public:
|
||||
inline GlobalRef() noexcept : obj (0) {}
|
||||
inline explicit GlobalRef (jobject o) : obj (retain (o)) {}
|
||||
inline GlobalRef (const GlobalRef& other) : obj (retain (other.obj)) {}
|
||||
~GlobalRef() { clear(); }
|
||||
|
||||
inline void clear()
|
||||
{
|
||||
if (obj != 0)
|
||||
{
|
||||
getEnv()->DeleteGlobalRef (obj);
|
||||
obj = 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline GlobalRef& operator= (const GlobalRef& other)
|
||||
{
|
||||
jobject newObj = retain (other.obj);
|
||||
clear();
|
||||
obj = newObj;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
inline operator jobject() const noexcept { return obj; }
|
||||
inline jobject get() const noexcept { return obj; }
|
||||
|
||||
//==============================================================================
|
||||
#define DECLARE_CALL_TYPE_METHOD(returnType, typeName) \
|
||||
returnType call##typeName##Method (jmethodID methodID, ... ) const \
|
||||
{ \
|
||||
va_list args; \
|
||||
va_start (args, methodID); \
|
||||
returnType result = getEnv()->Call##typeName##MethodV (obj, methodID, args); \
|
||||
va_end (args); \
|
||||
return result; \
|
||||
}
|
||||
|
||||
DECLARE_CALL_TYPE_METHOD (jobject, Object)
|
||||
DECLARE_CALL_TYPE_METHOD (jboolean, Boolean)
|
||||
DECLARE_CALL_TYPE_METHOD (jbyte, Byte)
|
||||
DECLARE_CALL_TYPE_METHOD (jchar, Char)
|
||||
DECLARE_CALL_TYPE_METHOD (jshort, Short)
|
||||
DECLARE_CALL_TYPE_METHOD (jint, Int)
|
||||
DECLARE_CALL_TYPE_METHOD (jlong, Long)
|
||||
DECLARE_CALL_TYPE_METHOD (jfloat, Float)
|
||||
DECLARE_CALL_TYPE_METHOD (jdouble, Double)
|
||||
#undef DECLARE_CALL_TYPE_METHOD
|
||||
|
||||
void callVoidMethod (jmethodID methodID, ... ) const
|
||||
{
|
||||
va_list args;
|
||||
va_start (args, methodID);
|
||||
getEnv()->CallVoidMethodV (obj, methodID, args);
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
jobject obj;
|
||||
|
||||
static inline jobject retain (jobject obj)
|
||||
{
|
||||
return obj == 0 ? 0 : getEnv()->NewGlobalRef (obj);
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
template <typename JavaType>
|
||||
class LocalRef
|
||||
{
|
||||
public:
|
||||
explicit inline LocalRef (JavaType o) noexcept : obj (o) {}
|
||||
inline LocalRef (const LocalRef& other) noexcept : obj (retain (other.obj)) {}
|
||||
~LocalRef() { clear(); }
|
||||
|
||||
void clear()
|
||||
{
|
||||
if (obj != 0)
|
||||
getEnv()->DeleteLocalRef (obj);
|
||||
}
|
||||
|
||||
LocalRef& operator= (const LocalRef& other)
|
||||
{
|
||||
jobject newObj = retain (other.obj);
|
||||
clear();
|
||||
obj = newObj;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline operator JavaType() const noexcept { return obj; }
|
||||
inline JavaType get() const noexcept { return obj; }
|
||||
|
||||
private:
|
||||
JavaType obj;
|
||||
|
||||
static JavaType retain (JavaType obj)
|
||||
{
|
||||
return obj == 0 ? 0 : (JavaType) getEnv()->NewLocalRef (obj);
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
namespace
|
||||
{
|
||||
String beastString (JNIEnv* env, jstring s)
|
||||
{
|
||||
const char* const utf8 = env->GetStringUTFChars (s, nullptr);
|
||||
CharPointer_UTF8 utf8CP (utf8);
|
||||
const String result (utf8CP);
|
||||
env->ReleaseStringUTFChars (s, utf8);
|
||||
return result;
|
||||
}
|
||||
|
||||
String beastString (jstring s)
|
||||
{
|
||||
return beastString (getEnv(), s);
|
||||
}
|
||||
|
||||
LocalRef<jstring> javaString (const String& s)
|
||||
{
|
||||
return LocalRef<jstring> (getEnv()->NewStringUTF (s.toUTF8()));
|
||||
}
|
||||
|
||||
LocalRef<jstring> javaStringFromChar (const beast_wchar c)
|
||||
{
|
||||
char utf8[8] = { 0 };
|
||||
CharPointer_UTF8 (utf8).write (c);
|
||||
return LocalRef<jstring> (getEnv()->NewStringUTF (utf8));
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class JNIClassBase
|
||||
{
|
||||
public:
|
||||
explicit JNIClassBase (const char* classPath);
|
||||
virtual ~JNIClassBase();
|
||||
|
||||
inline operator jclass() const noexcept { return classRef; }
|
||||
|
||||
static void initialiseAllClasses (JNIEnv*);
|
||||
static void releaseAllClasses (JNIEnv*);
|
||||
|
||||
protected:
|
||||
virtual void initialiseFields (JNIEnv*) = 0;
|
||||
|
||||
jmethodID resolveMethod (JNIEnv*, const char* methodName, const char* params);
|
||||
jmethodID resolveStaticMethod (JNIEnv*, const char* methodName, const char* params);
|
||||
jfieldID resolveField (JNIEnv*, const char* fieldName, const char* signature);
|
||||
jfieldID resolveStaticField (JNIEnv*, const char* fieldName, const char* signature);
|
||||
|
||||
private:
|
||||
const char* const classPath;
|
||||
jclass classRef;
|
||||
|
||||
static Array<JNIClassBase*>& getClasses();
|
||||
void initialise (JNIEnv*);
|
||||
void release (JNIEnv*);
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE (JNIClassBase)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
#define CREATE_JNI_METHOD(methodID, stringName, params) methodID = resolveMethod (env, stringName, params);
|
||||
#define CREATE_JNI_STATICMETHOD(methodID, stringName, params) methodID = resolveStaticMethod (env, stringName, params);
|
||||
#define CREATE_JNI_FIELD(fieldID, stringName, signature) fieldID = resolveField (env, stringName, signature);
|
||||
#define CREATE_JNI_STATICFIELD(fieldID, stringName, signature) fieldID = resolveStaticField (env, stringName, signature);
|
||||
#define DECLARE_JNI_METHOD(methodID, stringName, params) jmethodID methodID;
|
||||
#define DECLARE_JNI_FIELD(fieldID, stringName, signature) jfieldID fieldID;
|
||||
|
||||
#define DECLARE_JNI_CLASS(CppClassName, javaPath) \
|
||||
class CppClassName ## _Class : public JNIClassBase \
|
||||
{ \
|
||||
public: \
|
||||
CppClassName ## _Class() : JNIClassBase (javaPath) {} \
|
||||
\
|
||||
void initialiseFields (JNIEnv* env) \
|
||||
{ \
|
||||
JNI_CLASS_MEMBERS (CREATE_JNI_METHOD, CREATE_JNI_STATICMETHOD, CREATE_JNI_FIELD, CREATE_JNI_STATICFIELD); \
|
||||
} \
|
||||
\
|
||||
JNI_CLASS_MEMBERS (DECLARE_JNI_METHOD, DECLARE_JNI_METHOD, DECLARE_JNI_FIELD, DECLARE_JNI_FIELD); \
|
||||
}; \
|
||||
static CppClassName ## _Class CppClassName;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
#define BEAST_JNI_CALLBACK(className, methodName, returnType, params) \
|
||||
extern "C" __attribute__ ((visibility("default"))) returnType BEAST_JOIN_MACRO (BEAST_JOIN_MACRO (Java_, className), _ ## methodName) params
|
||||
|
||||
//==============================================================================
|
||||
class AndroidSystem
|
||||
{
|
||||
public:
|
||||
AndroidSystem();
|
||||
|
||||
void initialise (JNIEnv*, jobject activity, jstring appFile, jstring appDataDir);
|
||||
void shutdown (JNIEnv*);
|
||||
|
||||
//==============================================================================
|
||||
GlobalRef activity;
|
||||
String appFile, appDataDir;
|
||||
int screenWidth, screenHeight;
|
||||
};
|
||||
|
||||
extern AndroidSystem android;
|
||||
|
||||
//==============================================================================
|
||||
class ThreadLocalJNIEnvHolder
|
||||
{
|
||||
public:
|
||||
ThreadLocalJNIEnvHolder()
|
||||
: jvm (nullptr)
|
||||
{
|
||||
zeromem (threads, sizeof (threads));
|
||||
zeromem (envs, sizeof (envs));
|
||||
}
|
||||
|
||||
void initialise (JNIEnv* env)
|
||||
{
|
||||
// NB: the DLL can be left loaded by the JVM, so the same static
|
||||
// objects can end up being reused by subsequent runs of the app
|
||||
zeromem (threads, sizeof (threads));
|
||||
zeromem (envs, sizeof (envs));
|
||||
|
||||
env->GetJavaVM (&jvm);
|
||||
addEnv (env);
|
||||
}
|
||||
|
||||
JNIEnv* attach()
|
||||
{
|
||||
JNIEnv* env = nullptr;
|
||||
jvm->AttachCurrentThread (&env, nullptr);
|
||||
|
||||
if (env != nullptr)
|
||||
addEnv (env);
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
void detach()
|
||||
{
|
||||
jvm->DetachCurrentThread();
|
||||
|
||||
const pthread_t thisThread = pthread_self();
|
||||
|
||||
SpinLock::ScopedLockType sl (addRemoveLock);
|
||||
for (int i = 0; i < maxThreads; ++i)
|
||||
if (threads[i] == thisThread)
|
||||
threads[i] = 0;
|
||||
}
|
||||
|
||||
JNIEnv* getOrAttach() noexcept
|
||||
{
|
||||
JNIEnv* env = get();
|
||||
|
||||
if (env == nullptr)
|
||||
env = attach();
|
||||
|
||||
bassert (env != nullptr);
|
||||
return env;
|
||||
}
|
||||
|
||||
JNIEnv* get() const noexcept
|
||||
{
|
||||
const pthread_t thisThread = pthread_self();
|
||||
|
||||
for (int i = 0; i < maxThreads; ++i)
|
||||
if (threads[i] == thisThread)
|
||||
return envs[i];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
enum { maxThreads = 32 };
|
||||
|
||||
private:
|
||||
JavaVM* jvm;
|
||||
pthread_t threads [maxThreads];
|
||||
JNIEnv* envs [maxThreads];
|
||||
SpinLock addRemoveLock;
|
||||
|
||||
void addEnv (JNIEnv* env)
|
||||
{
|
||||
SpinLock::ScopedLockType sl (addRemoveLock);
|
||||
|
||||
if (get() == nullptr)
|
||||
{
|
||||
const pthread_t thisThread = pthread_self();
|
||||
|
||||
for (int i = 0; i < maxThreads; ++i)
|
||||
{
|
||||
if (threads[i] == 0)
|
||||
{
|
||||
envs[i] = env;
|
||||
threads[i] = thisThread;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jassertfalse; // too many threads!
|
||||
}
|
||||
};
|
||||
|
||||
extern ThreadLocalJNIEnvHolder threadLocalJNIEnvHolder;
|
||||
|
||||
//==============================================================================
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||
METHOD (createNewView, "createNewView", "(Z)L" BEAST_ANDROID_ACTIVITY_CLASSPATH "$ComponentPeerView;") \
|
||||
METHOD (deleteView, "deleteView", "(L" BEAST_ANDROID_ACTIVITY_CLASSPATH "$ComponentPeerView;)V") \
|
||||
METHOD (postMessage, "postMessage", "(J)V") \
|
||||
METHOD (finish, "finish", "()V") \
|
||||
METHOD (getClipboardContent, "getClipboardContent", "()Ljava/lang/String;") \
|
||||
METHOD (setClipboardContent, "setClipboardContent", "(Ljava/lang/String;)V") \
|
||||
METHOD (excludeClipRegion, "excludeClipRegion", "(Landroid/graphics/Canvas;FFFF)V") \
|
||||
METHOD (renderGlyph, "renderGlyph", "(CLandroid/graphics/Paint;Landroid/graphics/Matrix;Landroid/graphics/Rect;)[I") \
|
||||
STATICMETHOD (createHTTPStream, "createHTTPStream", "(Ljava/lang/String;Z[BLjava/lang/String;ILjava/lang/StringBuffer;)L" BEAST_ANDROID_ACTIVITY_CLASSPATH "$HTTPStream;") \
|
||||
METHOD (launchURL, "launchURL", "(Ljava/lang/String;)V") \
|
||||
METHOD (showMessageBox, "showMessageBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \
|
||||
METHOD (showOkCancelBox, "showOkCancelBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \
|
||||
METHOD (showYesNoCancelBox, "showYesNoCancelBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \
|
||||
STATICMETHOD (getLocaleValue, "getLocaleValue", "(Z)Ljava/lang/String;") \
|
||||
METHOD (scanFile, "scanFile", "(Ljava/lang/String;)V")
|
||||
|
||||
DECLARE_JNI_CLASS (BeastAppActivity, BEAST_ANDROID_ACTIVITY_CLASSPATH);
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
//==============================================================================
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||
METHOD (constructor, "<init>", "(I)V") \
|
||||
METHOD (setColor, "setColor", "(I)V") \
|
||||
METHOD (setAlpha, "setAlpha", "(I)V") \
|
||||
METHOD (setTypeface, "setTypeface", "(Landroid/graphics/Typeface;)Landroid/graphics/Typeface;") \
|
||||
METHOD (ascent, "ascent", "()F") \
|
||||
METHOD (descent, "descent", "()F") \
|
||||
METHOD (setTextSize, "setTextSize", "(F)V") \
|
||||
METHOD (getTextWidths, "getTextWidths", "(Ljava/lang/String;[F)I") \
|
||||
METHOD (setTextScaleX, "setTextScaleX", "(F)V") \
|
||||
METHOD (getTextPath, "getTextPath", "(Ljava/lang/String;IIFFLandroid/graphics/Path;)V") \
|
||||
METHOD (setShader, "setShader", "(Landroid/graphics/Shader;)Landroid/graphics/Shader;") \
|
||||
|
||||
DECLARE_JNI_CLASS (Paint, "android/graphics/Paint");
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
//==============================================================================
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||
METHOD (constructor, "<init>", "()V") \
|
||||
METHOD (setValues, "setValues", "([F)V") \
|
||||
|
||||
DECLARE_JNI_CLASS (Matrix, "android/graphics/Matrix");
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
//==============================================================================
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||
METHOD (constructor, "<init>", "(IIII)V") \
|
||||
FIELD (left, "left", "I") \
|
||||
FIELD (right, "right", "I") \
|
||||
FIELD (top, "top", "I") \
|
||||
FIELD (bottom, "bottom", "I") \
|
||||
|
||||
DECLARE_JNI_CLASS (RectClass, "android/graphics/Rect");
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
#endif // BEAST_ANDROID_JNIHELPERS_BEASTHEADER
|
||||
27
modules/beast_core/native/beast_android_Misc.cpp
Normal file
27
modules/beast_core/native/beast_android_Misc.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
void Logger::outputDebugString (const String& text)
|
||||
{
|
||||
__android_log_print (ANDROID_LOG_INFO, "BEAST", text.toUTF8());
|
||||
}
|
||||
171
modules/beast_core/native/beast_android_Network.cpp
Normal file
171
modules/beast_core/native/beast_android_Network.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
//==============================================================================
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||
METHOD (constructor, "<init>", "()V") \
|
||||
METHOD (toString, "toString", "()Ljava/lang/String;") \
|
||||
|
||||
DECLARE_JNI_CLASS (StringBuffer, "java/lang/StringBuffer");
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
//==============================================================================
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||
METHOD (release, "release", "()V") \
|
||||
METHOD (read, "read", "([BI)I") \
|
||||
METHOD (getPosition, "getPosition", "()J") \
|
||||
METHOD (getTotalLength, "getTotalLength", "()J") \
|
||||
METHOD (isExhausted, "isExhausted", "()Z") \
|
||||
METHOD (setPosition, "setPosition", "(J)Z") \
|
||||
|
||||
DECLARE_JNI_CLASS (HTTPStream, BEAST_ANDROID_ACTIVITY_CLASSPATH "$HTTPStream");
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
|
||||
//==============================================================================
|
||||
void MACAddress::findAllAddresses (Array<MACAddress>& result)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
bool Process::openEmailWithAttachments (const String& targetEmailAddress,
|
||||
const String& emailSubject,
|
||||
const String& bodyText,
|
||||
const StringArray& filesToAttach)
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class WebInputStream : public InputStream
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
WebInputStream (String address, bool isPost, const MemoryBlock& postData,
|
||||
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
|
||||
const String& headers, int timeOutMs, StringPairArray* responseHeaders)
|
||||
{
|
||||
if (! address.contains ("://"))
|
||||
address = "http://" + address;
|
||||
|
||||
JNIEnv* env = getEnv();
|
||||
|
||||
jbyteArray postDataArray = 0;
|
||||
|
||||
if (postData.getSize() > 0)
|
||||
{
|
||||
postDataArray = env->NewByteArray (postData.getSize());
|
||||
env->SetByteArrayRegion (postDataArray, 0, postData.getSize(), (const jbyte*) postData.getData());
|
||||
}
|
||||
|
||||
LocalRef<jobject> responseHeaderBuffer (env->NewObject (StringBuffer, StringBuffer.constructor));
|
||||
|
||||
stream = GlobalRef (env->CallStaticObjectMethod (BeastAppActivity,
|
||||
BeastAppActivity.createHTTPStream,
|
||||
javaString (address).get(),
|
||||
(jboolean) isPost,
|
||||
postDataArray,
|
||||
javaString (headers).get(),
|
||||
(jint) timeOutMs,
|
||||
responseHeaderBuffer.get()));
|
||||
|
||||
if (postDataArray != 0)
|
||||
env->DeleteLocalRef (postDataArray);
|
||||
|
||||
if (stream != 0)
|
||||
{
|
||||
StringArray headerLines;
|
||||
|
||||
{
|
||||
LocalRef<jstring> headersString ((jstring) env->CallObjectMethod (responseHeaderBuffer.get(),
|
||||
StringBuffer.toString));
|
||||
headerLines.addLines (beastString (env, headersString));
|
||||
}
|
||||
|
||||
if (responseHeaders != 0)
|
||||
{
|
||||
for (int i = 0; i < headerLines.size(); ++i)
|
||||
{
|
||||
const String& header = headerLines[i];
|
||||
const String key (header.upToFirstOccurrenceOf (": ", false, false));
|
||||
const String value (header.fromFirstOccurrenceOf (": ", false, false));
|
||||
const String previousValue ((*responseHeaders) [key]);
|
||||
|
||||
responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~WebInputStream()
|
||||
{
|
||||
if (stream != 0)
|
||||
stream.callVoidMethod (HTTPStream.release);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool isExhausted() { return stream != nullptr && stream.callBooleanMethod (HTTPStream.isExhausted); }
|
||||
int64 getTotalLength() { return stream != nullptr ? stream.callLongMethod (HTTPStream.getTotalLength) : 0; }
|
||||
int64 getPosition() { return stream != nullptr ? stream.callLongMethod (HTTPStream.getPosition) : 0; }
|
||||
bool setPosition (int64 wantedPos) { return stream != nullptr && stream.callBooleanMethod (HTTPStream.setPosition, (jlong) wantedPos); }
|
||||
|
||||
int read (void* buffer, int bytesToRead)
|
||||
{
|
||||
bassert (buffer != nullptr && bytesToRead >= 0);
|
||||
|
||||
if (stream == nullptr)
|
||||
return 0;
|
||||
|
||||
JNIEnv* env = getEnv();
|
||||
|
||||
jbyteArray javaArray = env->NewByteArray (bytesToRead);
|
||||
|
||||
int numBytes = stream.callIntMethod (HTTPStream.read, javaArray, (jint) bytesToRead);
|
||||
|
||||
if (numBytes > 0)
|
||||
env->GetByteArrayRegion (javaArray, 0, numBytes, static_cast <jbyte*> (buffer));
|
||||
|
||||
env->DeleteLocalRef (javaArray);
|
||||
return numBytes;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
GlobalRef stream;
|
||||
|
||||
private:
|
||||
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream)
|
||||
};
|
||||
|
||||
InputStream* URL::createNativeStream (const String& address, bool isPost, const MemoryBlock& postData,
|
||||
OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
|
||||
const String& headers, const int timeOutMs, StringPairArray* responseHeaders)
|
||||
{
|
||||
ScopedPointer <WebInputStream> wi (new WebInputStream (address, isPost, postData,
|
||||
progressCallback, progressCallbackContext,
|
||||
headers, timeOutMs, responseHeaders));
|
||||
|
||||
return wi->stream != 0 ? wi.release() : nullptr;
|
||||
}
|
||||
307
modules/beast_core/native/beast_android_SystemStats.cpp
Normal file
307
modules/beast_core/native/beast_android_SystemStats.cpp
Normal file
@@ -0,0 +1,307 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
JNIClassBase::JNIClassBase (const char* classPath_)
|
||||
: classPath (classPath_), classRef (0)
|
||||
{
|
||||
getClasses().add (this);
|
||||
}
|
||||
|
||||
JNIClassBase::~JNIClassBase()
|
||||
{
|
||||
getClasses().removeFirstMatchingValue (this);
|
||||
}
|
||||
|
||||
Array<JNIClassBase*>& JNIClassBase::getClasses()
|
||||
{
|
||||
static Array<JNIClassBase*> classes;
|
||||
return classes;
|
||||
}
|
||||
|
||||
void JNIClassBase::initialise (JNIEnv* env)
|
||||
{
|
||||
classRef = (jclass) env->NewGlobalRef (env->FindClass (classPath));
|
||||
bassert (classRef != 0);
|
||||
|
||||
initialiseFields (env);
|
||||
}
|
||||
|
||||
void JNIClassBase::release (JNIEnv* env)
|
||||
{
|
||||
env->DeleteGlobalRef (classRef);
|
||||
}
|
||||
|
||||
void JNIClassBase::initialiseAllClasses (JNIEnv* env)
|
||||
{
|
||||
const Array<JNIClassBase*>& classes = getClasses();
|
||||
for (int i = classes.size(); --i >= 0;)
|
||||
classes.getUnchecked(i)->initialise (env);
|
||||
}
|
||||
|
||||
void JNIClassBase::releaseAllClasses (JNIEnv* env)
|
||||
{
|
||||
const Array<JNIClassBase*>& classes = getClasses();
|
||||
for (int i = classes.size(); --i >= 0;)
|
||||
classes.getUnchecked(i)->release (env);
|
||||
}
|
||||
|
||||
jmethodID JNIClassBase::resolveMethod (JNIEnv* env, const char* methodName, const char* params)
|
||||
{
|
||||
jmethodID m = env->GetMethodID (classRef, methodName, params);
|
||||
bassert (m != 0);
|
||||
return m;
|
||||
}
|
||||
|
||||
jmethodID JNIClassBase::resolveStaticMethod (JNIEnv* env, const char* methodName, const char* params)
|
||||
{
|
||||
jmethodID m = env->GetStaticMethodID (classRef, methodName, params);
|
||||
bassert (m != 0);
|
||||
return m;
|
||||
}
|
||||
|
||||
jfieldID JNIClassBase::resolveField (JNIEnv* env, const char* fieldName, const char* signature)
|
||||
{
|
||||
jfieldID f = env->GetFieldID (classRef, fieldName, signature);
|
||||
bassert (f != 0);
|
||||
return f;
|
||||
}
|
||||
|
||||
jfieldID JNIClassBase::resolveStaticField (JNIEnv* env, const char* fieldName, const char* signature)
|
||||
{
|
||||
jfieldID f = env->GetStaticFieldID (classRef, fieldName, signature);
|
||||
bassert (f != 0);
|
||||
return f;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
ThreadLocalJNIEnvHolder threadLocalJNIEnvHolder;
|
||||
|
||||
#if BEAST_DEBUG
|
||||
static bool systemInitialised = false;
|
||||
#endif
|
||||
|
||||
JNIEnv* getEnv() noexcept
|
||||
{
|
||||
#if BEAST_DEBUG
|
||||
if (! systemInitialised)
|
||||
{
|
||||
DBG ("*** Call to getEnv() when system not initialised");
|
||||
jassertfalse;
|
||||
exit (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
return threadLocalJNIEnvHolder.getOrAttach();
|
||||
}
|
||||
|
||||
extern "C" jint JNI_OnLoad (JavaVM*, void*)
|
||||
{
|
||||
return JNI_VERSION_1_2;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
AndroidSystem::AndroidSystem() : screenWidth (0), screenHeight (0)
|
||||
{
|
||||
}
|
||||
|
||||
void AndroidSystem::initialise (JNIEnv* env, jobject activity_,
|
||||
jstring appFile_, jstring appDataDir_)
|
||||
{
|
||||
screenWidth = screenHeight = 0;
|
||||
JNIClassBase::initialiseAllClasses (env);
|
||||
|
||||
threadLocalJNIEnvHolder.initialise (env);
|
||||
#if BEAST_DEBUG
|
||||
systemInitialised = true;
|
||||
#endif
|
||||
|
||||
activity = GlobalRef (activity_);
|
||||
appFile = beastString (env, appFile_);
|
||||
appDataDir = beastString (env, appDataDir_);
|
||||
}
|
||||
|
||||
void AndroidSystem::shutdown (JNIEnv* env)
|
||||
{
|
||||
activity.clear();
|
||||
|
||||
#if BEAST_DEBUG
|
||||
systemInitialised = false;
|
||||
#endif
|
||||
|
||||
JNIClassBase::releaseAllClasses (env);
|
||||
}
|
||||
|
||||
AndroidSystem android;
|
||||
|
||||
//==============================================================================
|
||||
namespace AndroidStatsHelpers
|
||||
{
|
||||
//==============================================================================
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||
STATICMETHOD (getProperty, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;")
|
||||
|
||||
DECLARE_JNI_CLASS (SystemClass, "java/lang/System");
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
//==============================================================================
|
||||
String getSystemProperty (const String& name)
|
||||
{
|
||||
return beastString (LocalRef<jstring> ((jstring) getEnv()->CallStaticObjectMethod (SystemClass,
|
||||
SystemClass.getProperty,
|
||||
javaString (name).get())));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String getLocaleValue (bool isRegion)
|
||||
{
|
||||
return beastString (LocalRef<jstring> ((jstring) getEnv()->CallStaticObjectMethod (BeastAppActivity,
|
||||
BeastAppActivity.getLocaleValue,
|
||||
isRegion)));
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
|
||||
{
|
||||
return Android;
|
||||
}
|
||||
|
||||
String SystemStats::getOperatingSystemName()
|
||||
{
|
||||
return "Android " + AndroidStatsHelpers::getSystemProperty ("os.version");
|
||||
}
|
||||
|
||||
bool SystemStats::isOperatingSystem64Bit()
|
||||
{
|
||||
#if BEAST_64BIT
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
String SystemStats::getCpuVendor()
|
||||
{
|
||||
return AndroidStatsHelpers::getSystemProperty ("os.arch");
|
||||
}
|
||||
|
||||
int SystemStats::getCpuSpeedInMegaherz()
|
||||
{
|
||||
return 0; // TODO
|
||||
}
|
||||
|
||||
int SystemStats::getMemorySizeInMegabytes()
|
||||
{
|
||||
#if __ANDROID_API__ >= 9
|
||||
struct sysinfo sysi;
|
||||
|
||||
if (sysinfo (&sysi) == 0)
|
||||
return (sysi.totalram * sysi.mem_unit / (1024 * 1024));
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SystemStats::getPageSize()
|
||||
{
|
||||
return sysconf (_SC_PAGESIZE);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String SystemStats::getLogonName()
|
||||
{
|
||||
const char* user = getenv ("USER");
|
||||
|
||||
if (user == 0)
|
||||
{
|
||||
struct passwd* const pw = getpwuid (getuid());
|
||||
if (pw != 0)
|
||||
user = pw->pw_name;
|
||||
}
|
||||
|
||||
return CharPointer_UTF8 (user);
|
||||
}
|
||||
|
||||
String SystemStats::getFullUserName()
|
||||
{
|
||||
return getLogonName();
|
||||
}
|
||||
|
||||
String SystemStats::getComputerName()
|
||||
{
|
||||
char name [256] = { 0 };
|
||||
if (gethostname (name, sizeof (name) - 1) == 0)
|
||||
return name;
|
||||
|
||||
return String::empty;
|
||||
}
|
||||
|
||||
|
||||
String SystemStats::getUserLanguage() { return AndroidStatsHelpers::getLocaleValue (false); }
|
||||
String SystemStats::getUserRegion() { return AndroidStatsHelpers::getLocaleValue (true); }
|
||||
String SystemStats::getDisplayLanguage() { return getUserLanguage(); }
|
||||
|
||||
//==============================================================================
|
||||
SystemStats::CPUFlags::CPUFlags()
|
||||
{
|
||||
// TODO
|
||||
hasMMX = false;
|
||||
hasSSE = false;
|
||||
hasSSE2 = false;
|
||||
has3DNow = false;
|
||||
|
||||
numCpus = bmax (1, sysconf (_SC_NPROCESSORS_ONLN));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
uint32 beast_millisecondsSinceStartup() noexcept
|
||||
{
|
||||
timespec t;
|
||||
clock_gettime (CLOCK_MONOTONIC, &t);
|
||||
|
||||
return t.tv_sec * 1000 + t.tv_nsec / 1000000;
|
||||
}
|
||||
|
||||
int64 Time::getHighResolutionTicks() noexcept
|
||||
{
|
||||
timespec t;
|
||||
clock_gettime (CLOCK_MONOTONIC, &t);
|
||||
|
||||
return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000);
|
||||
}
|
||||
|
||||
int64 Time::getHighResolutionTicksPerSecond() noexcept
|
||||
{
|
||||
return 1000000; // (microseconds)
|
||||
}
|
||||
|
||||
double Time::getMillisecondCounterHiRes() noexcept
|
||||
{
|
||||
return getHighResolutionTicks() * 0.001;
|
||||
}
|
||||
|
||||
bool Time::setSystemTimeToThisTime() const
|
||||
{
|
||||
jassertfalse;
|
||||
return false;
|
||||
}
|
||||
77
modules/beast_core/native/beast_android_Threads.cpp
Normal file
77
modules/beast_core/native/beast_android_Threads.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
/*
|
||||
Note that a lot of methods that you'd expect to find in this file actually
|
||||
live in beast_posix_SharedCode.h!
|
||||
*/
|
||||
|
||||
//==============================================================================
|
||||
// sets the process to 0=low priority, 1=normal, 2=high, 3=realtime
|
||||
void Process::setPriority (ProcessPriority prior)
|
||||
{
|
||||
// TODO
|
||||
|
||||
struct sched_param param;
|
||||
int policy, maxp, minp;
|
||||
|
||||
const int p = (int) prior;
|
||||
|
||||
if (p <= 1)
|
||||
policy = SCHED_OTHER;
|
||||
else
|
||||
policy = SCHED_RR;
|
||||
|
||||
minp = sched_get_priority_min (policy);
|
||||
maxp = sched_get_priority_max (policy);
|
||||
|
||||
if (p < 2)
|
||||
param.sched_priority = 0;
|
||||
else if (p == 2 )
|
||||
// Set to middle of lower realtime priority range
|
||||
param.sched_priority = minp + (maxp - minp) / 4;
|
||||
else
|
||||
// Set to middle of higher realtime priority range
|
||||
param.sched_priority = minp + (3 * (maxp - minp) / 4);
|
||||
|
||||
pthread_setschedparam (pthread_self(), policy, ¶m);
|
||||
}
|
||||
|
||||
void Process::terminate()
|
||||
{
|
||||
// TODO
|
||||
exit (0);
|
||||
}
|
||||
|
||||
BEAST_API bool BEAST_CALLTYPE beast_isRunningUnderDebugger()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BEAST_API bool BEAST_CALLTYPE Process::isRunningUnderDebugger()
|
||||
{
|
||||
return beast_isRunningUnderDebugger();
|
||||
}
|
||||
|
||||
void Process::raisePrivilege() {}
|
||||
void Process::lowerPrivilege() {}
|
||||
373
modules/beast_core/native/beast_linux_Files.cpp
Normal file
373
modules/beast_core/native/beast_linux_Files.cpp
Normal file
@@ -0,0 +1,373 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
enum
|
||||
{
|
||||
U_ISOFS_SUPER_MAGIC = 0x9660, // linux/iso_fs.h
|
||||
U_MSDOS_SUPER_MAGIC = 0x4d44, // linux/msdos_fs.h
|
||||
U_NFS_SUPER_MAGIC = 0x6969, // linux/nfs_fs.h
|
||||
U_SMB_SUPER_MAGIC = 0x517B // linux/smb_fs.h
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
bool File::copyInternal (const File& dest) const
|
||||
{
|
||||
FileInputStream in (*this);
|
||||
|
||||
if (dest.deleteFile())
|
||||
{
|
||||
{
|
||||
FileOutputStream out (dest);
|
||||
|
||||
if (out.failedToOpen())
|
||||
return false;
|
||||
|
||||
if (out.writeFromInputStream (in, -1) == getSize())
|
||||
return true;
|
||||
}
|
||||
|
||||
dest.deleteFile();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void File::findFileSystemRoots (Array<File>& destArray)
|
||||
{
|
||||
destArray.add (File ("/"));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool File::isOnCDRomDrive() const
|
||||
{
|
||||
struct statfs buf;
|
||||
|
||||
return statfs (getFullPathName().toUTF8(), &buf) == 0
|
||||
&& buf.f_type == (short) U_ISOFS_SUPER_MAGIC;
|
||||
}
|
||||
|
||||
bool File::isOnHardDisk() const
|
||||
{
|
||||
struct statfs buf;
|
||||
|
||||
if (statfs (getFullPathName().toUTF8(), &buf) == 0)
|
||||
{
|
||||
switch (buf.f_type)
|
||||
{
|
||||
case U_ISOFS_SUPER_MAGIC: // CD-ROM
|
||||
case U_MSDOS_SUPER_MAGIC: // Probably floppy (but could be mounted FAT filesystem)
|
||||
case U_NFS_SUPER_MAGIC: // Network NFS
|
||||
case U_SMB_SUPER_MAGIC: // Network Samba
|
||||
return false;
|
||||
|
||||
default:
|
||||
// Assume anything else is a hard-disk (but note it could
|
||||
// be a RAM disk. There isn't a good way of determining
|
||||
// this for sure)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Assume so if this fails for some reason
|
||||
return true;
|
||||
}
|
||||
|
||||
bool File::isOnRemovableDrive() const
|
||||
{
|
||||
jassertfalse; // xxx not implemented for linux!
|
||||
return false;
|
||||
}
|
||||
|
||||
bool File::isHidden() const
|
||||
{
|
||||
return getFileName().startsWithChar ('.');
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
namespace
|
||||
{
|
||||
File beast_readlink (const String& file, const File& defaultFile)
|
||||
{
|
||||
const size_t size = 8192;
|
||||
HeapBlock<char> buffer;
|
||||
buffer.malloc (size + 4);
|
||||
|
||||
const size_t numBytes = readlink (file.toUTF8(), buffer, size);
|
||||
|
||||
if (numBytes > 0 && numBytes <= size)
|
||||
return File (file).getSiblingFile (String::fromUTF8 (buffer, (int) numBytes));
|
||||
|
||||
return defaultFile;
|
||||
}
|
||||
}
|
||||
|
||||
File File::getLinkedTarget() const
|
||||
{
|
||||
return beast_readlink (getFullPathName().toUTF8(), *this);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static File resolveXDGFolder (const char* const type, const char* const fallbackFolder)
|
||||
{
|
||||
StringArray confLines;
|
||||
File ("~/.config/user-dirs.dirs").readLines (confLines);
|
||||
|
||||
for (int i = 0; i < confLines.size(); ++i)
|
||||
{
|
||||
const String line (confLines[i].trimStart());
|
||||
|
||||
if (line.startsWith (type))
|
||||
{
|
||||
// eg. resolve XDG_MUSIC_DIR="$HOME/Music" to /home/user/Music
|
||||
const File f (line.replace ("$HOME", File ("~").getFullPathName())
|
||||
.fromFirstOccurrenceOf ("=", false, false)
|
||||
.trim().unquoted());
|
||||
|
||||
if (f.isDirectory())
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
return File (fallbackFolder);
|
||||
}
|
||||
|
||||
const char* const* beast_argv = nullptr;
|
||||
int beast_argc = 0;
|
||||
|
||||
File File::getSpecialLocation (const SpecialLocationType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case userHomeDirectory:
|
||||
{
|
||||
const char* homeDir = getenv ("HOME");
|
||||
|
||||
if (homeDir == nullptr)
|
||||
{
|
||||
struct passwd* const pw = getpwuid (getuid());
|
||||
if (pw != nullptr)
|
||||
homeDir = pw->pw_dir;
|
||||
}
|
||||
|
||||
return File (CharPointer_UTF8 (homeDir));
|
||||
}
|
||||
|
||||
case userDocumentsDirectory: return resolveXDGFolder ("XDG_DOCUMENTS_DIR", "~");
|
||||
case userMusicDirectory: return resolveXDGFolder ("XDG_MUSIC_DIR", "~");
|
||||
case userMoviesDirectory: return resolveXDGFolder ("XDG_VIDEOS_DIR", "~");
|
||||
case userPicturesDirectory: return resolveXDGFolder ("XDG_PICTURES_DIR", "~");
|
||||
case userDesktopDirectory: return resolveXDGFolder ("XDG_DESKTOP_DIR", "~/Desktop");
|
||||
case userApplicationDataDirectory: return File ("~");
|
||||
case commonApplicationDataDirectory: return File ("/var");
|
||||
case globalApplicationsDirectory: return File ("/usr");
|
||||
|
||||
case tempDirectory:
|
||||
{
|
||||
File tmp ("/var/tmp");
|
||||
|
||||
if (! tmp.isDirectory())
|
||||
{
|
||||
tmp = "/tmp";
|
||||
|
||||
if (! tmp.isDirectory())
|
||||
tmp = File::getCurrentWorkingDirectory();
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
case invokedExecutableFile:
|
||||
if (beast_argv != nullptr && beast_argc > 0)
|
||||
return File (CharPointer_UTF8 (beast_argv[0]));
|
||||
// deliberate fall-through...
|
||||
|
||||
case currentExecutableFile:
|
||||
case currentApplicationFile:
|
||||
return beast_getExecutableFile();
|
||||
|
||||
case hostApplicationPath:
|
||||
return beast_readlink ("/proc/self/exe", beast_getExecutableFile());
|
||||
|
||||
default:
|
||||
jassertfalse; // unknown type?
|
||||
break;
|
||||
}
|
||||
|
||||
return File::nonexistent;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String File::getVersion() const
|
||||
{
|
||||
return String::empty; // xxx not yet implemented
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool File::moveToTrash() const
|
||||
{
|
||||
if (! exists())
|
||||
return true;
|
||||
|
||||
File trashCan ("~/.Trash");
|
||||
|
||||
if (! trashCan.isDirectory())
|
||||
trashCan = "~/.local/share/Trash/files";
|
||||
|
||||
if (! trashCan.isDirectory())
|
||||
return false;
|
||||
|
||||
return moveFileTo (trashCan.getNonexistentChildFile (getFileNameWithoutExtension(),
|
||||
getFileExtension()));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class DirectoryIterator::NativeIterator::Pimpl
|
||||
{
|
||||
public:
|
||||
Pimpl (const File& directory, const String& wildCard_)
|
||||
: parentDir (File::addTrailingSeparator (directory.getFullPathName())),
|
||||
wildCard (wildCard_),
|
||||
dir (opendir (directory.getFullPathName().toUTF8()))
|
||||
{
|
||||
}
|
||||
|
||||
~Pimpl()
|
||||
{
|
||||
if (dir != nullptr)
|
||||
closedir (dir);
|
||||
}
|
||||
|
||||
bool next (String& filenameFound,
|
||||
bool* const isDir, bool* const isHidden, int64* const fileSize,
|
||||
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||
{
|
||||
if (dir != nullptr)
|
||||
{
|
||||
const char* wildcardUTF8 = nullptr;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
struct dirent* const de = readdir (dir);
|
||||
|
||||
if (de == nullptr)
|
||||
break;
|
||||
|
||||
if (wildcardUTF8 == nullptr)
|
||||
wildcardUTF8 = wildCard.toUTF8();
|
||||
|
||||
if (fnmatch (wildcardUTF8, de->d_name, FNM_CASEFOLD) == 0)
|
||||
{
|
||||
filenameFound = CharPointer_UTF8 (de->d_name);
|
||||
|
||||
updateStatInfoForFile (parentDir + filenameFound, isDir, fileSize, modTime, creationTime, isReadOnly);
|
||||
|
||||
if (isHidden != nullptr)
|
||||
*isHidden = filenameFound.startsWithChar ('.');
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
String parentDir, wildCard;
|
||||
DIR* dir;
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE (Pimpl)
|
||||
};
|
||||
|
||||
DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildCard)
|
||||
: pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildCard))
|
||||
{
|
||||
}
|
||||
|
||||
DirectoryIterator::NativeIterator::~NativeIterator()
|
||||
{
|
||||
}
|
||||
|
||||
bool DirectoryIterator::NativeIterator::next (String& filenameFound,
|
||||
bool* const isDir, bool* const isHidden, int64* const fileSize,
|
||||
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||
{
|
||||
return pimpl->next (filenameFound, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
static bool isFileExecutable (const String& filename)
|
||||
{
|
||||
beast_statStruct info;
|
||||
|
||||
return beast_stat (filename, info)
|
||||
&& S_ISREG (info.st_mode)
|
||||
&& access (filename.toUTF8(), X_OK) == 0;
|
||||
}
|
||||
|
||||
bool Process::openDocument (const String& fileName, const String& parameters)
|
||||
{
|
||||
String cmdString (fileName.replace (" ", "\\ ",false));
|
||||
cmdString << " " << parameters;
|
||||
|
||||
if (URL::isProbablyAWebsiteURL (fileName)
|
||||
|| cmdString.startsWithIgnoreCase ("file:")
|
||||
|| URL::isProbablyAnEmailAddress (fileName)
|
||||
|| File::createFileWithoutCheckingPath (fileName).isDirectory()
|
||||
|| ! isFileExecutable (fileName))
|
||||
{
|
||||
// create a command that tries to launch a bunch of likely browsers
|
||||
const char* const browserNames[] = { "xdg-open", "/etc/alternatives/x-www-browser", "firefox", "mozilla",
|
||||
"google-chrome", "chromium-browser", "opera", "konqueror" };
|
||||
StringArray cmdLines;
|
||||
|
||||
for (int i = 0; i < numElementsInArray (browserNames); ++i)
|
||||
cmdLines.add (String (browserNames[i]) + " " + cmdString.trim().quoted());
|
||||
|
||||
cmdString = cmdLines.joinIntoString (" || ");
|
||||
}
|
||||
|
||||
const char* const argv[4] = { "/bin/sh", "-c", cmdString.toUTF8(), 0 };
|
||||
|
||||
const int cpid = fork();
|
||||
|
||||
if (cpid == 0)
|
||||
{
|
||||
setsid();
|
||||
|
||||
// Child process
|
||||
execve (argv[0], (char**) argv, environ);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
return cpid >= 0;
|
||||
}
|
||||
|
||||
void File::revealToUser() const
|
||||
{
|
||||
if (isDirectory())
|
||||
startAsProcess();
|
||||
else if (getParentDirectory().exists())
|
||||
getParentDirectory().startAsProcess();
|
||||
}
|
||||
457
modules/beast_core/native/beast_linux_Network.cpp
Normal file
457
modules/beast_core/native/beast_linux_Network.cpp
Normal file
@@ -0,0 +1,457 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
void MACAddress::findAllAddresses (Array<MACAddress>& result)
|
||||
{
|
||||
const int s = socket (AF_INET, SOCK_DGRAM, 0);
|
||||
if (s != -1)
|
||||
{
|
||||
char buf [1024];
|
||||
struct ifconf ifc;
|
||||
ifc.ifc_len = sizeof (buf);
|
||||
ifc.ifc_buf = buf;
|
||||
ioctl (s, SIOCGIFCONF, &ifc);
|
||||
|
||||
for (unsigned int i = 0; i < ifc.ifc_len / sizeof (struct ifreq); ++i)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
strcpy (ifr.ifr_name, ifc.ifc_req[i].ifr_name);
|
||||
|
||||
if (ioctl (s, SIOCGIFFLAGS, &ifr) == 0
|
||||
&& (ifr.ifr_flags & IFF_LOOPBACK) == 0
|
||||
&& ioctl (s, SIOCGIFHWADDR, &ifr) == 0)
|
||||
{
|
||||
result.addIfNotAlreadyThere (MACAddress ((const uint8*) ifr.ifr_hwaddr.sa_data));
|
||||
}
|
||||
}
|
||||
|
||||
close (s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Process::openEmailWithAttachments (const String& /* targetEmailAddress */,
|
||||
const String& /* emailSubject */,
|
||||
const String& /* bodyText */,
|
||||
const StringArray& /* filesToAttach */)
|
||||
{
|
||||
jassertfalse; // xxx todo
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class WebInputStream : public InputStream
|
||||
{
|
||||
public:
|
||||
WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_,
|
||||
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
|
||||
const String& headers_, int timeOutMs_, StringPairArray* responseHeaders)
|
||||
: socketHandle (-1), levelsOfRedirection (0),
|
||||
address (address_), headers (headers_), postData (postData_), position (0),
|
||||
finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
|
||||
{
|
||||
createConnection (progressCallback, progressCallbackContext);
|
||||
|
||||
if (responseHeaders != nullptr && ! isError())
|
||||
{
|
||||
for (int i = 0; i < headerLines.size(); ++i)
|
||||
{
|
||||
const String& headersEntry = headerLines[i];
|
||||
const String key (headersEntry.upToFirstOccurrenceOf (": ", false, false));
|
||||
const String value (headersEntry.fromFirstOccurrenceOf (": ", false, false));
|
||||
const String previousValue ((*responseHeaders) [key]);
|
||||
responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~WebInputStream()
|
||||
{
|
||||
closeSocket();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool isError() const { return socketHandle < 0; }
|
||||
bool isExhausted() { return finished; }
|
||||
int64 getPosition() { return position; }
|
||||
|
||||
int64 getTotalLength()
|
||||
{
|
||||
//xxx to do
|
||||
return -1;
|
||||
}
|
||||
|
||||
int read (void* buffer, int bytesToRead)
|
||||
{
|
||||
if (finished || isError())
|
||||
return 0;
|
||||
|
||||
fd_set readbits;
|
||||
FD_ZERO (&readbits);
|
||||
FD_SET (socketHandle, &readbits);
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = bmax (1, timeOutMs / 1000);
|
||||
tv.tv_usec = 0;
|
||||
|
||||
if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0)
|
||||
return 0; // (timeout)
|
||||
|
||||
const int bytesRead = bmax (0, (int) recv (socketHandle, buffer, bytesToRead, MSG_WAITALL));
|
||||
if (bytesRead == 0)
|
||||
finished = true;
|
||||
position += bytesRead;
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
bool setPosition (int64 wantedPos)
|
||||
{
|
||||
if (isError())
|
||||
return false;
|
||||
|
||||
if (wantedPos != position)
|
||||
{
|
||||
finished = false;
|
||||
|
||||
if (wantedPos < position)
|
||||
{
|
||||
closeSocket();
|
||||
position = 0;
|
||||
createConnection (0, 0);
|
||||
}
|
||||
|
||||
skipNextBytes (wantedPos - position);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
private:
|
||||
int socketHandle, levelsOfRedirection;
|
||||
StringArray headerLines;
|
||||
String address, headers;
|
||||
MemoryBlock postData;
|
||||
int64 position;
|
||||
bool finished;
|
||||
const bool isPost;
|
||||
const int timeOutMs;
|
||||
|
||||
void closeSocket()
|
||||
{
|
||||
if (socketHandle >= 0)
|
||||
close (socketHandle);
|
||||
|
||||
socketHandle = -1;
|
||||
levelsOfRedirection = 0;
|
||||
}
|
||||
|
||||
void createConnection (URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext)
|
||||
{
|
||||
closeSocket();
|
||||
|
||||
uint32 timeOutTime = Time::getMillisecondCounter();
|
||||
|
||||
if (timeOutMs == 0)
|
||||
timeOutTime += 60000;
|
||||
else if (timeOutMs < 0)
|
||||
timeOutTime = 0xffffffff;
|
||||
else
|
||||
timeOutTime += timeOutMs;
|
||||
|
||||
String hostName, hostPath;
|
||||
int hostPort;
|
||||
if (! decomposeURL (address, hostName, hostPath, hostPort))
|
||||
return;
|
||||
|
||||
String serverName, proxyName, proxyPath;
|
||||
int proxyPort = 0;
|
||||
int port = 0;
|
||||
|
||||
const String proxyURL (getenv ("http_proxy"));
|
||||
if (proxyURL.startsWithIgnoreCase ("http://"))
|
||||
{
|
||||
if (! decomposeURL (proxyURL, proxyName, proxyPath, proxyPort))
|
||||
return;
|
||||
|
||||
serverName = proxyName;
|
||||
port = proxyPort;
|
||||
}
|
||||
else
|
||||
{
|
||||
serverName = hostName;
|
||||
port = hostPort;
|
||||
}
|
||||
|
||||
struct addrinfo hints;
|
||||
zerostruct (hints);
|
||||
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_NUMERICSERV;
|
||||
|
||||
struct addrinfo* result = nullptr;
|
||||
if (getaddrinfo (serverName.toUTF8(), String (port).toUTF8(), &hints, &result) != 0 || result == 0)
|
||||
return;
|
||||
|
||||
socketHandle = socket (result->ai_family, result->ai_socktype, 0);
|
||||
|
||||
if (socketHandle == -1)
|
||||
{
|
||||
freeaddrinfo (result);
|
||||
return;
|
||||
}
|
||||
|
||||
int receiveBufferSize = 16384;
|
||||
setsockopt (socketHandle, SOL_SOCKET, SO_RCVBUF, (char*) &receiveBufferSize, sizeof (receiveBufferSize));
|
||||
setsockopt (socketHandle, SOL_SOCKET, SO_KEEPALIVE, 0, 0);
|
||||
|
||||
#if BEAST_MAC
|
||||
setsockopt (socketHandle, SOL_SOCKET, SO_NOSIGPIPE, 0, 0);
|
||||
#endif
|
||||
|
||||
if (connect (socketHandle, result->ai_addr, result->ai_addrlen) == -1)
|
||||
{
|
||||
closeSocket();
|
||||
freeaddrinfo (result);
|
||||
return;
|
||||
}
|
||||
|
||||
freeaddrinfo (result);
|
||||
|
||||
{
|
||||
const MemoryBlock requestHeader (createRequestHeader (hostName, hostPort, proxyName, proxyPort,
|
||||
hostPath, address, headers, postData, isPost));
|
||||
|
||||
if (! sendHeader (socketHandle, requestHeader, timeOutTime, progressCallback, progressCallbackContext))
|
||||
{
|
||||
closeSocket();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
String responseHeader (readResponse (socketHandle, timeOutTime));
|
||||
|
||||
if (responseHeader.isNotEmpty())
|
||||
{
|
||||
headerLines = StringArray::fromLines (responseHeader);
|
||||
|
||||
const int statusCode = responseHeader.fromFirstOccurrenceOf (" ", false, false)
|
||||
.substring (0, 3).getIntValue();
|
||||
|
||||
//int contentLength = findHeaderItem (lines, "Content-Length:").getIntValue();
|
||||
//bool isChunked = findHeaderItem (lines, "Transfer-Encoding:").equalsIgnoreCase ("chunked");
|
||||
|
||||
String location (findHeaderItem (headerLines, "Location:"));
|
||||
|
||||
if (statusCode >= 300 && statusCode < 400 && location.isNotEmpty())
|
||||
{
|
||||
if (! location.startsWithIgnoreCase ("http://"))
|
||||
location = "http://" + location;
|
||||
|
||||
if (++levelsOfRedirection <= 3)
|
||||
{
|
||||
address = location;
|
||||
createConnection (progressCallback, progressCallbackContext);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
levelsOfRedirection = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
closeSocket();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static String readResponse (const int socketHandle, const uint32 timeOutTime)
|
||||
{
|
||||
int bytesRead = 0, numConsecutiveLFs = 0;
|
||||
MemoryBlock buffer (1024, true);
|
||||
|
||||
while (numConsecutiveLFs < 2 && bytesRead < 32768
|
||||
&& Time::getMillisecondCounter() <= timeOutTime)
|
||||
{
|
||||
fd_set readbits;
|
||||
FD_ZERO (&readbits);
|
||||
FD_SET (socketHandle, &readbits);
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = bmax (1, (int) (timeOutTime - Time::getMillisecondCounter()) / 1000);
|
||||
tv.tv_usec = 0;
|
||||
|
||||
if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0)
|
||||
return String::empty; // (timeout)
|
||||
|
||||
buffer.ensureSize (bytesRead + 8, true);
|
||||
char* const dest = (char*) buffer.getData() + bytesRead;
|
||||
|
||||
if (recv (socketHandle, dest, 1, 0) == -1)
|
||||
return String::empty;
|
||||
|
||||
const char lastByte = *dest;
|
||||
++bytesRead;
|
||||
|
||||
if (lastByte == '\n')
|
||||
++numConsecutiveLFs;
|
||||
else if (lastByte != '\r')
|
||||
numConsecutiveLFs = 0;
|
||||
}
|
||||
|
||||
const String header (CharPointer_UTF8 ((const char*) buffer.getData()));
|
||||
|
||||
if (header.startsWithIgnoreCase ("HTTP/"))
|
||||
return header.trimEnd();
|
||||
|
||||
return String::empty;
|
||||
}
|
||||
|
||||
static void writeValueIfNotPresent (MemoryOutputStream& dest, const String& headers, const String& key, const String& value)
|
||||
{
|
||||
if (! headers.containsIgnoreCase (key))
|
||||
dest << "\r\n" << key << ' ' << value;
|
||||
}
|
||||
|
||||
static void writeHost (MemoryOutputStream& dest, const bool isPost, const String& path, const String& host, const int port)
|
||||
{
|
||||
dest << (isPost ? "POST " : "GET ") << path << " HTTP/1.0\r\nHost: " << host;
|
||||
|
||||
if (port > 0)
|
||||
dest << ':' << port;
|
||||
}
|
||||
|
||||
static MemoryBlock createRequestHeader (const String& hostName, const int hostPort,
|
||||
const String& proxyName, const int proxyPort,
|
||||
const String& hostPath, const String& originalURL,
|
||||
const String& userHeaders, const MemoryBlock& postData,
|
||||
const bool isPost)
|
||||
{
|
||||
MemoryOutputStream header;
|
||||
|
||||
if (proxyName.isEmpty())
|
||||
writeHost (header, isPost, hostPath, hostName, hostPort);
|
||||
else
|
||||
writeHost (header, isPost, originalURL, proxyName, proxyPort);
|
||||
|
||||
writeValueIfNotPresent (header, userHeaders, "User-Agent:", "BEAST/" BEAST_STRINGIFY(BEAST_MAJOR_VERSION)
|
||||
"." BEAST_STRINGIFY(BEAST_MINOR_VERSION)
|
||||
"." BEAST_STRINGIFY(BEAST_BUILDNUMBER));
|
||||
writeValueIfNotPresent (header, userHeaders, "Connection:", "Close");
|
||||
|
||||
if (isPost)
|
||||
writeValueIfNotPresent (header, userHeaders, "Content-Length:", String ((int) postData.getSize()));
|
||||
|
||||
header << "\r\n" << userHeaders
|
||||
<< "\r\n" << postData;
|
||||
|
||||
return header.getMemoryBlock();
|
||||
}
|
||||
|
||||
static bool sendHeader (int socketHandle, const MemoryBlock& requestHeader, const uint32 timeOutTime,
|
||||
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext)
|
||||
{
|
||||
size_t totalHeaderSent = 0;
|
||||
|
||||
while (totalHeaderSent < requestHeader.getSize())
|
||||
{
|
||||
if (Time::getMillisecondCounter() > timeOutTime)
|
||||
return false;
|
||||
|
||||
const int numToSend = bmin (1024, (int) (requestHeader.getSize() - totalHeaderSent));
|
||||
|
||||
if (send (socketHandle, static_cast <const char*> (requestHeader.getData()) + totalHeaderSent, numToSend, 0) != numToSend)
|
||||
return false;
|
||||
|
||||
totalHeaderSent += numToSend;
|
||||
|
||||
if (progressCallback != nullptr && ! progressCallback (progressCallbackContext, totalHeaderSent, requestHeader.getSize()))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool decomposeURL (const String& url, String& host, String& path, int& port)
|
||||
{
|
||||
if (! url.startsWithIgnoreCase ("http://"))
|
||||
return false;
|
||||
|
||||
const int nextSlash = url.indexOfChar (7, '/');
|
||||
int nextColon = url.indexOfChar (7, ':');
|
||||
if (nextColon > nextSlash && nextSlash > 0)
|
||||
nextColon = -1;
|
||||
|
||||
if (nextColon >= 0)
|
||||
{
|
||||
host = url.substring (7, nextColon);
|
||||
|
||||
if (nextSlash >= 0)
|
||||
port = url.substring (nextColon + 1, nextSlash).getIntValue();
|
||||
else
|
||||
port = url.substring (nextColon + 1).getIntValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
port = 80;
|
||||
|
||||
if (nextSlash >= 0)
|
||||
host = url.substring (7, nextSlash);
|
||||
else
|
||||
host = url.substring (7);
|
||||
}
|
||||
|
||||
if (nextSlash >= 0)
|
||||
path = url.substring (nextSlash);
|
||||
else
|
||||
path = "/";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static String findHeaderItem (const StringArray& lines, const String& itemName)
|
||||
{
|
||||
for (int i = 0; i < lines.size(); ++i)
|
||||
if (lines[i].startsWithIgnoreCase (itemName))
|
||||
return lines[i].substring (itemName.length()).trim();
|
||||
|
||||
return String::empty;
|
||||
}
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream)
|
||||
};
|
||||
|
||||
InputStream* URL::createNativeStream (const String& address, bool isPost, const MemoryBlock& postData,
|
||||
OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
|
||||
const String& headers, const int timeOutMs, StringPairArray* responseHeaders)
|
||||
{
|
||||
ScopedPointer <WebInputStream> wi (new WebInputStream (address, isPost, postData,
|
||||
progressCallback, progressCallbackContext,
|
||||
headers, timeOutMs, responseHeaders));
|
||||
|
||||
return wi->isError() ? nullptr : wi.release();
|
||||
}
|
||||
177
modules/beast_core/native/beast_linux_SystemStats.cpp
Normal file
177
modules/beast_core/native/beast_linux_SystemStats.cpp
Normal file
@@ -0,0 +1,177 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
void Logger::outputDebugString (const String& text)
|
||||
{
|
||||
std::cerr << text << std::endl;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
|
||||
{
|
||||
return Linux;
|
||||
}
|
||||
|
||||
String SystemStats::getOperatingSystemName()
|
||||
{
|
||||
return "Linux";
|
||||
}
|
||||
|
||||
bool SystemStats::isOperatingSystem64Bit()
|
||||
{
|
||||
#if BEAST_64BIT
|
||||
return true;
|
||||
#else
|
||||
//xxx not sure how to find this out?..
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
namespace LinuxStatsHelpers
|
||||
{
|
||||
String getCpuInfo (const char* const key)
|
||||
{
|
||||
StringArray lines;
|
||||
File ("/proc/cpuinfo").readLines (lines);
|
||||
|
||||
for (int i = lines.size(); --i >= 0;) // (NB - it's important that this runs in reverse order)
|
||||
if (lines[i].startsWithIgnoreCase (key))
|
||||
return lines[i].fromFirstOccurrenceOf (":", false, false).trim();
|
||||
|
||||
return String::empty;
|
||||
}
|
||||
}
|
||||
|
||||
String SystemStats::getCpuVendor()
|
||||
{
|
||||
return LinuxStatsHelpers::getCpuInfo ("vendor_id");
|
||||
}
|
||||
|
||||
int SystemStats::getCpuSpeedInMegaherz()
|
||||
{
|
||||
return roundToInt (LinuxStatsHelpers::getCpuInfo ("cpu MHz").getFloatValue());
|
||||
}
|
||||
|
||||
int SystemStats::getMemorySizeInMegabytes()
|
||||
{
|
||||
struct sysinfo sysi;
|
||||
|
||||
if (sysinfo (&sysi) == 0)
|
||||
return (sysi.totalram * sysi.mem_unit / (1024 * 1024));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SystemStats::getPageSize()
|
||||
{
|
||||
return sysconf (_SC_PAGESIZE);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String SystemStats::getLogonName()
|
||||
{
|
||||
const char* user = getenv ("USER");
|
||||
|
||||
if (user == nullptr)
|
||||
{
|
||||
struct passwd* const pw = getpwuid (getuid());
|
||||
if (pw != nullptr)
|
||||
user = pw->pw_name;
|
||||
}
|
||||
|
||||
return CharPointer_UTF8 (user);
|
||||
}
|
||||
|
||||
String SystemStats::getFullUserName()
|
||||
{
|
||||
return getLogonName();
|
||||
}
|
||||
|
||||
String SystemStats::getComputerName()
|
||||
{
|
||||
char name [256] = { 0 };
|
||||
if (gethostname (name, sizeof (name) - 1) == 0)
|
||||
return name;
|
||||
|
||||
return String::empty;
|
||||
}
|
||||
|
||||
String getLocaleValue (nl_item key)
|
||||
{
|
||||
const char* oldLocale = ::setlocale (LC_ALL, "");
|
||||
return String (const_cast <const char*> (nl_langinfo (key)));
|
||||
::setlocale (LC_ALL, oldLocale);
|
||||
}
|
||||
|
||||
String SystemStats::getUserLanguage() { return getLocaleValue (_NL_IDENTIFICATION_LANGUAGE); }
|
||||
String SystemStats::getUserRegion() { return getLocaleValue (_NL_IDENTIFICATION_TERRITORY); }
|
||||
String SystemStats::getDisplayLanguage() { return getUserLanguage(); }
|
||||
|
||||
//==============================================================================
|
||||
SystemStats::CPUFlags::CPUFlags()
|
||||
{
|
||||
const String flags (LinuxStatsHelpers::getCpuInfo ("flags"));
|
||||
hasMMX = flags.contains ("mmx");
|
||||
hasSSE = flags.contains ("sse");
|
||||
hasSSE2 = flags.contains ("sse2");
|
||||
has3DNow = flags.contains ("3dnow");
|
||||
|
||||
numCpus = LinuxStatsHelpers::getCpuInfo ("processor").getIntValue() + 1;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
uint32 beast_millisecondsSinceStartup() noexcept
|
||||
{
|
||||
timespec t;
|
||||
clock_gettime (CLOCK_MONOTONIC, &t);
|
||||
|
||||
return t.tv_sec * 1000 + t.tv_nsec / 1000000;
|
||||
}
|
||||
|
||||
int64 Time::getHighResolutionTicks() noexcept
|
||||
{
|
||||
timespec t;
|
||||
clock_gettime (CLOCK_MONOTONIC, &t);
|
||||
|
||||
return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000);
|
||||
}
|
||||
|
||||
int64 Time::getHighResolutionTicksPerSecond() noexcept
|
||||
{
|
||||
return 1000000; // (microseconds)
|
||||
}
|
||||
|
||||
double Time::getMillisecondCounterHiRes() noexcept
|
||||
{
|
||||
return getHighResolutionTicks() * 0.001;
|
||||
}
|
||||
|
||||
bool Time::setSystemTimeToThisTime() const
|
||||
{
|
||||
timeval t;
|
||||
t.tv_sec = millisSinceEpoch / 1000;
|
||||
t.tv_usec = (millisSinceEpoch - t.tv_sec * 1000) * 1000;
|
||||
|
||||
return settimeofday (&t, 0) == 0;
|
||||
}
|
||||
85
modules/beast_core/native/beast_linux_Threads.cpp
Normal file
85
modules/beast_core/native/beast_linux_Threads.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
/*
|
||||
Note that a lot of methods that you'd expect to find in this file actually
|
||||
live in beast_posix_SharedCode.h!
|
||||
*/
|
||||
|
||||
//==============================================================================
|
||||
void Process::setPriority (const ProcessPriority prior)
|
||||
{
|
||||
const int policy = (prior <= NormalPriority) ? SCHED_OTHER : SCHED_RR;
|
||||
const int minp = sched_get_priority_min (policy);
|
||||
const int maxp = sched_get_priority_max (policy);
|
||||
|
||||
struct sched_param param;
|
||||
|
||||
switch (prior)
|
||||
{
|
||||
case LowPriority:
|
||||
case NormalPriority: param.sched_priority = 0; break;
|
||||
case HighPriority: param.sched_priority = minp + (maxp - minp) / 4; break;
|
||||
case RealtimePriority: param.sched_priority = minp + (3 * (maxp - minp) / 4); break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
|
||||
pthread_setschedparam (pthread_self(), policy, ¶m);
|
||||
}
|
||||
|
||||
void Process::terminate()
|
||||
{
|
||||
exit (0);
|
||||
}
|
||||
|
||||
BEAST_API bool BEAST_CALLTYPE beast_isRunningUnderDebugger()
|
||||
{
|
||||
static char testResult = 0;
|
||||
|
||||
if (testResult == 0)
|
||||
{
|
||||
testResult = (char) ptrace (PT_TRACE_ME, 0, 0, 0);
|
||||
|
||||
if (testResult >= 0)
|
||||
{
|
||||
ptrace (PT_DETACH, 0, (caddr_t) 1, 0);
|
||||
testResult = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return testResult < 0;
|
||||
}
|
||||
|
||||
BEAST_API bool BEAST_CALLTYPE Process::isRunningUnderDebugger()
|
||||
{
|
||||
return beast_isRunningUnderDebugger();
|
||||
}
|
||||
|
||||
static void swapUserAndEffectiveUser()
|
||||
{
|
||||
(void) setreuid (geteuid(), getuid());
|
||||
(void) setregid (getegid(), getgid());
|
||||
}
|
||||
|
||||
void Process::raisePrivilege() { if (geteuid() != 0 && getuid() == 0) swapUserAndEffectiveUser(); }
|
||||
void Process::lowerPrivilege() { if (geteuid() == 0 && getuid() != 0) swapUserAndEffectiveUser(); }
|
||||
480
modules/beast_core/native/beast_mac_Files.mm
Normal file
480
modules/beast_core/native/beast_mac_Files.mm
Normal file
@@ -0,0 +1,480 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
/*
|
||||
Note that a lot of methods that you'd expect to find in this file actually
|
||||
live in beast_posix_SharedCode.h!
|
||||
*/
|
||||
|
||||
//==============================================================================
|
||||
bool File::copyInternal (const File& dest) const
|
||||
{
|
||||
BEAST_AUTORELEASEPOOL
|
||||
{
|
||||
NSFileManager* fm = [NSFileManager defaultManager];
|
||||
|
||||
return [fm fileExistsAtPath: beastStringToNS (fullPath)]
|
||||
#if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
|
||||
&& [fm copyItemAtPath: beastStringToNS (fullPath)
|
||||
toPath: beastStringToNS (dest.getFullPathName())
|
||||
error: nil];
|
||||
#else
|
||||
&& [fm copyPath: beastStringToNS (fullPath)
|
||||
toPath: beastStringToNS (dest.getFullPathName())
|
||||
handler: nil];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void File::findFileSystemRoots (Array<File>& destArray)
|
||||
{
|
||||
destArray.add (File ("/"));
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
namespace FileHelpers
|
||||
{
|
||||
static bool isFileOnDriveType (const File& f, const char* const* types)
|
||||
{
|
||||
struct statfs buf;
|
||||
|
||||
if (beast_doStatFS (f, buf))
|
||||
{
|
||||
const String type (buf.f_fstypename);
|
||||
|
||||
while (*types != 0)
|
||||
if (type.equalsIgnoreCase (*types++))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool isHiddenFile (const String& path)
|
||||
{
|
||||
#if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
|
||||
BEAST_AUTORELEASEPOOL
|
||||
{
|
||||
NSNumber* hidden = nil;
|
||||
NSError* err = nil;
|
||||
|
||||
return [[NSURL fileURLWithPath: beastStringToNS (path)]
|
||||
getResourceValue: &hidden forKey: NSURLIsHiddenKey error: &err]
|
||||
&& [hidden boolValue];
|
||||
}
|
||||
#elif BEAST_IOS
|
||||
return File (path).getFileName().startsWithChar ('.');
|
||||
#else
|
||||
FSRef ref;
|
||||
LSItemInfoRecord info;
|
||||
|
||||
return FSPathMakeRefWithOptions ((const UInt8*) path.toRawUTF8(), kFSPathMakeRefDoNotFollowLeafSymlink, &ref, 0) == noErr
|
||||
&& LSCopyItemInfoForRef (&ref, kLSRequestBasicFlagsOnly, &info) == noErr
|
||||
&& (info.flags & kLSItemInfoIsInvisible) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if BEAST_IOS
|
||||
String getIOSSystemLocation (NSSearchPathDirectory type)
|
||||
{
|
||||
return nsStringToBeast ([NSSearchPathForDirectoriesInDomains (type, NSUserDomainMask, YES)
|
||||
objectAtIndex: 0]);
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool launchExecutable (const String& pathAndArguments)
|
||||
{
|
||||
const char* const argv[4] = { "/bin/sh", "-c", pathAndArguments.toUTF8(), 0 };
|
||||
|
||||
const int cpid = fork();
|
||||
|
||||
if (cpid == 0)
|
||||
{
|
||||
// Child process
|
||||
if (execve (argv[0], (char**) argv, 0) < 0)
|
||||
exit (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cpid < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool File::isOnCDRomDrive() const
|
||||
{
|
||||
const char* const cdTypes[] = { "cd9660", "cdfs", "cddafs", "udf", 0 };
|
||||
|
||||
return FileHelpers::isFileOnDriveType (*this, cdTypes);
|
||||
}
|
||||
|
||||
bool File::isOnHardDisk() const
|
||||
{
|
||||
const char* const nonHDTypes[] = { "nfs", "smbfs", "ramfs", 0 };
|
||||
|
||||
return ! (isOnCDRomDrive() || FileHelpers::isFileOnDriveType (*this, nonHDTypes));
|
||||
}
|
||||
|
||||
bool File::isOnRemovableDrive() const
|
||||
{
|
||||
#if BEAST_IOS
|
||||
return false; // xxx is this possible?
|
||||
#else
|
||||
BEAST_AUTORELEASEPOOL
|
||||
{
|
||||
BOOL removable = false;
|
||||
|
||||
[[NSWorkspace sharedWorkspace]
|
||||
getFileSystemInfoForPath: beastStringToNS (getFullPathName())
|
||||
isRemovable: &removable
|
||||
isWritable: nil
|
||||
isUnmountable: nil
|
||||
description: nil
|
||||
type: nil];
|
||||
|
||||
return removable;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool File::isHidden() const
|
||||
{
|
||||
return FileHelpers::isHiddenFile (getFullPathName());
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
const char* const* beast_argv = nullptr;
|
||||
int beast_argc = 0;
|
||||
|
||||
File File::getSpecialLocation (const SpecialLocationType type)
|
||||
{
|
||||
BEAST_AUTORELEASEPOOL
|
||||
{
|
||||
String resultPath;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case userHomeDirectory: resultPath = nsStringToBeast (NSHomeDirectory()); break;
|
||||
|
||||
#if BEAST_IOS
|
||||
case userDocumentsDirectory: resultPath = FileHelpers::getIOSSystemLocation (NSDocumentDirectory); break;
|
||||
case userDesktopDirectory: resultPath = FileHelpers::getIOSSystemLocation (NSDesktopDirectory); break;
|
||||
|
||||
case tempDirectory:
|
||||
{
|
||||
File tmp (FileHelpers::getIOSSystemLocation (NSCachesDirectory));
|
||||
tmp = tmp.getChildFile (beast_getExecutableFile().getFileNameWithoutExtension());
|
||||
tmp.createDirectory();
|
||||
return tmp.getFullPathName();
|
||||
}
|
||||
|
||||
#else
|
||||
case userDocumentsDirectory: resultPath = "~/Documents"; break;
|
||||
case userDesktopDirectory: resultPath = "~/Desktop"; break;
|
||||
|
||||
case tempDirectory:
|
||||
{
|
||||
File tmp ("~/Library/Caches/" + beast_getExecutableFile().getFileNameWithoutExtension());
|
||||
tmp.createDirectory();
|
||||
return tmp.getFullPathName();
|
||||
}
|
||||
#endif
|
||||
case userMusicDirectory: resultPath = "~/Music"; break;
|
||||
case userMoviesDirectory: resultPath = "~/Movies"; break;
|
||||
case userPicturesDirectory: resultPath = "~/Pictures"; break;
|
||||
case userApplicationDataDirectory: resultPath = "~/Library"; break;
|
||||
case commonApplicationDataDirectory: resultPath = "/Library"; break;
|
||||
case globalApplicationsDirectory: resultPath = "/Applications"; break;
|
||||
|
||||
case invokedExecutableFile:
|
||||
if (beast_argv != nullptr && beast_argc > 0)
|
||||
return File (CharPointer_UTF8 (beast_argv[0]));
|
||||
// deliberate fall-through...
|
||||
|
||||
case currentExecutableFile:
|
||||
return beast_getExecutableFile();
|
||||
|
||||
case currentApplicationFile:
|
||||
{
|
||||
const File exe (beast_getExecutableFile());
|
||||
const File parent (exe.getParentDirectory());
|
||||
|
||||
#if BEAST_IOS
|
||||
return parent;
|
||||
#else
|
||||
return parent.getFullPathName().endsWithIgnoreCase ("Contents/MacOS")
|
||||
? parent.getParentDirectory().getParentDirectory()
|
||||
: exe;
|
||||
#endif
|
||||
}
|
||||
|
||||
case hostApplicationPath:
|
||||
{
|
||||
unsigned int size = 8192;
|
||||
HeapBlock<char> buffer;
|
||||
buffer.calloc (size + 8);
|
||||
|
||||
_NSGetExecutablePath (buffer.getData(), &size);
|
||||
return String::fromUTF8 (buffer, (int) size);
|
||||
}
|
||||
|
||||
default:
|
||||
jassertfalse; // unknown type?
|
||||
break;
|
||||
}
|
||||
|
||||
if (resultPath.isNotEmpty())
|
||||
return File (resultPath.convertToPrecomposedUnicode());
|
||||
}
|
||||
|
||||
return File::nonexistent;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String File::getVersion() const
|
||||
{
|
||||
BEAST_AUTORELEASEPOOL
|
||||
{
|
||||
if (NSBundle* bundle = [NSBundle bundleWithPath: beastStringToNS (getFullPathName())])
|
||||
if (NSDictionary* info = [bundle infoDictionary])
|
||||
if (NSString* name = [info valueForKey: nsStringLiteral ("CFBundleShortVersionString")])
|
||||
return nsStringToBeast (name);
|
||||
}
|
||||
|
||||
return String::empty;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
File File::getLinkedTarget() const
|
||||
{
|
||||
#if BEAST_IOS || (defined (MAC_OS_X_VERSION_10_5) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
|
||||
NSString* dest = [[NSFileManager defaultManager] destinationOfSymbolicLinkAtPath: beastStringToNS (getFullPathName()) error: nil];
|
||||
#else
|
||||
// (the cast here avoids a deprecation warning)
|
||||
NSString* dest = [((id) [NSFileManager defaultManager]) pathContentOfSymbolicLinkAtPath: beastStringToNS (getFullPathName())];
|
||||
#endif
|
||||
|
||||
if (dest != nil)
|
||||
return File (nsStringToBeast (dest));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool File::moveToTrash() const
|
||||
{
|
||||
if (! exists())
|
||||
return true;
|
||||
|
||||
#if BEAST_IOS
|
||||
return deleteFile(); //xxx is there a trashcan on the iOS?
|
||||
#else
|
||||
BEAST_AUTORELEASEPOOL
|
||||
{
|
||||
NSString* p = beastStringToNS (getFullPathName());
|
||||
|
||||
return [[NSWorkspace sharedWorkspace]
|
||||
performFileOperation: NSWorkspaceRecycleOperation
|
||||
source: [p stringByDeletingLastPathComponent]
|
||||
destination: nsEmptyString()
|
||||
files: [NSArray arrayWithObject: [p lastPathComponent]]
|
||||
tag: nil ];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class DirectoryIterator::NativeIterator::Pimpl
|
||||
{
|
||||
public:
|
||||
Pimpl (const File& directory, const String& wildCard_)
|
||||
: parentDir (File::addTrailingSeparator (directory.getFullPathName())),
|
||||
wildCard (wildCard_),
|
||||
enumerator (nil)
|
||||
{
|
||||
BEAST_AUTORELEASEPOOL
|
||||
{
|
||||
enumerator = [[[NSFileManager defaultManager] enumeratorAtPath: beastStringToNS (directory.getFullPathName())] retain];
|
||||
}
|
||||
}
|
||||
|
||||
~Pimpl()
|
||||
{
|
||||
[enumerator release];
|
||||
}
|
||||
|
||||
bool next (String& filenameFound,
|
||||
bool* const isDir, bool* const isHidden, int64* const fileSize,
|
||||
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||
{
|
||||
BEAST_AUTORELEASEPOOL
|
||||
{
|
||||
const char* wildcardUTF8 = nullptr;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
NSString* file;
|
||||
if (enumerator == nil || (file = [enumerator nextObject]) == nil)
|
||||
return false;
|
||||
|
||||
[enumerator skipDescendents];
|
||||
filenameFound = nsStringToBeast (file);
|
||||
|
||||
if (wildcardUTF8 == nullptr)
|
||||
wildcardUTF8 = wildCard.toUTF8();
|
||||
|
||||
if (fnmatch (wildcardUTF8, filenameFound.toUTF8(), FNM_CASEFOLD) != 0)
|
||||
continue;
|
||||
|
||||
const String fullPath (parentDir + filenameFound);
|
||||
updateStatInfoForFile (fullPath, isDir, fileSize, modTime, creationTime, isReadOnly);
|
||||
|
||||
if (isHidden != nullptr)
|
||||
*isHidden = FileHelpers::isHiddenFile (fullPath);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
String parentDir, wildCard;
|
||||
NSDirectoryEnumerator* enumerator;
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE (Pimpl)
|
||||
};
|
||||
|
||||
DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildcard)
|
||||
: pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildcard))
|
||||
{
|
||||
}
|
||||
|
||||
DirectoryIterator::NativeIterator::~NativeIterator()
|
||||
{
|
||||
}
|
||||
|
||||
bool DirectoryIterator::NativeIterator::next (String& filenameFound,
|
||||
bool* const isDir, bool* const isHidden, int64* const fileSize,
|
||||
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||
{
|
||||
return pimpl->next (filenameFound, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
bool Process::openDocument (const String& fileName, const String& parameters)
|
||||
{
|
||||
#if BEAST_IOS
|
||||
return [[UIApplication sharedApplication] openURL: [NSURL URLWithString: beastStringToNS (fileName)]];
|
||||
#else
|
||||
BEAST_AUTORELEASEPOOL
|
||||
{
|
||||
if (parameters.isEmpty())
|
||||
{
|
||||
return [[NSWorkspace sharedWorkspace] openFile: beastStringToNS (fileName)]
|
||||
|| [[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString: beastStringToNS (fileName)]];
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
const File file (fileName);
|
||||
|
||||
if (file.isBundle())
|
||||
{
|
||||
NSMutableArray* urls = [NSMutableArray array];
|
||||
|
||||
StringArray docs;
|
||||
docs.addTokens (parameters, true);
|
||||
for (int i = 0; i < docs.size(); ++i)
|
||||
[urls addObject: beastStringToNS (docs[i])];
|
||||
|
||||
ok = [[NSWorkspace sharedWorkspace] openURLs: urls
|
||||
withAppBundleIdentifier: [[NSBundle bundleWithPath: beastStringToNS (fileName)] bundleIdentifier]
|
||||
options: 0
|
||||
additionalEventParamDescriptor: nil
|
||||
launchIdentifiers: nil];
|
||||
}
|
||||
else if (file.exists())
|
||||
{
|
||||
ok = FileHelpers::launchExecutable ("\"" + fileName + "\" " + parameters);
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void File::revealToUser() const
|
||||
{
|
||||
#if ! BEAST_IOS
|
||||
if (exists())
|
||||
[[NSWorkspace sharedWorkspace] selectFile: beastStringToNS (getFullPathName()) inFileViewerRootedAtPath: nsEmptyString()];
|
||||
else if (getParentDirectory().exists())
|
||||
getParentDirectory().revealToUser();
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
OSType File::getMacOSType() const
|
||||
{
|
||||
BEAST_AUTORELEASEPOOL
|
||||
{
|
||||
#if BEAST_IOS || (defined (MAC_OS_X_VERSION_10_5) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
|
||||
NSDictionary* fileDict = [[NSFileManager defaultManager] attributesOfItemAtPath: beastStringToNS (getFullPathName()) error: nil];
|
||||
#else
|
||||
// (the cast here avoids a deprecation warning)
|
||||
NSDictionary* fileDict = [((id) [NSFileManager defaultManager]) fileAttributesAtPath: beastStringToNS (getFullPathName()) traverseLink: NO];
|
||||
#endif
|
||||
|
||||
return [fileDict fileHFSTypeCode];
|
||||
}
|
||||
}
|
||||
|
||||
bool File::isBundle() const
|
||||
{
|
||||
#if BEAST_IOS
|
||||
return false; // xxx can't find a sensible way to do this without trying to open the bundle..
|
||||
#else
|
||||
BEAST_AUTORELEASEPOOL
|
||||
{
|
||||
return [[NSWorkspace sharedWorkspace] isFilePackageAtPath: beastStringToNS (getFullPathName())];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if BEAST_MAC
|
||||
void File::addToDock() const
|
||||
{
|
||||
// check that it's not already there...
|
||||
if (! beast_getOutputFromCommand ("defaults read com.apple.dock persistent-apps").containsIgnoreCase (getFullPathName()))
|
||||
{
|
||||
beast_runSystemCommand ("defaults write com.apple.dock persistent-apps -array-add \"<dict><key>tile-data</key><dict><key>file-data</key><dict><key>_CFURLString</key><string>"
|
||||
+ getFullPathName() + "</string><key>_CFURLStringType</key><integer>0</integer></dict></dict></dict>\"");
|
||||
|
||||
beast_runSystemCommand ("osascript -e \"tell application \\\"Dock\\\" to quit\"");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
427
modules/beast_core/native/beast_mac_Network.mm
Normal file
427
modules/beast_core/native/beast_mac_Network.mm
Normal file
@@ -0,0 +1,427 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
void MACAddress::findAllAddresses (Array<MACAddress>& result)
|
||||
{
|
||||
ifaddrs* addrs = nullptr;
|
||||
|
||||
if (getifaddrs (&addrs) == 0)
|
||||
{
|
||||
for (const ifaddrs* cursor = addrs; cursor != nullptr; cursor = cursor->ifa_next)
|
||||
{
|
||||
sockaddr_storage* sto = (sockaddr_storage*) cursor->ifa_addr;
|
||||
if (sto->ss_family == AF_LINK)
|
||||
{
|
||||
const sockaddr_dl* const sadd = (const sockaddr_dl*) cursor->ifa_addr;
|
||||
|
||||
#ifndef IFT_ETHER
|
||||
#define IFT_ETHER 6
|
||||
#endif
|
||||
|
||||
if (sadd->sdl_type == IFT_ETHER)
|
||||
result.addIfNotAlreadyThere (MACAddress (((const uint8*) sadd->sdl_data) + sadd->sdl_nlen));
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs (addrs);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool Process::openEmailWithAttachments (const String& targetEmailAddress,
|
||||
const String& emailSubject,
|
||||
const String& bodyText,
|
||||
const StringArray& filesToAttach)
|
||||
{
|
||||
#if BEAST_IOS
|
||||
//xxx probably need to use MFMailComposeViewController
|
||||
jassertfalse;
|
||||
return false;
|
||||
#else
|
||||
BEAST_AUTORELEASEPOOL
|
||||
{
|
||||
String script;
|
||||
script << "tell application \"Mail\"\r\n"
|
||||
"set newMessage to make new outgoing message with properties {subject:\""
|
||||
<< emailSubject.replace ("\"", "\\\"")
|
||||
<< "\", content:\""
|
||||
<< bodyText.replace ("\"", "\\\"")
|
||||
<< "\" & return & return}\r\n"
|
||||
"tell newMessage\r\n"
|
||||
"set visible to true\r\n"
|
||||
"set sender to \"sdfsdfsdfewf\"\r\n"
|
||||
"make new to recipient at end of to recipients with properties {address:\""
|
||||
<< targetEmailAddress
|
||||
<< "\"}\r\n";
|
||||
|
||||
for (int i = 0; i < filesToAttach.size(); ++i)
|
||||
{
|
||||
script << "tell content\r\n"
|
||||
"make new attachment with properties {file name:\""
|
||||
<< filesToAttach[i].replace ("\"", "\\\"")
|
||||
<< "\"} at after the last paragraph\r\n"
|
||||
"end tell\r\n";
|
||||
}
|
||||
|
||||
script << "end tell\r\n"
|
||||
"end tell\r\n";
|
||||
|
||||
NSAppleScript* s = [[NSAppleScript alloc] initWithSource: beastStringToNS (script)];
|
||||
NSDictionary* error = nil;
|
||||
const bool ok = [s executeAndReturnError: &error] != nil;
|
||||
[s release];
|
||||
|
||||
return ok;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class URLConnectionState : public Thread
|
||||
{
|
||||
public:
|
||||
URLConnectionState (NSURLRequest* req)
|
||||
: Thread ("http connection"),
|
||||
contentLength (-1),
|
||||
delegate (nil),
|
||||
request ([req retain]),
|
||||
connection (nil),
|
||||
data ([[NSMutableData data] retain]),
|
||||
headers (nil),
|
||||
initialised (false),
|
||||
hasFailed (false),
|
||||
hasFinished (false)
|
||||
{
|
||||
static DelegateClass cls;
|
||||
delegate = [cls.createInstance() init];
|
||||
DelegateClass::setState (delegate, this);
|
||||
}
|
||||
|
||||
~URLConnectionState()
|
||||
{
|
||||
stop();
|
||||
[connection release];
|
||||
[data release];
|
||||
[request release];
|
||||
[headers release];
|
||||
[delegate release];
|
||||
}
|
||||
|
||||
bool start (URL::OpenStreamProgressCallback* callback, void* context)
|
||||
{
|
||||
startThread();
|
||||
|
||||
while (isThreadRunning() && ! initialised)
|
||||
{
|
||||
if (callback != nullptr)
|
||||
callback (context, -1, (int) [[request HTTPBody] length]);
|
||||
|
||||
Thread::sleep (1);
|
||||
}
|
||||
|
||||
return connection != nil && ! hasFailed;
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
[connection cancel];
|
||||
stopThread (10000);
|
||||
}
|
||||
|
||||
int read (char* dest, int numBytes)
|
||||
{
|
||||
int numDone = 0;
|
||||
|
||||
while (numBytes > 0)
|
||||
{
|
||||
const int available = bmin (numBytes, (int) [data length]);
|
||||
|
||||
if (available > 0)
|
||||
{
|
||||
const ScopedLock sl (dataLock);
|
||||
[data getBytes: dest length: (NSUInteger) available];
|
||||
[data replaceBytesInRange: NSMakeRange (0, (NSUInteger) available) withBytes: nil length: 0];
|
||||
|
||||
numDone += available;
|
||||
numBytes -= available;
|
||||
dest += available;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hasFailed || hasFinished)
|
||||
break;
|
||||
|
||||
Thread::sleep (1);
|
||||
}
|
||||
}
|
||||
|
||||
return numDone;
|
||||
}
|
||||
|
||||
void didReceiveResponse (NSURLResponse* response)
|
||||
{
|
||||
{
|
||||
const ScopedLock sl (dataLock);
|
||||
[data setLength: 0];
|
||||
}
|
||||
|
||||
initialised = true;
|
||||
contentLength = [response expectedContentLength];
|
||||
|
||||
[headers release];
|
||||
headers = nil;
|
||||
|
||||
if ([response isKindOfClass: [NSHTTPURLResponse class]])
|
||||
headers = [[((NSHTTPURLResponse*) response) allHeaderFields] retain];
|
||||
}
|
||||
|
||||
void didFailWithError (NSError* error)
|
||||
{
|
||||
DBG (nsStringToBeast ([error description])); (void) error;
|
||||
hasFailed = true;
|
||||
initialised = true;
|
||||
signalThreadShouldExit();
|
||||
}
|
||||
|
||||
void didReceiveData (NSData* newData)
|
||||
{
|
||||
const ScopedLock sl (dataLock);
|
||||
[data appendData: newData];
|
||||
initialised = true;
|
||||
}
|
||||
|
||||
void didSendBodyData (int /*totalBytesWritten*/, int /*totalBytesExpected*/)
|
||||
{
|
||||
}
|
||||
|
||||
void finishedLoading()
|
||||
{
|
||||
hasFinished = true;
|
||||
initialised = true;
|
||||
signalThreadShouldExit();
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
connection = [[NSURLConnection alloc] initWithRequest: request
|
||||
delegate: delegate];
|
||||
while (! threadShouldExit())
|
||||
{
|
||||
BEAST_AUTORELEASEPOOL
|
||||
{
|
||||
[[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int64 contentLength;
|
||||
CriticalSection dataLock;
|
||||
NSObject* delegate;
|
||||
NSURLRequest* request;
|
||||
NSURLConnection* connection;
|
||||
NSMutableData* data;
|
||||
NSDictionary* headers;
|
||||
bool initialised, hasFailed, hasFinished;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct DelegateClass : public ObjCClass <NSObject>
|
||||
{
|
||||
DelegateClass() : ObjCClass <NSObject> ("BEASTAppDelegate_")
|
||||
{
|
||||
addIvar <URLConnectionState*> ("state");
|
||||
|
||||
addMethod (@selector (connection:didReceiveResponse:), didReceiveResponse, "v@:@@");
|
||||
addMethod (@selector (connection:didFailWithError:), didFailWithError, "v@:@@");
|
||||
addMethod (@selector (connection:didReceiveData:), didReceiveData, "v@:@@");
|
||||
addMethod (@selector (connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:totalBytesExpectedToWrite:),
|
||||
connectionDidSendBodyData, "v@:@iii");
|
||||
addMethod (@selector (connectionDidFinishLoading:), connectionDidFinishLoading, "v@:@");
|
||||
|
||||
registerClass();
|
||||
}
|
||||
|
||||
static void setState (id self, URLConnectionState* state) { object_setInstanceVariable (self, "state", state); }
|
||||
static URLConnectionState* getState (id self) { return getIvar<URLConnectionState*> (self, "state"); }
|
||||
|
||||
private:
|
||||
static void didReceiveResponse (id self, SEL, NSURLConnection*, NSURLResponse* response)
|
||||
{
|
||||
getState (self)->didReceiveResponse (response);
|
||||
}
|
||||
|
||||
static void didFailWithError (id self, SEL, NSURLConnection*, NSError* error)
|
||||
{
|
||||
getState (self)->didFailWithError (error);
|
||||
}
|
||||
|
||||
static void didReceiveData (id self, SEL, NSURLConnection*, NSData* newData)
|
||||
{
|
||||
getState (self)->didReceiveData (newData);
|
||||
}
|
||||
|
||||
static void connectionDidSendBodyData (id self, SEL, NSURLConnection*, NSInteger, NSInteger totalBytesWritten, NSInteger totalBytesExpected)
|
||||
{
|
||||
getState (self)->didSendBodyData (totalBytesWritten, totalBytesExpected);
|
||||
}
|
||||
|
||||
static void connectionDidFinishLoading (id self, SEL, NSURLConnection*)
|
||||
{
|
||||
getState (self)->finishedLoading();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (URLConnectionState)
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class WebInputStream : public InputStream
|
||||
{
|
||||
public:
|
||||
WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_,
|
||||
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
|
||||
const String& headers_, int timeOutMs_, StringPairArray* responseHeaders)
|
||||
: address (address_), headers (headers_), postData (postData_), position (0),
|
||||
finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
|
||||
{
|
||||
BEAST_AUTORELEASEPOOL
|
||||
{
|
||||
createConnection (progressCallback, progressCallbackContext);
|
||||
|
||||
if (responseHeaders != nullptr && connection != nullptr && connection->headers != nil)
|
||||
{
|
||||
NSEnumerator* enumerator = [connection->headers keyEnumerator];
|
||||
NSString* key;
|
||||
|
||||
while ((key = [enumerator nextObject]) != nil)
|
||||
responseHeaders->set (nsStringToBeast (key),
|
||||
nsStringToBeast ((NSString*) [connection->headers objectForKey: key]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool isError() const { return connection == nullptr; }
|
||||
int64 getTotalLength() { return connection == nullptr ? -1 : connection->contentLength; }
|
||||
bool isExhausted() { return finished; }
|
||||
int64 getPosition() { return position; }
|
||||
|
||||
int read (void* buffer, int bytesToRead)
|
||||
{
|
||||
bassert (buffer != nullptr && bytesToRead >= 0);
|
||||
|
||||
if (finished || isError())
|
||||
return 0;
|
||||
|
||||
BEAST_AUTORELEASEPOOL
|
||||
{
|
||||
const int bytesRead = connection->read (static_cast <char*> (buffer), bytesToRead);
|
||||
position += bytesRead;
|
||||
|
||||
if (bytesRead == 0)
|
||||
finished = true;
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
bool setPosition (int64 wantedPos)
|
||||
{
|
||||
if (wantedPos != position)
|
||||
{
|
||||
finished = false;
|
||||
|
||||
if (wantedPos < position)
|
||||
{
|
||||
connection = nullptr;
|
||||
position = 0;
|
||||
createConnection (0, 0);
|
||||
}
|
||||
|
||||
skipNextBytes (wantedPos - position);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
ScopedPointer<URLConnectionState> connection;
|
||||
String address, headers;
|
||||
MemoryBlock postData;
|
||||
int64 position;
|
||||
bool finished;
|
||||
const bool isPost;
|
||||
const int timeOutMs;
|
||||
|
||||
void createConnection (URL::OpenStreamProgressCallback* progressCallback,
|
||||
void* progressCallbackContext)
|
||||
{
|
||||
bassert (connection == nullptr);
|
||||
|
||||
NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL: [NSURL URLWithString: beastStringToNS (address)]
|
||||
cachePolicy: NSURLRequestReloadIgnoringLocalCacheData
|
||||
timeoutInterval: timeOutMs <= 0 ? 60.0 : (timeOutMs / 1000.0)];
|
||||
|
||||
if (req != nil)
|
||||
{
|
||||
[req setHTTPMethod: nsStringLiteral (isPost ? "POST" : "GET")];
|
||||
//[req setCachePolicy: NSURLRequestReloadIgnoringLocalAndRemoteCacheData];
|
||||
|
||||
StringArray headerLines;
|
||||
headerLines.addLines (headers);
|
||||
headerLines.removeEmptyStrings (true);
|
||||
|
||||
for (int i = 0; i < headerLines.size(); ++i)
|
||||
{
|
||||
const String key (headerLines[i].upToFirstOccurrenceOf (":", false, false).trim());
|
||||
const String value (headerLines[i].fromFirstOccurrenceOf (":", false, false).trim());
|
||||
|
||||
if (key.isNotEmpty() && value.isNotEmpty())
|
||||
[req addValue: beastStringToNS (value) forHTTPHeaderField: beastStringToNS (key)];
|
||||
}
|
||||
|
||||
if (isPost && postData.getSize() > 0)
|
||||
[req setHTTPBody: [NSData dataWithBytes: postData.getData()
|
||||
length: postData.getSize()]];
|
||||
|
||||
connection = new URLConnectionState (req);
|
||||
|
||||
if (! connection->start (progressCallback, progressCallbackContext))
|
||||
connection = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream)
|
||||
};
|
||||
|
||||
InputStream* URL::createNativeStream (const String& address, bool isPost, const MemoryBlock& postData,
|
||||
OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
|
||||
const String& headers, const int timeOutMs, StringPairArray* responseHeaders)
|
||||
{
|
||||
ScopedPointer <WebInputStream> wi (new WebInputStream (address, isPost, postData,
|
||||
progressCallback, progressCallbackContext,
|
||||
headers, timeOutMs, responseHeaders));
|
||||
|
||||
return wi->isError() ? nullptr : wi.release();
|
||||
}
|
||||
91
modules/beast_core/native/beast_mac_Strings.mm
Normal file
91
modules/beast_core/native/beast_mac_Strings.mm
Normal file
@@ -0,0 +1,91 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
String String::fromCFString (CFStringRef cfString)
|
||||
{
|
||||
if (cfString == 0)
|
||||
return String::empty;
|
||||
|
||||
CFRange range = { 0, CFStringGetLength (cfString) };
|
||||
HeapBlock <UniChar> u ((size_t) range.length + 1);
|
||||
CFStringGetCharacters (cfString, range, u);
|
||||
u[range.length] = 0;
|
||||
|
||||
return String (CharPointer_UTF16 ((const CharPointer_UTF16::CharType*) u.getData()));
|
||||
}
|
||||
|
||||
CFStringRef String::toCFString() const
|
||||
{
|
||||
CharPointer_UTF16 utf16 (toUTF16());
|
||||
return CFStringCreateWithCharacters (kCFAllocatorDefault, (const UniChar*) utf16.getAddress(), (CFIndex) utf16.length());
|
||||
}
|
||||
|
||||
String String::convertToPrecomposedUnicode() const
|
||||
{
|
||||
#if BEAST_IOS
|
||||
BEAST_AUTORELEASEPOOL
|
||||
{
|
||||
return nsStringToBeast ([beastStringToNS (*this) precomposedStringWithCanonicalMapping]);
|
||||
}
|
||||
#else
|
||||
UnicodeMapping map;
|
||||
|
||||
map.unicodeEncoding = CreateTextEncoding (kTextEncodingUnicodeDefault,
|
||||
kUnicodeNoSubset,
|
||||
kTextEncodingDefaultFormat);
|
||||
|
||||
map.otherEncoding = CreateTextEncoding (kTextEncodingUnicodeDefault,
|
||||
kUnicodeCanonicalCompVariant,
|
||||
kTextEncodingDefaultFormat);
|
||||
|
||||
map.mappingVersion = kUnicodeUseLatestMapping;
|
||||
|
||||
UnicodeToTextInfo conversionInfo = 0;
|
||||
String result;
|
||||
|
||||
if (CreateUnicodeToTextInfo (&map, &conversionInfo) == noErr)
|
||||
{
|
||||
const size_t bytesNeeded = CharPointer_UTF16::getBytesRequiredFor (getCharPointer());
|
||||
|
||||
HeapBlock <char> tempOut;
|
||||
tempOut.calloc (bytesNeeded + 4);
|
||||
|
||||
ByteCount bytesRead = 0;
|
||||
ByteCount outputBufferSize = 0;
|
||||
|
||||
if (ConvertFromUnicodeToText (conversionInfo,
|
||||
bytesNeeded, (ConstUniCharArrayPtr) toUTF16().getAddress(),
|
||||
kUnicodeDefaultDirectionMask,
|
||||
0, 0, 0, 0,
|
||||
bytesNeeded, &bytesRead,
|
||||
&outputBufferSize, tempOut) == noErr)
|
||||
{
|
||||
result = String (CharPointer_UTF16 ((CharPointer_UTF16::CharType*) tempOut.getData()));
|
||||
}
|
||||
|
||||
DisposeUnicodeToTextInfo (&conversionInfo);
|
||||
}
|
||||
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
291
modules/beast_core/native/beast_mac_SystemStats.mm
Normal file
291
modules/beast_core/native/beast_mac_SystemStats.mm
Normal file
@@ -0,0 +1,291 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
ScopedAutoReleasePool::ScopedAutoReleasePool()
|
||||
{
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
}
|
||||
|
||||
ScopedAutoReleasePool::~ScopedAutoReleasePool()
|
||||
{
|
||||
[((NSAutoreleasePool*) pool) release];
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void Logger::outputDebugString (const String& text)
|
||||
{
|
||||
// Would prefer to use std::cerr here, but avoiding it for
|
||||
// the moment, due to clang JIT linkage problems.
|
||||
fputs (text.toRawUTF8(), stderr);
|
||||
fputs ("\n", stderr);
|
||||
fflush (stderr);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
namespace SystemStatsHelpers
|
||||
{
|
||||
#if BEAST_INTEL && ! BEAST_NO_INLINE_ASM
|
||||
static void doCPUID (uint32& a, uint32& b, uint32& c, uint32& d, uint32 type)
|
||||
{
|
||||
uint32 la = a, lb = b, lc = c, ld = d;
|
||||
|
||||
asm ("mov %%ebx, %%esi \n\t"
|
||||
"cpuid \n\t"
|
||||
"xchg %%esi, %%ebx"
|
||||
: "=a" (la), "=S" (lb), "=c" (lc), "=d" (ld) : "a" (type)
|
||||
#if BEAST_64BIT
|
||||
, "b" (lb), "c" (lc), "d" (ld)
|
||||
#endif
|
||||
);
|
||||
|
||||
a = la; b = lb; c = lc; d = ld;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
SystemStats::CPUFlags::CPUFlags()
|
||||
{
|
||||
#if BEAST_INTEL && ! BEAST_NO_INLINE_ASM
|
||||
uint32 familyModel = 0, extFeatures = 0, features = 0, dummy = 0;
|
||||
SystemStatsHelpers::doCPUID (familyModel, extFeatures, dummy, features, 1);
|
||||
|
||||
hasMMX = (features & (1u << 23)) != 0;
|
||||
hasSSE = (features & (1u << 25)) != 0;
|
||||
hasSSE2 = (features & (1u << 26)) != 0;
|
||||
has3DNow = (extFeatures & (1u << 31)) != 0;
|
||||
#else
|
||||
hasMMX = false;
|
||||
hasSSE = false;
|
||||
hasSSE2 = false;
|
||||
has3DNow = false;
|
||||
#endif
|
||||
|
||||
#if BEAST_IOS || (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
|
||||
numCpus = (int) [[NSProcessInfo processInfo] activeProcessorCount];
|
||||
#else
|
||||
numCpus = (int) MPProcessors();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if BEAST_MAC
|
||||
struct RLimitInitialiser
|
||||
{
|
||||
RLimitInitialiser()
|
||||
{
|
||||
rlimit lim;
|
||||
getrlimit (RLIMIT_NOFILE, &lim);
|
||||
lim.rlim_cur = lim.rlim_max = RLIM_INFINITY;
|
||||
setrlimit (RLIMIT_NOFILE, &lim);
|
||||
}
|
||||
};
|
||||
|
||||
static RLimitInitialiser rLimitInitialiser;
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#if ! BEAST_IOS
|
||||
static String getOSXVersion()
|
||||
{
|
||||
BEAST_AUTORELEASEPOOL
|
||||
{
|
||||
NSDictionary* dict = [NSDictionary dictionaryWithContentsOfFile:
|
||||
nsStringLiteral ("/System/Library/CoreServices/SystemVersion.plist")];
|
||||
|
||||
return nsStringToBeast ([dict objectForKey: nsStringLiteral ("ProductVersion")]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
|
||||
{
|
||||
#if BEAST_IOS
|
||||
return iOS;
|
||||
#else
|
||||
StringArray parts;
|
||||
parts.addTokens (getOSXVersion(), ".", String::empty);
|
||||
|
||||
bassert (parts[0].getIntValue() == 10);
|
||||
const int major = parts[1].getIntValue();
|
||||
bassert (major > 2);
|
||||
|
||||
return (OperatingSystemType) (major + MacOSX_10_4 - 4);
|
||||
#endif
|
||||
}
|
||||
|
||||
String SystemStats::getOperatingSystemName()
|
||||
{
|
||||
#if BEAST_IOS
|
||||
return "iOS " + nsStringToBeast ([[UIDevice currentDevice] systemVersion]);
|
||||
#else
|
||||
return "Mac OSX " + getOSXVersion();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SystemStats::isOperatingSystem64Bit()
|
||||
{
|
||||
#if BEAST_IOS
|
||||
return false;
|
||||
#elif BEAST_64BIT
|
||||
return true;
|
||||
#else
|
||||
return getOperatingSystemType() >= MacOSX_10_6;
|
||||
#endif
|
||||
}
|
||||
|
||||
int SystemStats::getMemorySizeInMegabytes()
|
||||
{
|
||||
uint64 mem = 0;
|
||||
size_t memSize = sizeof (mem);
|
||||
int mib[] = { CTL_HW, HW_MEMSIZE };
|
||||
sysctl (mib, 2, &mem, &memSize, 0, 0);
|
||||
return (int) (mem / (1024 * 1024));
|
||||
}
|
||||
|
||||
String SystemStats::getCpuVendor()
|
||||
{
|
||||
#if BEAST_INTEL && ! BEAST_NO_INLINE_ASM
|
||||
uint32 dummy = 0;
|
||||
uint32 vendor[4] = { 0 };
|
||||
|
||||
SystemStatsHelpers::doCPUID (dummy, vendor[0], vendor[2], vendor[1], 0);
|
||||
|
||||
return String (reinterpret_cast <const char*> (vendor), 12);
|
||||
#else
|
||||
return String::empty;
|
||||
#endif
|
||||
}
|
||||
|
||||
int SystemStats::getCpuSpeedInMegaherz()
|
||||
{
|
||||
uint64 speedHz = 0;
|
||||
size_t speedSize = sizeof (speedHz);
|
||||
int mib[] = { CTL_HW, HW_CPU_FREQ };
|
||||
sysctl (mib, 2, &speedHz, &speedSize, 0, 0);
|
||||
|
||||
#if BEAST_BIG_ENDIAN
|
||||
if (speedSize == 4)
|
||||
speedHz >>= 32;
|
||||
#endif
|
||||
|
||||
return (int) (speedHz / 1000000);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String SystemStats::getLogonName()
|
||||
{
|
||||
return nsStringToBeast (NSUserName());
|
||||
}
|
||||
|
||||
String SystemStats::getFullUserName()
|
||||
{
|
||||
return nsStringToBeast (NSFullUserName());
|
||||
}
|
||||
|
||||
String SystemStats::getComputerName()
|
||||
{
|
||||
char name [256] = { 0 };
|
||||
if (gethostname (name, sizeof (name) - 1) == 0)
|
||||
return String (name).upToLastOccurrenceOf (".local", false, true);
|
||||
|
||||
return String::empty;
|
||||
}
|
||||
|
||||
static String getLocaleValue (CFStringRef key)
|
||||
{
|
||||
CFLocaleRef cfLocale = CFLocaleCopyCurrent();
|
||||
const String result (String::fromCFString ((CFStringRef) CFLocaleGetValue (cfLocale, key)));
|
||||
CFRelease (cfLocale);
|
||||
return result;
|
||||
}
|
||||
|
||||
String SystemStats::getUserLanguage() { return getLocaleValue (kCFLocaleLanguageCode); }
|
||||
String SystemStats::getUserRegion() { return getLocaleValue (kCFLocaleCountryCode); }
|
||||
|
||||
String SystemStats::getDisplayLanguage()
|
||||
{
|
||||
CFArrayRef cfPrefLangs = CFLocaleCopyPreferredLanguages();
|
||||
const String result (String::fromCFString ((CFStringRef) CFArrayGetValueAtIndex (cfPrefLangs, 0)));
|
||||
CFRelease (cfPrefLangs);
|
||||
return result;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class HiResCounterHandler
|
||||
{
|
||||
public:
|
||||
HiResCounterHandler()
|
||||
{
|
||||
mach_timebase_info_data_t timebase;
|
||||
(void) mach_timebase_info (&timebase);
|
||||
|
||||
if (timebase.numer % 1000000 == 0)
|
||||
{
|
||||
numerator = timebase.numer / 1000000;
|
||||
denominator = timebase.denom;
|
||||
}
|
||||
else
|
||||
{
|
||||
numerator = timebase.numer;
|
||||
denominator = timebase.denom * (uint64) 1000000;
|
||||
}
|
||||
|
||||
highResTimerFrequency = (timebase.denom * (uint64) 1000000000) / timebase.numer;
|
||||
highResTimerToMillisecRatio = numerator / (double) denominator;
|
||||
}
|
||||
|
||||
inline uint32 millisecondsSinceStartup() const noexcept
|
||||
{
|
||||
return (uint32) ((mach_absolute_time() * numerator) / denominator);
|
||||
}
|
||||
|
||||
inline double getMillisecondCounterHiRes() const noexcept
|
||||
{
|
||||
return mach_absolute_time() * highResTimerToMillisecRatio;
|
||||
}
|
||||
|
||||
int64 highResTimerFrequency;
|
||||
|
||||
private:
|
||||
uint64 numerator, denominator;
|
||||
double highResTimerToMillisecRatio;
|
||||
};
|
||||
|
||||
static HiResCounterHandler hiResCounterHandler;
|
||||
|
||||
uint32 beast_millisecondsSinceStartup() noexcept { return hiResCounterHandler.millisecondsSinceStartup(); }
|
||||
double Time::getMillisecondCounterHiRes() noexcept { return hiResCounterHandler.getMillisecondCounterHiRes(); }
|
||||
int64 Time::getHighResolutionTicksPerSecond() noexcept { return hiResCounterHandler.highResTimerFrequency; }
|
||||
int64 Time::getHighResolutionTicks() noexcept { return (int64) mach_absolute_time(); }
|
||||
|
||||
bool Time::setSystemTimeToThisTime() const
|
||||
{
|
||||
jassertfalse;
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
int SystemStats::getPageSize()
|
||||
{
|
||||
return (int) NSPageSize();
|
||||
}
|
||||
86
modules/beast_core/native/beast_mac_Threads.mm
Normal file
86
modules/beast_core/native/beast_mac_Threads.mm
Normal file
@@ -0,0 +1,86 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
/*
|
||||
Note that a lot of methods that you'd expect to find in this file actually
|
||||
live in beast_posix_SharedCode.h!
|
||||
*/
|
||||
|
||||
//==============================================================================
|
||||
bool Process::isForegroundProcess()
|
||||
{
|
||||
#if BEAST_MAC
|
||||
return [NSApp isActive];
|
||||
#else
|
||||
return true; // xxx change this if more than one app is ever possible on iOS!
|
||||
#endif
|
||||
}
|
||||
|
||||
void Process::makeForegroundProcess()
|
||||
{
|
||||
#if BEAST_MAC
|
||||
[NSApp activateIgnoringOtherApps: YES];
|
||||
#endif
|
||||
}
|
||||
|
||||
void Process::raisePrivilege()
|
||||
{
|
||||
jassertfalse;
|
||||
}
|
||||
|
||||
void Process::lowerPrivilege()
|
||||
{
|
||||
jassertfalse;
|
||||
}
|
||||
|
||||
void Process::terminate()
|
||||
{
|
||||
exit (0);
|
||||
}
|
||||
|
||||
void Process::setPriority (ProcessPriority)
|
||||
{
|
||||
// xxx
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
BEAST_API bool BEAST_CALLTYPE beast_isRunningUnderDebugger()
|
||||
{
|
||||
static char testResult = 0;
|
||||
|
||||
if (testResult == 0)
|
||||
{
|
||||
struct kinfo_proc info;
|
||||
int m[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() };
|
||||
size_t sz = sizeof (info);
|
||||
sysctl (m, 4, &info, &sz, 0, 0);
|
||||
testResult = ((info.kp_proc.p_flag & P_TRACED) != 0) ? 1 : -1;
|
||||
}
|
||||
|
||||
return testResult > 0;
|
||||
}
|
||||
|
||||
BEAST_API bool BEAST_CALLTYPE Process::isRunningUnderDebugger()
|
||||
{
|
||||
return beast_isRunningUnderDebugger();
|
||||
}
|
||||
153
modules/beast_core/native/beast_osx_ObjCHelpers.h
Normal file
153
modules/beast_core/native/beast_osx_ObjCHelpers.h
Normal file
@@ -0,0 +1,153 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_OSX_OBJCHELPERS_BEASTHEADER
|
||||
#define BEAST_OSX_OBJCHELPERS_BEASTHEADER
|
||||
|
||||
|
||||
/* This file contains a few helper functions that are used internally but which
|
||||
need to be kept away from the public headers because they use obj-C symbols.
|
||||
*/
|
||||
namespace
|
||||
{
|
||||
//==============================================================================
|
||||
static inline String nsStringToBeast (NSString* s)
|
||||
{
|
||||
return CharPointer_UTF8 ([s UTF8String]);
|
||||
}
|
||||
|
||||
static inline NSString* beastStringToNS (const String& s)
|
||||
{
|
||||
return [NSString stringWithUTF8String: s.toUTF8()];
|
||||
}
|
||||
|
||||
static inline NSString* nsStringLiteral (const char* const s) noexcept
|
||||
{
|
||||
return [NSString stringWithUTF8String: s];
|
||||
}
|
||||
|
||||
static inline NSString* nsEmptyString() noexcept
|
||||
{
|
||||
return [NSString string];
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
template <typename ObjectType>
|
||||
struct NSObjectRetainer
|
||||
{
|
||||
inline NSObjectRetainer (ObjectType* o) : object (o) { [object retain]; }
|
||||
inline ~NSObjectRetainer() { [object release]; }
|
||||
|
||||
ObjectType* object;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
template <typename SuperclassType>
|
||||
struct ObjCClass
|
||||
{
|
||||
ObjCClass (const char* nameRoot)
|
||||
: cls (objc_allocateClassPair ([SuperclassType class], getRandomisedName (nameRoot).toUTF8(), 0))
|
||||
{
|
||||
}
|
||||
|
||||
~ObjCClass()
|
||||
{
|
||||
objc_disposeClassPair (cls);
|
||||
}
|
||||
|
||||
void registerClass()
|
||||
{
|
||||
objc_registerClassPair (cls);
|
||||
}
|
||||
|
||||
SuperclassType* createInstance() const
|
||||
{
|
||||
return class_createInstance (cls, 0);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
void addIvar (const char* name)
|
||||
{
|
||||
BOOL b = class_addIvar (cls, name, sizeof (Type), (uint8_t) rint (log2 (sizeof (Type))), @encode (Type));
|
||||
bassert (b); (void) b;
|
||||
}
|
||||
|
||||
template <typename FunctionType>
|
||||
void addMethod (SEL selector, FunctionType callbackFn, const char* signature)
|
||||
{
|
||||
BOOL b = class_addMethod (cls, selector, (IMP) callbackFn, signature);
|
||||
bassert (b); (void) b;
|
||||
}
|
||||
|
||||
template <typename FunctionType>
|
||||
void addMethod (SEL selector, FunctionType callbackFn, const char* sig1, const char* sig2)
|
||||
{
|
||||
addMethod (selector, callbackFn, (String (sig1) + sig2).toUTF8());
|
||||
}
|
||||
|
||||
template <typename FunctionType>
|
||||
void addMethod (SEL selector, FunctionType callbackFn, const char* sig1, const char* sig2, const char* sig3)
|
||||
{
|
||||
addMethod (selector, callbackFn, (String (sig1) + sig2 + sig3).toUTF8());
|
||||
}
|
||||
|
||||
template <typename FunctionType>
|
||||
void addMethod (SEL selector, FunctionType callbackFn, const char* sig1, const char* sig2, const char* sig3, const char* sig4)
|
||||
{
|
||||
addMethod (selector, callbackFn, (String (sig1) + sig2 + sig3 + sig4).toUTF8());
|
||||
}
|
||||
|
||||
void addProtocol (Protocol* protocol)
|
||||
{
|
||||
BOOL b = class_addProtocol (cls, protocol);
|
||||
bassert (b); (void) b;
|
||||
}
|
||||
|
||||
static id sendSuperclassMessage (id self, SEL selector)
|
||||
{
|
||||
objc_super s = { self, [SuperclassType class] };
|
||||
return objc_msgSendSuper (&s, selector);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
static Type getIvar (id self, const char* name)
|
||||
{
|
||||
void* v = nullptr;
|
||||
object_getInstanceVariable (self, name, &v);
|
||||
return static_cast <Type> (v);
|
||||
}
|
||||
|
||||
Class cls;
|
||||
|
||||
private:
|
||||
static String getRandomisedName (const char* root)
|
||||
{
|
||||
return root + String::toHexString (beast::Random::getSystemRandom().nextInt64());
|
||||
}
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE (ObjCClass)
|
||||
};
|
||||
|
||||
|
||||
#endif // BEAST_OSX_OBJCHELPERS_BEASTHEADER
|
||||
214
modules/beast_core/native/beast_posix_NamedPipe.cpp
Normal file
214
modules/beast_core/native/beast_posix_NamedPipe.cpp
Normal file
@@ -0,0 +1,214 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
class NamedPipe::Pimpl
|
||||
{
|
||||
public:
|
||||
Pimpl (const String& pipePath, bool createPipe)
|
||||
: pipeInName (pipePath + "_in"),
|
||||
pipeOutName (pipePath + "_out"),
|
||||
pipeIn (-1), pipeOut (-1),
|
||||
createdPipe (createPipe),
|
||||
stopReadOperation (false)
|
||||
{
|
||||
signal (SIGPIPE, signalHandler);
|
||||
siginterrupt (SIGPIPE, 1);
|
||||
}
|
||||
|
||||
~Pimpl()
|
||||
{
|
||||
if (pipeIn != -1) ::close (pipeIn);
|
||||
if (pipeOut != -1) ::close (pipeOut);
|
||||
|
||||
if (createdPipe)
|
||||
{
|
||||
unlink (pipeInName.toUTF8());
|
||||
unlink (pipeOutName.toUTF8());
|
||||
}
|
||||
}
|
||||
|
||||
int read (char* destBuffer, int maxBytesToRead, int timeOutMilliseconds)
|
||||
{
|
||||
const uint32 timeoutEnd = getTimeoutEnd (timeOutMilliseconds);
|
||||
|
||||
if (pipeIn == -1)
|
||||
{
|
||||
pipeIn = openPipe (createdPipe ? pipeInName : pipeOutName, O_RDWR | O_NONBLOCK, timeoutEnd);
|
||||
|
||||
if (pipeIn == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int bytesRead = 0;
|
||||
|
||||
while (bytesRead < maxBytesToRead)
|
||||
{
|
||||
const int bytesThisTime = maxBytesToRead - bytesRead;
|
||||
const int numRead = (int) ::read (pipeIn, destBuffer, (size_t) bytesThisTime);
|
||||
|
||||
if (numRead <= 0)
|
||||
{
|
||||
if (errno != EWOULDBLOCK || stopReadOperation || hasExpired (timeoutEnd))
|
||||
return -1;
|
||||
|
||||
const int maxWaitingTime = 30;
|
||||
waitForInput (pipeIn, timeoutEnd == 0 ? maxWaitingTime
|
||||
: bmin (maxWaitingTime,
|
||||
(int) (timeoutEnd - Time::getMillisecondCounter())));
|
||||
continue;
|
||||
}
|
||||
|
||||
bytesRead += numRead;
|
||||
destBuffer += numRead;
|
||||
}
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
int write (const char* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
|
||||
{
|
||||
const uint32 timeoutEnd = getTimeoutEnd (timeOutMilliseconds);
|
||||
|
||||
if (pipeOut == -1)
|
||||
{
|
||||
pipeOut = openPipe (createdPipe ? pipeOutName : pipeInName, O_WRONLY, timeoutEnd);
|
||||
|
||||
if (pipeOut == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int bytesWritten = 0;
|
||||
|
||||
while (bytesWritten < numBytesToWrite && ! hasExpired (timeoutEnd))
|
||||
{
|
||||
const int bytesThisTime = numBytesToWrite - bytesWritten;
|
||||
const int numWritten = (int) ::write (pipeOut, sourceBuffer, (size_t) bytesThisTime);
|
||||
|
||||
if (numWritten <= 0)
|
||||
return -1;
|
||||
|
||||
bytesWritten += numWritten;
|
||||
sourceBuffer += numWritten;
|
||||
}
|
||||
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
bool createFifos() const
|
||||
{
|
||||
return (mkfifo (pipeInName .toUTF8(), 0666) == 0 || errno == EEXIST)
|
||||
&& (mkfifo (pipeOutName.toUTF8(), 0666) == 0 || errno == EEXIST);
|
||||
}
|
||||
|
||||
const String pipeInName, pipeOutName;
|
||||
int pipeIn, pipeOut;
|
||||
|
||||
const bool createdPipe;
|
||||
bool stopReadOperation;
|
||||
|
||||
private:
|
||||
static void signalHandler (int) {}
|
||||
|
||||
static uint32 getTimeoutEnd (const int timeOutMilliseconds)
|
||||
{
|
||||
return timeOutMilliseconds >= 0 ? Time::getMillisecondCounter() + (uint32) timeOutMilliseconds : 0;
|
||||
}
|
||||
|
||||
static bool hasExpired (const uint32 timeoutEnd)
|
||||
{
|
||||
return timeoutEnd != 0 && Time::getMillisecondCounter() >= timeoutEnd;
|
||||
}
|
||||
|
||||
int openPipe (const String& name, int flags, const uint32 timeoutEnd)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
const int p = ::open (name.toUTF8(), flags);
|
||||
|
||||
if (p != -1 || hasExpired (timeoutEnd) || stopReadOperation)
|
||||
return p;
|
||||
|
||||
Thread::sleep (2);
|
||||
}
|
||||
}
|
||||
|
||||
static void waitForInput (const int handle, const int timeoutMsecs) noexcept
|
||||
{
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = timeoutMsecs / 1000;
|
||||
timeout.tv_usec = (timeoutMsecs % 1000) * 1000;
|
||||
|
||||
fd_set rset;
|
||||
FD_ZERO (&rset);
|
||||
FD_SET (handle, &rset);
|
||||
|
||||
select (handle + 1, &rset, nullptr, 0, &timeout);
|
||||
}
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
|
||||
};
|
||||
|
||||
void NamedPipe::close()
|
||||
{
|
||||
if (pimpl != nullptr)
|
||||
{
|
||||
pimpl->stopReadOperation = true;
|
||||
|
||||
char buffer[1] = { 0 };
|
||||
ssize_t done = ::write (pimpl->pipeIn, buffer, 1);
|
||||
(void) done;
|
||||
|
||||
ScopedWriteLock sl (lock);
|
||||
pimpl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool NamedPipe::openInternal (const String& pipeName, const bool createPipe)
|
||||
{
|
||||
#if BEAST_IOS
|
||||
pimpl = new Pimpl (File::getSpecialLocation (File::tempDirectory)
|
||||
.getChildFile (File::createLegalFileName (pipeName)).getFullPathName(), createPipe);
|
||||
#else
|
||||
pimpl = new Pimpl ("/tmp/" + File::createLegalFileName (pipeName), createPipe);
|
||||
#endif
|
||||
|
||||
if (createPipe && ! pimpl->createFifos())
|
||||
{
|
||||
pimpl = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int NamedPipe::read (void* destBuffer, int maxBytesToRead, int timeOutMilliseconds)
|
||||
{
|
||||
ScopedReadLock sl (lock);
|
||||
return pimpl != nullptr ? pimpl->read (static_cast <char*> (destBuffer), maxBytesToRead, timeOutMilliseconds) : -1;
|
||||
}
|
||||
|
||||
int NamedPipe::write (const void* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
|
||||
{
|
||||
ScopedReadLock sl (lock);
|
||||
return pimpl != nullptr ? pimpl->write (static_cast <const char*> (sourceBuffer), numBytesToWrite, timeOutMilliseconds) : -1;
|
||||
}
|
||||
1251
modules/beast_core/native/beast_posix_SharedCode.h
Normal file
1251
modules/beast_core/native/beast_posix_SharedCode.h
Normal file
File diff suppressed because it is too large
Load Diff
165
modules/beast_core/native/beast_win32_ComSmartPtr.h
Normal file
165
modules/beast_core/native/beast_win32_ComSmartPtr.h
Normal file
@@ -0,0 +1,165 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_WIN32_COMSMARTPTR_BEASTHEADER
|
||||
#define BEAST_WIN32_COMSMARTPTR_BEASTHEADER
|
||||
|
||||
#ifndef _MSC_VER
|
||||
template<typename Type> struct UUIDGetter { static CLSID get() { jassertfalse; return CLSID(); } };
|
||||
#define __uuidof(x) UUIDGetter<x>::get()
|
||||
#endif
|
||||
|
||||
inline GUID uuidFromString (const char* const s) noexcept
|
||||
{
|
||||
unsigned long p0;
|
||||
unsigned int p1, p2, p3, p4, p5, p6, p7, p8, p9, p10;
|
||||
|
||||
#ifndef _MSC_VER
|
||||
sscanf
|
||||
#else
|
||||
sscanf_s
|
||||
#endif
|
||||
(s, "%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
||||
&p0, &p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8, &p9, &p10);
|
||||
|
||||
GUID g = { p0, (uint16) p1, (uint16) p2, { (uint8) p3, (uint8) p4, (uint8) p5, (uint8) p6,
|
||||
(uint8) p7, (uint8) p8, (uint8) p9, (uint8) p10 }};
|
||||
return g;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** A simple COM smart pointer.
|
||||
*/
|
||||
template <class ComClass>
|
||||
class ComSmartPtr
|
||||
{
|
||||
public:
|
||||
ComSmartPtr() throw() : p (0) {}
|
||||
ComSmartPtr (ComClass* const obj) : p (obj) { if (p) p->AddRef(); }
|
||||
ComSmartPtr (const ComSmartPtr<ComClass>& other) : p (other.p) { if (p) p->AddRef(); }
|
||||
~ComSmartPtr() { release(); }
|
||||
|
||||
operator ComClass*() const throw() { return p; }
|
||||
ComClass& operator*() const throw() { return *p; }
|
||||
ComClass* operator->() const throw() { return p; }
|
||||
|
||||
ComSmartPtr& operator= (ComClass* const newP)
|
||||
{
|
||||
if (newP != 0) newP->AddRef();
|
||||
release();
|
||||
p = newP;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ComSmartPtr& operator= (const ComSmartPtr<ComClass>& newP) { return operator= (newP.p); }
|
||||
|
||||
// Releases and nullifies this pointer and returns its address
|
||||
ComClass** resetAndGetPointerAddress()
|
||||
{
|
||||
release();
|
||||
p = 0;
|
||||
return &p;
|
||||
}
|
||||
|
||||
HRESULT CoCreateInstance (REFCLSID classUUID, DWORD dwClsContext = CLSCTX_INPROC_SERVER)
|
||||
{
|
||||
HRESULT hr = ::CoCreateInstance (classUUID, 0, dwClsContext, __uuidof (ComClass), (void**) resetAndGetPointerAddress());
|
||||
bassert (hr != CO_E_NOTINITIALIZED); // You haven't called CoInitialize for the current thread!
|
||||
return hr;
|
||||
}
|
||||
|
||||
template <class OtherComClass>
|
||||
HRESULT QueryInterface (REFCLSID classUUID, ComSmartPtr<OtherComClass>& destObject) const
|
||||
{
|
||||
if (p == 0)
|
||||
return E_POINTER;
|
||||
|
||||
return p->QueryInterface (classUUID, (void**) destObject.resetAndGetPointerAddress());
|
||||
}
|
||||
|
||||
template <class OtherComClass>
|
||||
HRESULT QueryInterface (ComSmartPtr<OtherComClass>& destObject) const
|
||||
{
|
||||
return this->QueryInterface (__uuidof (OtherComClass), destObject);
|
||||
}
|
||||
|
||||
private:
|
||||
ComClass* p;
|
||||
|
||||
void release() { if (p != 0) p->Release(); }
|
||||
|
||||
ComClass** operator&() throw(); // private to avoid it being used accidentally
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
#define BEAST_COMRESULT HRESULT __stdcall
|
||||
|
||||
//==============================================================================
|
||||
template <class ComClass>
|
||||
class ComBaseClassHelperBase : public ComClass
|
||||
{
|
||||
public:
|
||||
ComBaseClassHelperBase (unsigned int initialRefCount) : refCount (initialRefCount) {}
|
||||
virtual ~ComBaseClassHelperBase() {}
|
||||
|
||||
ULONG __stdcall AddRef() { return ++refCount; }
|
||||
ULONG __stdcall Release() { const ULONG r = --refCount; if (r == 0) delete this; return r; }
|
||||
|
||||
protected:
|
||||
ULONG refCount;
|
||||
|
||||
BEAST_COMRESULT QueryInterface (REFIID refId, void** result)
|
||||
{
|
||||
if (refId == IID_IUnknown)
|
||||
return castToType <IUnknown> (result);
|
||||
|
||||
*result = 0;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
BEAST_COMRESULT castToType (void** result)
|
||||
{
|
||||
this->AddRef(); *result = dynamic_cast <Type*> (this); return S_OK;
|
||||
}
|
||||
};
|
||||
|
||||
/** Handy base class for writing COM objects, providing ref-counting and a basic QueryInterface method.
|
||||
*/
|
||||
template <class ComClass>
|
||||
class ComBaseClassHelper : public ComBaseClassHelperBase <ComClass>
|
||||
{
|
||||
public:
|
||||
ComBaseClassHelper (unsigned int initialRefCount = 1) : ComBaseClassHelperBase <ComClass> (initialRefCount) {}
|
||||
~ComBaseClassHelper() {}
|
||||
|
||||
BEAST_COMRESULT QueryInterface (REFIID refId, void** result)
|
||||
{
|
||||
if (refId == __uuidof (ComClass))
|
||||
return this->template castToType <ComClass> (result);
|
||||
|
||||
return ComBaseClassHelperBase <ComClass>::QueryInterface (refId, result);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // BEAST_WIN32_COMSMARTPTR_BEASTHEADER
|
||||
956
modules/beast_core/native/beast_win32_Files.cpp
Normal file
956
modules/beast_core/native/beast_win32_Files.cpp
Normal file
@@ -0,0 +1,956 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef INVALID_FILE_ATTRIBUTES
|
||||
#define INVALID_FILE_ATTRIBUTES ((DWORD) -1)
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
namespace WindowsFileHelpers
|
||||
{
|
||||
DWORD getAtts (const String& path)
|
||||
{
|
||||
return GetFileAttributes (path.toWideCharPointer());
|
||||
}
|
||||
|
||||
int64 fileTimeToTime (const FILETIME* const ft)
|
||||
{
|
||||
static_bassert (sizeof (ULARGE_INTEGER) == sizeof (FILETIME)); // tell me if this fails!
|
||||
|
||||
return (int64) ((reinterpret_cast<const ULARGE_INTEGER*> (ft)->QuadPart - literal64bit (116444736000000000)) / 10000);
|
||||
}
|
||||
|
||||
FILETIME* timeToFileTime (const int64 time, FILETIME* const ft) noexcept
|
||||
{
|
||||
if (time <= 0)
|
||||
return nullptr;
|
||||
|
||||
reinterpret_cast<ULARGE_INTEGER*> (ft)->QuadPart = (ULONGLONG) (time * 10000 + literal64bit (116444736000000000));
|
||||
return ft;
|
||||
}
|
||||
|
||||
String getDriveFromPath (String path)
|
||||
{
|
||||
if (path.isNotEmpty() && path[1] == ':' && path[2] == 0)
|
||||
path << '\\';
|
||||
|
||||
const size_t numBytes = CharPointer_UTF16::getBytesRequiredFor (path.getCharPointer()) + 4;
|
||||
HeapBlock<WCHAR> pathCopy;
|
||||
pathCopy.calloc (numBytes, 1);
|
||||
path.copyToUTF16 (pathCopy, numBytes);
|
||||
|
||||
if (PathStripToRoot (pathCopy))
|
||||
path = static_cast <const WCHAR*> (pathCopy);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
int64 getDiskSpaceInfo (const String& path, const bool total)
|
||||
{
|
||||
ULARGE_INTEGER spc, tot, totFree;
|
||||
|
||||
if (GetDiskFreeSpaceEx (getDriveFromPath (path).toWideCharPointer(), &spc, &tot, &totFree))
|
||||
return total ? (int64) tot.QuadPart
|
||||
: (int64) spc.QuadPart;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int getWindowsDriveType (const String& path)
|
||||
{
|
||||
return GetDriveType (getDriveFromPath (path).toWideCharPointer());
|
||||
}
|
||||
|
||||
File getSpecialFolderPath (int type)
|
||||
{
|
||||
WCHAR path [MAX_PATH + 256];
|
||||
|
||||
if (SHGetSpecialFolderPath (0, path, type, FALSE))
|
||||
return File (String (path));
|
||||
|
||||
return File::nonexistent;
|
||||
}
|
||||
|
||||
File getModuleFileName (HINSTANCE moduleHandle)
|
||||
{
|
||||
WCHAR dest [MAX_PATH + 256];
|
||||
dest[0] = 0;
|
||||
GetModuleFileName (moduleHandle, dest, (DWORD) numElementsInArray (dest));
|
||||
return File (String (dest));
|
||||
}
|
||||
|
||||
Result getResultForLastError()
|
||||
{
|
||||
TCHAR messageBuffer [256] = { 0 };
|
||||
|
||||
FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
nullptr, GetLastError(), MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
messageBuffer, (DWORD) numElementsInArray (messageBuffer) - 1, nullptr);
|
||||
|
||||
return Result::fail (String (messageBuffer));
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
const beast_wchar File::separator = '\\';
|
||||
const String File::separatorString ("\\");
|
||||
|
||||
|
||||
//==============================================================================
|
||||
bool File::exists() const
|
||||
{
|
||||
return fullPath.isNotEmpty()
|
||||
&& WindowsFileHelpers::getAtts (fullPath) != INVALID_FILE_ATTRIBUTES;
|
||||
}
|
||||
|
||||
bool File::existsAsFile() const
|
||||
{
|
||||
return fullPath.isNotEmpty()
|
||||
&& (WindowsFileHelpers::getAtts (fullPath) & FILE_ATTRIBUTE_DIRECTORY) == 0;
|
||||
}
|
||||
|
||||
bool File::isDirectory() const
|
||||
{
|
||||
const DWORD attr = WindowsFileHelpers::getAtts (fullPath);
|
||||
return ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) && (attr != INVALID_FILE_ATTRIBUTES);
|
||||
}
|
||||
|
||||
bool File::hasWriteAccess() const
|
||||
{
|
||||
if (exists())
|
||||
return (WindowsFileHelpers::getAtts (fullPath) & FILE_ATTRIBUTE_READONLY) == 0;
|
||||
|
||||
// on windows, it seems that even read-only directories can still be written into,
|
||||
// so checking the parent directory's permissions would return the wrong result..
|
||||
return true;
|
||||
}
|
||||
|
||||
bool File::setFileReadOnlyInternal (const bool shouldBeReadOnly) const
|
||||
{
|
||||
const DWORD oldAtts = WindowsFileHelpers::getAtts (fullPath);
|
||||
|
||||
if (oldAtts == INVALID_FILE_ATTRIBUTES)
|
||||
return false;
|
||||
|
||||
const DWORD newAtts = shouldBeReadOnly ? (oldAtts | FILE_ATTRIBUTE_READONLY)
|
||||
: (oldAtts & ~FILE_ATTRIBUTE_READONLY);
|
||||
return newAtts == oldAtts
|
||||
|| SetFileAttributes (fullPath.toWideCharPointer(), newAtts) != FALSE;
|
||||
}
|
||||
|
||||
bool File::isHidden() const
|
||||
{
|
||||
return (WindowsFileHelpers::getAtts (fullPath) & FILE_ATTRIBUTE_HIDDEN) != 0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool File::deleteFile() const
|
||||
{
|
||||
if (! exists())
|
||||
return true;
|
||||
|
||||
return isDirectory() ? RemoveDirectory (fullPath.toWideCharPointer()) != 0
|
||||
: DeleteFile (fullPath.toWideCharPointer()) != 0;
|
||||
}
|
||||
|
||||
bool File::moveToTrash() const
|
||||
{
|
||||
if (! exists())
|
||||
return true;
|
||||
|
||||
// The string we pass in must be double null terminated..
|
||||
const size_t numBytes = CharPointer_UTF16::getBytesRequiredFor (fullPath.getCharPointer()) + 8;
|
||||
HeapBlock<WCHAR> doubleNullTermPath;
|
||||
doubleNullTermPath.calloc (numBytes, 1);
|
||||
fullPath.copyToUTF16 (doubleNullTermPath, numBytes);
|
||||
|
||||
SHFILEOPSTRUCT fos = { 0 };
|
||||
fos.wFunc = FO_DELETE;
|
||||
fos.pFrom = doubleNullTermPath;
|
||||
fos.fFlags = FOF_ALLOWUNDO | FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION
|
||||
| FOF_NOCONFIRMMKDIR | FOF_RENAMEONCOLLISION;
|
||||
|
||||
return SHFileOperation (&fos) == 0;
|
||||
}
|
||||
|
||||
bool File::copyInternal (const File& dest) const
|
||||
{
|
||||
return CopyFile (fullPath.toWideCharPointer(), dest.getFullPathName().toWideCharPointer(), false) != 0;
|
||||
}
|
||||
|
||||
bool File::moveInternal (const File& dest) const
|
||||
{
|
||||
return MoveFile (fullPath.toWideCharPointer(), dest.getFullPathName().toWideCharPointer()) != 0;
|
||||
}
|
||||
|
||||
Result File::createDirectoryInternal (const String& fileName) const
|
||||
{
|
||||
return CreateDirectory (fileName.toWideCharPointer(), 0) ? Result::ok()
|
||||
: WindowsFileHelpers::getResultForLastError();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
int64 beast_fileSetPosition (void* handle, int64 pos)
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
li.QuadPart = pos;
|
||||
li.LowPart = SetFilePointer ((HANDLE) handle, (LONG) li.LowPart, &li.HighPart, FILE_BEGIN); // (returns -1 if it fails)
|
||||
return li.QuadPart;
|
||||
}
|
||||
|
||||
void FileInputStream::openHandle()
|
||||
{
|
||||
HANDLE h = CreateFile (file.getFullPathName().toWideCharPointer(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0);
|
||||
|
||||
if (h != INVALID_HANDLE_VALUE)
|
||||
fileHandle = (void*) h;
|
||||
else
|
||||
status = WindowsFileHelpers::getResultForLastError();
|
||||
}
|
||||
|
||||
void FileInputStream::closeHandle()
|
||||
{
|
||||
CloseHandle ((HANDLE) fileHandle);
|
||||
}
|
||||
|
||||
size_t FileInputStream::readInternal (void* buffer, size_t numBytes)
|
||||
{
|
||||
if (fileHandle != 0)
|
||||
{
|
||||
DWORD actualNum = 0;
|
||||
if (! ReadFile ((HANDLE) fileHandle, buffer, (DWORD) numBytes, &actualNum, 0))
|
||||
status = WindowsFileHelpers::getResultForLastError();
|
||||
|
||||
return (size_t) actualNum;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void FileOutputStream::openHandle()
|
||||
{
|
||||
HANDLE h = CreateFile (file.getFullPathName().toWideCharPointer(), GENERIC_WRITE, FILE_SHARE_READ, 0,
|
||||
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
|
||||
if (h != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
li.QuadPart = 0;
|
||||
li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_END);
|
||||
|
||||
if (li.LowPart != INVALID_SET_FILE_POINTER)
|
||||
{
|
||||
fileHandle = (void*) h;
|
||||
currentPosition = li.QuadPart;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
status = WindowsFileHelpers::getResultForLastError();
|
||||
}
|
||||
|
||||
void FileOutputStream::closeHandle()
|
||||
{
|
||||
CloseHandle ((HANDLE) fileHandle);
|
||||
}
|
||||
|
||||
ssize_t FileOutputStream::writeInternal (const void* buffer, size_t numBytes)
|
||||
{
|
||||
if (fileHandle != nullptr)
|
||||
{
|
||||
DWORD actualNum = 0;
|
||||
if (! WriteFile ((HANDLE) fileHandle, buffer, (DWORD) numBytes, &actualNum, 0))
|
||||
status = WindowsFileHelpers::getResultForLastError();
|
||||
|
||||
return (ssize_t) actualNum;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FileOutputStream::flushInternal()
|
||||
{
|
||||
if (fileHandle != nullptr)
|
||||
if (! FlushFileBuffers ((HANDLE) fileHandle))
|
||||
status = WindowsFileHelpers::getResultForLastError();
|
||||
}
|
||||
|
||||
Result FileOutputStream::truncate()
|
||||
{
|
||||
if (fileHandle == nullptr)
|
||||
return status;
|
||||
|
||||
flush();
|
||||
return SetEndOfFile ((HANDLE) fileHandle) ? Result::ok()
|
||||
: WindowsFileHelpers::getResultForLastError();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void MemoryMappedFile::openInternal (const File& file, AccessMode mode)
|
||||
{
|
||||
bassert (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;
|
||||
|
||||
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 | FILE_FLAG_SEQUENTIAL_SCAN, 0);
|
||||
|
||||
if (h != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
fileHandle = (void*) h;
|
||||
|
||||
HANDLE mappingHandle = CreateFileMapping (h, 0, protect, (DWORD) (range.getEnd() >> 32), (DWORD) range.getEnd(), 0);
|
||||
|
||||
if (mappingHandle != 0)
|
||||
{
|
||||
address = MapViewOfFile (mappingHandle, access, (DWORD) (range.getStart() >> 32),
|
||||
(DWORD) range.getStart(), (SIZE_T) range.getLength());
|
||||
|
||||
if (address == nullptr)
|
||||
range = Range<int64>();
|
||||
|
||||
CloseHandle (mappingHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MemoryMappedFile::~MemoryMappedFile()
|
||||
{
|
||||
if (address != nullptr)
|
||||
UnmapViewOfFile (address);
|
||||
|
||||
if (fileHandle != nullptr)
|
||||
CloseHandle ((HANDLE) fileHandle);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
int64 File::getSize() const
|
||||
{
|
||||
WIN32_FILE_ATTRIBUTE_DATA attributes;
|
||||
|
||||
if (GetFileAttributesEx (fullPath.toWideCharPointer(), GetFileExInfoStandard, &attributes))
|
||||
return (((int64) attributes.nFileSizeHigh) << 32) | attributes.nFileSizeLow;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void File::getFileTimesInternal (int64& modificationTime, int64& accessTime, int64& creationTime) const
|
||||
{
|
||||
using namespace WindowsFileHelpers;
|
||||
WIN32_FILE_ATTRIBUTE_DATA attributes;
|
||||
|
||||
if (GetFileAttributesEx (fullPath.toWideCharPointer(), GetFileExInfoStandard, &attributes))
|
||||
{
|
||||
modificationTime = fileTimeToTime (&attributes.ftLastWriteTime);
|
||||
creationTime = fileTimeToTime (&attributes.ftCreationTime);
|
||||
accessTime = fileTimeToTime (&attributes.ftLastAccessTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
creationTime = accessTime = modificationTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool File::setFileTimesInternal (int64 modificationTime, int64 accessTime, int64 creationTime) const
|
||||
{
|
||||
using namespace WindowsFileHelpers;
|
||||
|
||||
bool ok = false;
|
||||
HANDLE h = CreateFile (fullPath.toWideCharPointer(), GENERIC_WRITE, FILE_SHARE_READ, 0,
|
||||
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
|
||||
if (h != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
FILETIME m, a, c;
|
||||
|
||||
ok = SetFileTime (h,
|
||||
timeToFileTime (creationTime, &c),
|
||||
timeToFileTime (accessTime, &a),
|
||||
timeToFileTime (modificationTime, &m)) != 0;
|
||||
|
||||
CloseHandle (h);
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void File::findFileSystemRoots (Array<File>& destArray)
|
||||
{
|
||||
TCHAR buffer [2048] = { 0 };
|
||||
GetLogicalDriveStrings (2048, buffer);
|
||||
|
||||
const TCHAR* n = buffer;
|
||||
StringArray roots;
|
||||
|
||||
while (*n != 0)
|
||||
{
|
||||
roots.add (String (n));
|
||||
|
||||
while (*n++ != 0)
|
||||
{}
|
||||
}
|
||||
|
||||
roots.sort (true);
|
||||
|
||||
for (int i = 0; i < roots.size(); ++i)
|
||||
destArray.add (roots [i]);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String File::getVolumeLabel() const
|
||||
{
|
||||
TCHAR dest[64];
|
||||
if (! GetVolumeInformation (WindowsFileHelpers::getDriveFromPath (getFullPathName()).toWideCharPointer(), dest,
|
||||
(DWORD) numElementsInArray (dest), 0, 0, 0, 0, 0))
|
||||
dest[0] = 0;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
int File::getVolumeSerialNumber() const
|
||||
{
|
||||
TCHAR dest[64];
|
||||
DWORD serialNum;
|
||||
|
||||
if (! GetVolumeInformation (WindowsFileHelpers::getDriveFromPath (getFullPathName()).toWideCharPointer(), dest,
|
||||
(DWORD) numElementsInArray (dest), &serialNum, 0, 0, 0, 0))
|
||||
return 0;
|
||||
|
||||
return (int) serialNum;
|
||||
}
|
||||
|
||||
int64 File::getBytesFreeOnVolume() const
|
||||
{
|
||||
return WindowsFileHelpers::getDiskSpaceInfo (getFullPathName(), false);
|
||||
}
|
||||
|
||||
int64 File::getVolumeTotalSize() const
|
||||
{
|
||||
return WindowsFileHelpers::getDiskSpaceInfo (getFullPathName(), true);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool File::isOnCDRomDrive() const
|
||||
{
|
||||
return WindowsFileHelpers::getWindowsDriveType (getFullPathName()) == DRIVE_CDROM;
|
||||
}
|
||||
|
||||
bool File::isOnHardDisk() const
|
||||
{
|
||||
if (fullPath.isEmpty())
|
||||
return false;
|
||||
|
||||
const unsigned int n = WindowsFileHelpers::getWindowsDriveType (getFullPathName());
|
||||
|
||||
if (fullPath.toLowerCase()[0] <= 'b' && fullPath[1] == ':')
|
||||
return n != DRIVE_REMOVABLE;
|
||||
|
||||
return n != DRIVE_CDROM && n != DRIVE_REMOTE;
|
||||
}
|
||||
|
||||
bool File::isOnRemovableDrive() const
|
||||
{
|
||||
if (fullPath.isEmpty())
|
||||
return false;
|
||||
|
||||
const unsigned int n = WindowsFileHelpers::getWindowsDriveType (getFullPathName());
|
||||
|
||||
return n == DRIVE_CDROM
|
||||
|| n == DRIVE_REMOTE
|
||||
|| n == DRIVE_REMOVABLE
|
||||
|| n == DRIVE_RAMDISK;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
File BEAST_CALLTYPE File::getSpecialLocation (const SpecialLocationType type)
|
||||
{
|
||||
int csidlType = 0;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case userHomeDirectory: csidlType = CSIDL_PROFILE; break;
|
||||
case userDocumentsDirectory: csidlType = CSIDL_PERSONAL; break;
|
||||
case userDesktopDirectory: csidlType = CSIDL_DESKTOP; break;
|
||||
case userApplicationDataDirectory: csidlType = CSIDL_APPDATA; break;
|
||||
case commonApplicationDataDirectory: csidlType = CSIDL_COMMON_APPDATA; break;
|
||||
case globalApplicationsDirectory: csidlType = CSIDL_PROGRAM_FILES; break;
|
||||
case userMusicDirectory: csidlType = 0x0d; /*CSIDL_MYMUSIC*/ break;
|
||||
case userMoviesDirectory: csidlType = 0x0e; /*CSIDL_MYVIDEO*/ break;
|
||||
case userPicturesDirectory: csidlType = 0x27; /*CSIDL_MYPICTURES*/ break;
|
||||
|
||||
case tempDirectory:
|
||||
{
|
||||
WCHAR dest [2048];
|
||||
dest[0] = 0;
|
||||
GetTempPath ((DWORD) numElementsInArray (dest), dest);
|
||||
return File (String (dest));
|
||||
}
|
||||
|
||||
case invokedExecutableFile:
|
||||
case currentExecutableFile:
|
||||
case currentApplicationFile:
|
||||
return WindowsFileHelpers::getModuleFileName ((HINSTANCE) Process::getCurrentModuleInstanceHandle());
|
||||
|
||||
case hostApplicationPath:
|
||||
return WindowsFileHelpers::getModuleFileName (0);
|
||||
|
||||
default:
|
||||
jassertfalse; // unknown type?
|
||||
return File::nonexistent;
|
||||
}
|
||||
|
||||
return WindowsFileHelpers::getSpecialFolderPath (csidlType);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
File File::getCurrentWorkingDirectory()
|
||||
{
|
||||
WCHAR dest [MAX_PATH + 256];
|
||||
dest[0] = 0;
|
||||
GetCurrentDirectory ((DWORD) numElementsInArray (dest), dest);
|
||||
return File (String (dest));
|
||||
}
|
||||
|
||||
bool File::setAsCurrentWorkingDirectory() const
|
||||
{
|
||||
return SetCurrentDirectory (getFullPathName().toWideCharPointer()) != FALSE;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String File::getVersion() const
|
||||
{
|
||||
String result;
|
||||
|
||||
DWORD handle = 0;
|
||||
DWORD bufferSize = GetFileVersionInfoSize (getFullPathName().toWideCharPointer(), &handle);
|
||||
HeapBlock<char> buffer;
|
||||
buffer.calloc (bufferSize);
|
||||
|
||||
if (GetFileVersionInfo (getFullPathName().toWideCharPointer(), 0, bufferSize, buffer))
|
||||
{
|
||||
VS_FIXEDFILEINFO* vffi;
|
||||
UINT len = 0;
|
||||
|
||||
if (VerQueryValue (buffer, (LPTSTR) _T("\\"), (LPVOID*) &vffi, &len))
|
||||
{
|
||||
result << (int) HIWORD (vffi->dwFileVersionMS) << '.'
|
||||
<< (int) LOWORD (vffi->dwFileVersionMS) << '.'
|
||||
<< (int) HIWORD (vffi->dwFileVersionLS) << '.'
|
||||
<< (int) LOWORD (vffi->dwFileVersionLS);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
File File::getLinkedTarget() const
|
||||
{
|
||||
File result (*this);
|
||||
String p (getFullPathName());
|
||||
|
||||
if (! exists())
|
||||
p += ".lnk";
|
||||
else if (! hasFileExtension (".lnk"))
|
||||
return result;
|
||||
|
||||
ComSmartPtr <IShellLink> shellLink;
|
||||
ComSmartPtr <IPersistFile> persistFile;
|
||||
|
||||
if (SUCCEEDED (shellLink.CoCreateInstance (CLSID_ShellLink))
|
||||
&& SUCCEEDED (shellLink.QueryInterface (persistFile))
|
||||
&& SUCCEEDED (persistFile->Load (p.toWideCharPointer(), STGM_READ))
|
||||
&& SUCCEEDED (shellLink->Resolve (0, SLR_ANY_MATCH | SLR_NO_UI)))
|
||||
{
|
||||
WIN32_FIND_DATA winFindData;
|
||||
WCHAR resolvedPath [MAX_PATH];
|
||||
|
||||
if (SUCCEEDED (shellLink->GetPath (resolvedPath, MAX_PATH, &winFindData, SLGP_UNCPRIORITY)))
|
||||
result = File (resolvedPath);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool File::createLink (const String& description, const File& linkFileToCreate) const
|
||||
{
|
||||
linkFileToCreate.deleteFile();
|
||||
|
||||
ComSmartPtr <IShellLink> shellLink;
|
||||
ComSmartPtr <IPersistFile> persistFile;
|
||||
|
||||
return SUCCEEDED (shellLink.CoCreateInstance (CLSID_ShellLink))
|
||||
&& SUCCEEDED (shellLink->SetPath (getFullPathName().toWideCharPointer()))
|
||||
&& SUCCEEDED (shellLink->SetDescription (description.toWideCharPointer()))
|
||||
&& SUCCEEDED (shellLink.QueryInterface (persistFile))
|
||||
&& SUCCEEDED (persistFile->Save (linkFileToCreate.getFullPathName().toWideCharPointer(), TRUE));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class DirectoryIterator::NativeIterator::Pimpl
|
||||
{
|
||||
public:
|
||||
Pimpl (const File& directory, const String& wildCard)
|
||||
: directoryWithWildCard (File::addTrailingSeparator (directory.getFullPathName()) + wildCard),
|
||||
handle (INVALID_HANDLE_VALUE)
|
||||
{
|
||||
}
|
||||
|
||||
~Pimpl()
|
||||
{
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
FindClose (handle);
|
||||
}
|
||||
|
||||
bool next (String& filenameFound,
|
||||
bool* const isDir, bool* const isHidden, int64* const fileSize,
|
||||
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||
{
|
||||
using namespace WindowsFileHelpers;
|
||||
WIN32_FIND_DATA findData;
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
handle = FindFirstFile (directoryWithWildCard.toWideCharPointer(), &findData);
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FindNextFile (handle, &findData) == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
filenameFound = findData.cFileName;
|
||||
|
||||
if (isDir != nullptr) *isDir = ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
|
||||
if (isHidden != nullptr) *isHidden = ((findData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0);
|
||||
if (isReadOnly != nullptr) *isReadOnly = ((findData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0);
|
||||
if (fileSize != nullptr) *fileSize = findData.nFileSizeLow + (((int64) findData.nFileSizeHigh) << 32);
|
||||
if (modTime != nullptr) *modTime = Time (fileTimeToTime (&findData.ftLastWriteTime));
|
||||
if (creationTime != nullptr) *creationTime = Time (fileTimeToTime (&findData.ftCreationTime));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
const String directoryWithWildCard;
|
||||
HANDLE handle;
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
|
||||
};
|
||||
|
||||
DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildCard)
|
||||
: pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildCard))
|
||||
{
|
||||
}
|
||||
|
||||
DirectoryIterator::NativeIterator::~NativeIterator()
|
||||
{
|
||||
}
|
||||
|
||||
bool DirectoryIterator::NativeIterator::next (String& filenameFound,
|
||||
bool* const isDir, bool* const isHidden, int64* const fileSize,
|
||||
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||
{
|
||||
return pimpl->next (filenameFound, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
bool Process::openDocument (const String& fileName, const String& parameters)
|
||||
{
|
||||
HINSTANCE hInstance = 0;
|
||||
|
||||
BEAST_TRY
|
||||
{
|
||||
hInstance = ShellExecute (0, 0, fileName.toWideCharPointer(),
|
||||
parameters.toWideCharPointer(), 0, SW_SHOWDEFAULT);
|
||||
}
|
||||
BEAST_CATCH_ALL
|
||||
|
||||
return hInstance > (HINSTANCE) 32;
|
||||
}
|
||||
|
||||
void File::revealToUser() const
|
||||
{
|
||||
DynamicLibrary dll ("Shell32.dll");
|
||||
BEAST_LOAD_WINAPI_FUNCTION (dll, ILCreateFromPathW, ilCreateFromPathW, ITEMIDLIST*, (LPCWSTR))
|
||||
BEAST_LOAD_WINAPI_FUNCTION (dll, ILFree, ilFree, void, (ITEMIDLIST*))
|
||||
BEAST_LOAD_WINAPI_FUNCTION (dll, SHOpenFolderAndSelectItems, shOpenFolderAndSelectItems, HRESULT, (ITEMIDLIST*, UINT, void*, DWORD))
|
||||
|
||||
if (ilCreateFromPathW != nullptr && shOpenFolderAndSelectItems != nullptr && ilFree != nullptr)
|
||||
{
|
||||
if (ITEMIDLIST* const itemIDList = ilCreateFromPathW (fullPath.toWideCharPointer()))
|
||||
{
|
||||
shOpenFolderAndSelectItems (itemIDList, 0, nullptr, 0);
|
||||
ilFree (itemIDList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class NamedPipe::Pimpl
|
||||
{
|
||||
public:
|
||||
Pimpl (const String& pipeName, const bool createPipe)
|
||||
: filename ("\\\\.\\pipe\\" + File::createLegalFileName (pipeName)),
|
||||
pipeH (INVALID_HANDLE_VALUE),
|
||||
cancelEvent (CreateEvent (0, FALSE, FALSE, 0)),
|
||||
connected (false), ownsPipe (createPipe), shouldStop (false)
|
||||
{
|
||||
if (createPipe)
|
||||
pipeH = CreateNamedPipe (filename.toWideCharPointer(),
|
||||
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0,
|
||||
PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, 0);
|
||||
}
|
||||
|
||||
~Pimpl()
|
||||
{
|
||||
disconnectPipe();
|
||||
|
||||
if (pipeH != INVALID_HANDLE_VALUE)
|
||||
CloseHandle (pipeH);
|
||||
|
||||
CloseHandle (cancelEvent);
|
||||
}
|
||||
|
||||
bool connect (const int timeOutMs)
|
||||
{
|
||||
if (! ownsPipe)
|
||||
{
|
||||
if (pipeH != INVALID_HANDLE_VALUE)
|
||||
return true;
|
||||
|
||||
const Time timeOutEnd (Time::getCurrentTime() + RelativeTime::milliseconds (timeOutMs));
|
||||
|
||||
for (;;)
|
||||
{
|
||||
{
|
||||
const ScopedLock sl (createFileLock);
|
||||
|
||||
if (pipeH == INVALID_HANDLE_VALUE)
|
||||
pipeH = CreateFile (filename.toWideCharPointer(),
|
||||
GENERIC_READ | GENERIC_WRITE, 0, 0,
|
||||
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
|
||||
}
|
||||
|
||||
if (pipeH != INVALID_HANDLE_VALUE)
|
||||
return true;
|
||||
|
||||
if (shouldStop || (timeOutMs >= 0 && Time::getCurrentTime() > timeOutEnd))
|
||||
return false;
|
||||
|
||||
Thread::sleep (1);
|
||||
}
|
||||
}
|
||||
|
||||
if (! connected)
|
||||
{
|
||||
OverlappedEvent over;
|
||||
|
||||
if (ConnectNamedPipe (pipeH, &over.over) == 0)
|
||||
{
|
||||
switch (GetLastError())
|
||||
{
|
||||
case ERROR_PIPE_CONNECTED: connected = true; break;
|
||||
case ERROR_IO_PENDING:
|
||||
case ERROR_PIPE_LISTENING: connected = waitForIO (over, timeOutMs); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return connected;
|
||||
}
|
||||
|
||||
void disconnectPipe()
|
||||
{
|
||||
if (ownsPipe && connected)
|
||||
{
|
||||
DisconnectNamedPipe (pipeH);
|
||||
connected = false;
|
||||
}
|
||||
}
|
||||
|
||||
int read (void* destBuffer, const int maxBytesToRead, const int timeOutMilliseconds)
|
||||
{
|
||||
while (connect (timeOutMilliseconds))
|
||||
{
|
||||
if (maxBytesToRead <= 0)
|
||||
return 0;
|
||||
|
||||
OverlappedEvent over;
|
||||
unsigned long numRead;
|
||||
|
||||
if (ReadFile (pipeH, destBuffer, (DWORD) maxBytesToRead, &numRead, &over.over))
|
||||
return (int) numRead;
|
||||
|
||||
const DWORD lastError = GetLastError();
|
||||
|
||||
if (lastError == ERROR_IO_PENDING)
|
||||
{
|
||||
if (! waitForIO (over, timeOutMilliseconds))
|
||||
return -1;
|
||||
|
||||
if (GetOverlappedResult (pipeH, &over.over, &numRead, FALSE))
|
||||
return (int) numRead;
|
||||
}
|
||||
|
||||
if (ownsPipe && (GetLastError() == ERROR_BROKEN_PIPE || GetLastError() == ERROR_PIPE_NOT_CONNECTED))
|
||||
disconnectPipe();
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int write (const void* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
|
||||
{
|
||||
if (connect (timeOutMilliseconds))
|
||||
{
|
||||
if (numBytesToWrite <= 0)
|
||||
return 0;
|
||||
|
||||
OverlappedEvent over;
|
||||
unsigned long numWritten;
|
||||
|
||||
if (WriteFile (pipeH, sourceBuffer, (DWORD) numBytesToWrite, &numWritten, &over.over))
|
||||
return (int) numWritten;
|
||||
|
||||
if (GetLastError() == ERROR_IO_PENDING)
|
||||
{
|
||||
if (! waitForIO (over, timeOutMilliseconds))
|
||||
return -1;
|
||||
|
||||
if (GetOverlappedResult (pipeH, &over.over, &numWritten, FALSE))
|
||||
return (int) numWritten;
|
||||
|
||||
if (GetLastError() == ERROR_BROKEN_PIPE && ownsPipe)
|
||||
disconnectPipe();
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
const String filename;
|
||||
HANDLE pipeH, cancelEvent;
|
||||
bool connected, ownsPipe, shouldStop;
|
||||
CriticalSection createFileLock;
|
||||
|
||||
private:
|
||||
struct OverlappedEvent
|
||||
{
|
||||
OverlappedEvent()
|
||||
{
|
||||
zerostruct (over);
|
||||
over.hEvent = CreateEvent (0, TRUE, FALSE, 0);
|
||||
}
|
||||
|
||||
~OverlappedEvent()
|
||||
{
|
||||
CloseHandle (over.hEvent);
|
||||
}
|
||||
|
||||
OVERLAPPED over;
|
||||
};
|
||||
|
||||
bool waitForIO (OverlappedEvent& over, int timeOutMilliseconds)
|
||||
{
|
||||
if (shouldStop)
|
||||
return false;
|
||||
|
||||
HANDLE handles[] = { over.over.hEvent, cancelEvent };
|
||||
DWORD waitResult = WaitForMultipleObjects (2, handles, FALSE,
|
||||
timeOutMilliseconds >= 0 ? timeOutMilliseconds
|
||||
: INFINITE);
|
||||
|
||||
if (waitResult == WAIT_OBJECT_0)
|
||||
return true;
|
||||
|
||||
CancelIo (pipeH);
|
||||
return false;
|
||||
}
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
|
||||
};
|
||||
|
||||
void NamedPipe::close()
|
||||
{
|
||||
if (pimpl != nullptr)
|
||||
{
|
||||
pimpl->shouldStop = true;
|
||||
SetEvent (pimpl->cancelEvent);
|
||||
|
||||
ScopedWriteLock sl (lock);
|
||||
pimpl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool NamedPipe::openInternal (const String& pipeName, const bool createPipe)
|
||||
{
|
||||
pimpl = new Pimpl (pipeName, createPipe);
|
||||
|
||||
if (createPipe && pimpl->pipeH == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
pimpl = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int NamedPipe::read (void* destBuffer, int maxBytesToRead, int timeOutMilliseconds)
|
||||
{
|
||||
ScopedReadLock sl (lock);
|
||||
return pimpl != nullptr ? pimpl->read (destBuffer, maxBytesToRead, timeOutMilliseconds) : -1;
|
||||
}
|
||||
|
||||
int NamedPipe::write (const void* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
|
||||
{
|
||||
ScopedReadLock sl (lock);
|
||||
return pimpl != nullptr ? pimpl->write (sourceBuffer, numBytesToWrite, timeOutMilliseconds) : -1;
|
||||
}
|
||||
464
modules/beast_core/native/beast_win32_Network.cpp
Normal file
464
modules/beast_core/native/beast_win32_Network.cpp
Normal file
@@ -0,0 +1,464 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef INTERNET_FLAG_NEED_FILE
|
||||
#define INTERNET_FLAG_NEED_FILE 0x00000010
|
||||
#endif
|
||||
|
||||
#ifndef INTERNET_OPTION_DISABLE_AUTODIAL
|
||||
#define INTERNET_OPTION_DISABLE_AUTODIAL 70
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
class WebInputStream : public InputStream
|
||||
{
|
||||
public:
|
||||
WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_,
|
||||
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
|
||||
const String& headers_, int timeOutMs_, StringPairArray* responseHeaders)
|
||||
: connection (0), request (0),
|
||||
address (address_), headers (headers_), postData (postData_), position (0),
|
||||
finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
|
||||
{
|
||||
createConnection (progressCallback, progressCallbackContext);
|
||||
|
||||
if (responseHeaders != nullptr && ! isError())
|
||||
{
|
||||
DWORD bufferSizeBytes = 4096;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
HeapBlock<char> buffer ((size_t) bufferSizeBytes);
|
||||
|
||||
if (HttpQueryInfo (request, HTTP_QUERY_RAW_HEADERS_CRLF, buffer.getData(), &bufferSizeBytes, 0))
|
||||
{
|
||||
StringArray headersArray;
|
||||
headersArray.addLines (reinterpret_cast <const WCHAR*> (buffer.getData()));
|
||||
|
||||
for (int i = 0; i < headersArray.size(); ++i)
|
||||
{
|
||||
const String& header = headersArray[i];
|
||||
const String key (header.upToFirstOccurrenceOf (": ", false, false));
|
||||
const String value (header.fromFirstOccurrenceOf (": ", false, false));
|
||||
const String previousValue ((*responseHeaders) [key]);
|
||||
|
||||
responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~WebInputStream()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool isError() const { return request == 0; }
|
||||
bool isExhausted() { return finished; }
|
||||
int64 getPosition() { return position; }
|
||||
|
||||
int64 getTotalLength()
|
||||
{
|
||||
if (! isError())
|
||||
{
|
||||
DWORD index = 0, result = 0, size = sizeof (result);
|
||||
|
||||
if (HttpQueryInfo (request, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &result, &size, &index))
|
||||
return (int64) result;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int read (void* buffer, int bytesToRead)
|
||||
{
|
||||
bassert (buffer != nullptr && bytesToRead >= 0);
|
||||
DWORD bytesRead = 0;
|
||||
|
||||
if (! (finished || isError()))
|
||||
{
|
||||
InternetReadFile (request, buffer, (DWORD) bytesToRead, &bytesRead);
|
||||
position += bytesRead;
|
||||
|
||||
if (bytesRead == 0)
|
||||
finished = true;
|
||||
}
|
||||
|
||||
return (int) bytesRead;
|
||||
}
|
||||
|
||||
bool setPosition (int64 wantedPos)
|
||||
{
|
||||
if (isError())
|
||||
return false;
|
||||
|
||||
if (wantedPos != position)
|
||||
{
|
||||
finished = false;
|
||||
position = (int64) InternetSetFilePointer (request, (LONG) wantedPos, 0, FILE_BEGIN, 0);
|
||||
|
||||
if (position == wantedPos)
|
||||
return true;
|
||||
|
||||
if (wantedPos < position)
|
||||
{
|
||||
close();
|
||||
position = 0;
|
||||
createConnection (0, 0);
|
||||
}
|
||||
|
||||
skipNextBytes (wantedPos - position);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
HINTERNET connection, request;
|
||||
String address, headers;
|
||||
MemoryBlock postData;
|
||||
int64 position;
|
||||
bool finished;
|
||||
const bool isPost;
|
||||
int timeOutMs;
|
||||
|
||||
void close()
|
||||
{
|
||||
if (request != 0)
|
||||
{
|
||||
InternetCloseHandle (request);
|
||||
request = 0;
|
||||
}
|
||||
|
||||
if (connection != 0)
|
||||
{
|
||||
InternetCloseHandle (connection);
|
||||
connection = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void createConnection (URL::OpenStreamProgressCallback* progressCallback,
|
||||
void* progressCallbackContext)
|
||||
{
|
||||
static HINTERNET sessionHandle = InternetOpen (_T("beast"), INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, 0);
|
||||
|
||||
close();
|
||||
|
||||
if (sessionHandle != 0)
|
||||
{
|
||||
// break up the url..
|
||||
const int fileNumChars = 65536;
|
||||
const int serverNumChars = 2048;
|
||||
const int usernameNumChars = 1024;
|
||||
const int passwordNumChars = 1024;
|
||||
HeapBlock<TCHAR> file (fileNumChars), server (serverNumChars),
|
||||
username (usernameNumChars), password (passwordNumChars);
|
||||
|
||||
URL_COMPONENTS uc = { 0 };
|
||||
uc.dwStructSize = sizeof (uc);
|
||||
uc.lpszUrlPath = file;
|
||||
uc.dwUrlPathLength = fileNumChars;
|
||||
uc.lpszHostName = server;
|
||||
uc.dwHostNameLength = serverNumChars;
|
||||
uc.lpszUserName = username;
|
||||
uc.dwUserNameLength = usernameNumChars;
|
||||
uc.lpszPassword = password;
|
||||
uc.dwPasswordLength = passwordNumChars;
|
||||
|
||||
if (InternetCrackUrl (address.toWideCharPointer(), 0, 0, &uc))
|
||||
openConnection (uc, sessionHandle, progressCallback, progressCallbackContext);
|
||||
}
|
||||
}
|
||||
|
||||
void openConnection (URL_COMPONENTS& uc, HINTERNET sessionHandle,
|
||||
URL::OpenStreamProgressCallback* progressCallback,
|
||||
void* progressCallbackContext)
|
||||
{
|
||||
int disable = 1;
|
||||
InternetSetOption (sessionHandle, INTERNET_OPTION_DISABLE_AUTODIAL, &disable, sizeof (disable));
|
||||
|
||||
if (timeOutMs == 0)
|
||||
timeOutMs = 30000;
|
||||
else if (timeOutMs < 0)
|
||||
timeOutMs = -1;
|
||||
|
||||
applyTimeout (sessionHandle, INTERNET_OPTION_CONNECT_TIMEOUT);
|
||||
applyTimeout (sessionHandle, INTERNET_OPTION_RECEIVE_TIMEOUT);
|
||||
applyTimeout (sessionHandle, INTERNET_OPTION_SEND_TIMEOUT);
|
||||
applyTimeout (sessionHandle, INTERNET_OPTION_DATA_RECEIVE_TIMEOUT);
|
||||
applyTimeout (sessionHandle, INTERNET_OPTION_DATA_SEND_TIMEOUT);
|
||||
|
||||
const bool isFtp = address.startsWithIgnoreCase ("ftp:");
|
||||
|
||||
connection = InternetConnect (sessionHandle, uc.lpszHostName, uc.nPort,
|
||||
uc.lpszUserName, uc.lpszPassword,
|
||||
isFtp ? (DWORD) INTERNET_SERVICE_FTP
|
||||
: (DWORD) INTERNET_SERVICE_HTTP,
|
||||
0, 0);
|
||||
if (connection != 0)
|
||||
{
|
||||
if (isFtp)
|
||||
request = FtpOpenFile (connection, uc.lpszUrlPath, GENERIC_READ,
|
||||
FTP_TRANSFER_TYPE_BINARY | INTERNET_FLAG_NEED_FILE, 0);
|
||||
else
|
||||
openHTTPConnection (uc, progressCallback, progressCallbackContext);
|
||||
}
|
||||
}
|
||||
|
||||
void applyTimeout (HINTERNET sessionHandle, const DWORD option)
|
||||
{
|
||||
InternetSetOption (sessionHandle, option, &timeOutMs, sizeof (timeOutMs));
|
||||
}
|
||||
|
||||
void openHTTPConnection (URL_COMPONENTS& uc, URL::OpenStreamProgressCallback* progressCallback,
|
||||
void* progressCallbackContext)
|
||||
{
|
||||
const TCHAR* mimeTypes[] = { _T("*/*"), nullptr };
|
||||
|
||||
DWORD flags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_COOKIES;
|
||||
|
||||
if (address.startsWithIgnoreCase ("https:"))
|
||||
flags |= INTERNET_FLAG_SECURE; // (this flag only seems necessary if the OS is running IE6 -
|
||||
// IE7 seems to automatically work out when it's https)
|
||||
|
||||
request = HttpOpenRequest (connection, isPost ? _T("POST") : _T("GET"),
|
||||
uc.lpszUrlPath, 0, 0, mimeTypes, flags, 0);
|
||||
|
||||
if (request != 0)
|
||||
{
|
||||
INTERNET_BUFFERS buffers = { 0 };
|
||||
buffers.dwStructSize = sizeof (INTERNET_BUFFERS);
|
||||
buffers.lpcszHeader = headers.toWideCharPointer();
|
||||
buffers.dwHeadersLength = (DWORD) headers.length();
|
||||
buffers.dwBufferTotal = (DWORD) postData.getSize();
|
||||
|
||||
if (HttpSendRequestEx (request, &buffers, 0, HSR_INITIATE, 0))
|
||||
{
|
||||
int bytesSent = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
const int bytesToDo = bmin (1024, (int) postData.getSize() - bytesSent);
|
||||
DWORD bytesDone = 0;
|
||||
|
||||
if (bytesToDo > 0
|
||||
&& ! InternetWriteFile (request,
|
||||
static_cast <const char*> (postData.getData()) + bytesSent,
|
||||
(DWORD) bytesToDo, &bytesDone))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (bytesToDo == 0 || (int) bytesDone < bytesToDo)
|
||||
{
|
||||
if (HttpEndRequest (request, 0, 0, 0))
|
||||
return;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
bytesSent += bytesDone;
|
||||
|
||||
if (progressCallback != nullptr
|
||||
&& ! progressCallback (progressCallbackContext, bytesSent, (int) postData.getSize()))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream)
|
||||
};
|
||||
|
||||
InputStream* URL::createNativeStream (const String& address, bool isPost, const MemoryBlock& postData,
|
||||
OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
|
||||
const String& headers, const int timeOutMs, StringPairArray* responseHeaders)
|
||||
{
|
||||
ScopedPointer <WebInputStream> wi (new WebInputStream (address, isPost, postData,
|
||||
progressCallback, progressCallbackContext,
|
||||
headers, timeOutMs, responseHeaders));
|
||||
|
||||
return wi->isError() ? nullptr : wi.release();
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
struct GetAdaptersInfoHelper
|
||||
{
|
||||
bool callGetAdaptersInfo()
|
||||
{
|
||||
DynamicLibrary dll ("iphlpapi.dll");
|
||||
BEAST_LOAD_WINAPI_FUNCTION (dll, GetAdaptersInfo, getAdaptersInfo, DWORD, (PIP_ADAPTER_INFO, PULONG))
|
||||
|
||||
if (getAdaptersInfo == nullptr)
|
||||
return false;
|
||||
|
||||
adapterInfo.malloc (1);
|
||||
ULONG len = sizeof (IP_ADAPTER_INFO);
|
||||
|
||||
if (getAdaptersInfo (adapterInfo, &len) == ERROR_BUFFER_OVERFLOW)
|
||||
adapterInfo.malloc (len, 1);
|
||||
|
||||
return getAdaptersInfo (adapterInfo, &len) == NO_ERROR;
|
||||
}
|
||||
|
||||
HeapBlock<IP_ADAPTER_INFO> adapterInfo;
|
||||
};
|
||||
|
||||
namespace MACAddressHelpers
|
||||
{
|
||||
void getViaGetAdaptersInfo (Array<MACAddress>& result)
|
||||
{
|
||||
GetAdaptersInfoHelper gah;
|
||||
|
||||
if (gah.callGetAdaptersInfo())
|
||||
{
|
||||
for (PIP_ADAPTER_INFO adapter = gah.adapterInfo; adapter != nullptr; adapter = adapter->Next)
|
||||
if (adapter->AddressLength >= 6)
|
||||
result.addIfNotAlreadyThere (MACAddress (adapter->Address));
|
||||
}
|
||||
}
|
||||
|
||||
void getViaNetBios (Array<MACAddress>& result)
|
||||
{
|
||||
DynamicLibrary dll ("netapi32.dll");
|
||||
BEAST_LOAD_WINAPI_FUNCTION (dll, Netbios, NetbiosCall, UCHAR, (PNCB))
|
||||
|
||||
if (NetbiosCall != 0)
|
||||
{
|
||||
LANA_ENUM enums = { 0 };
|
||||
|
||||
{
|
||||
NCB ncb = { 0 };
|
||||
ncb.ncb_command = NCBENUM;
|
||||
ncb.ncb_buffer = (unsigned char*) &enums;
|
||||
ncb.ncb_length = sizeof (LANA_ENUM);
|
||||
NetbiosCall (&ncb);
|
||||
}
|
||||
|
||||
for (int i = 0; i < enums.length; ++i)
|
||||
{
|
||||
NCB ncb2 = { 0 };
|
||||
ncb2.ncb_command = NCBRESET;
|
||||
ncb2.ncb_lana_num = enums.lana[i];
|
||||
|
||||
if (NetbiosCall (&ncb2) == 0)
|
||||
{
|
||||
NCB ncb = { 0 };
|
||||
memcpy (ncb.ncb_callname, "* ", NCBNAMSZ);
|
||||
ncb.ncb_command = NCBASTAT;
|
||||
ncb.ncb_lana_num = enums.lana[i];
|
||||
|
||||
struct ASTAT
|
||||
{
|
||||
ADAPTER_STATUS adapt;
|
||||
NAME_BUFFER NameBuff [30];
|
||||
};
|
||||
|
||||
ASTAT astat;
|
||||
zerostruct (astat);
|
||||
ncb.ncb_buffer = (unsigned char*) &astat;
|
||||
ncb.ncb_length = sizeof (ASTAT);
|
||||
|
||||
if (NetbiosCall (&ncb) == 0 && astat.adapt.adapter_type == 0xfe)
|
||||
result.addIfNotAlreadyThere (MACAddress (astat.adapt.adapter_address));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MACAddress::findAllAddresses (Array<MACAddress>& result)
|
||||
{
|
||||
MACAddressHelpers::getViaGetAdaptersInfo (result);
|
||||
MACAddressHelpers::getViaNetBios (result);
|
||||
}
|
||||
|
||||
void IPAddress::findAllAddresses (Array<IPAddress>& result)
|
||||
{
|
||||
result.addIfNotAlreadyThere (IPAddress::local());
|
||||
|
||||
GetAdaptersInfoHelper gah;
|
||||
|
||||
if (gah.callGetAdaptersInfo())
|
||||
{
|
||||
for (PIP_ADAPTER_INFO adapter = gah.adapterInfo; adapter != nullptr; adapter = adapter->Next)
|
||||
{
|
||||
IPAddress ip (adapter->IpAddressList.IpAddress.String);
|
||||
|
||||
if (ip != IPAddress::any())
|
||||
result.addIfNotAlreadyThere (ip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool Process::openEmailWithAttachments (const String& targetEmailAddress,
|
||||
const String& emailSubject,
|
||||
const String& bodyText,
|
||||
const StringArray& filesToAttach)
|
||||
{
|
||||
DynamicLibrary dll ("MAPI32.dll");
|
||||
BEAST_LOAD_WINAPI_FUNCTION (dll, MAPISendMail, mapiSendMail,
|
||||
ULONG, (LHANDLE, ULONG, lpMapiMessage, ::FLAGS, ULONG))
|
||||
|
||||
if (mapiSendMail == nullptr)
|
||||
return false;
|
||||
|
||||
MapiMessage message = { 0 };
|
||||
message.lpszSubject = (LPSTR) emailSubject.toRawUTF8();
|
||||
message.lpszNoteText = (LPSTR) bodyText.toRawUTF8();
|
||||
|
||||
MapiRecipDesc recip = { 0 };
|
||||
recip.ulRecipClass = MAPI_TO;
|
||||
String targetEmailAddress_ (targetEmailAddress);
|
||||
if (targetEmailAddress_.isEmpty())
|
||||
targetEmailAddress_ = " "; // (Windows Mail can't deal with a blank address)
|
||||
recip.lpszName = (LPSTR) targetEmailAddress_.toRawUTF8();
|
||||
message.nRecipCount = 1;
|
||||
message.lpRecips = &recip;
|
||||
|
||||
HeapBlock <MapiFileDesc> files;
|
||||
files.calloc ((size_t) filesToAttach.size());
|
||||
|
||||
message.nFileCount = (ULONG) filesToAttach.size();
|
||||
message.lpFiles = files;
|
||||
|
||||
for (int i = 0; i < filesToAttach.size(); ++i)
|
||||
{
|
||||
files[i].nPosition = (ULONG) -1;
|
||||
files[i].lpszPathName = (LPSTR) filesToAttach[i].toRawUTF8();
|
||||
}
|
||||
|
||||
return mapiSendMail (0, 0, &message, MAPI_DIALOG | MAPI_LOGON_UI, 0) == SUCCESS_SUCCESS;
|
||||
}
|
||||
216
modules/beast_core/native/beast_win32_Registry.cpp
Normal file
216
modules/beast_core/native/beast_win32_Registry.cpp
Normal file
@@ -0,0 +1,216 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
struct RegistryKeyWrapper
|
||||
{
|
||||
RegistryKeyWrapper (String name, const bool createForWriting, const DWORD wow64Flags)
|
||||
: key (0), wideCharValueName (nullptr)
|
||||
{
|
||||
HKEY rootKey = 0;
|
||||
|
||||
if (name.startsWithIgnoreCase ("HKEY_CURRENT_USER\\")) rootKey = HKEY_CURRENT_USER;
|
||||
else if (name.startsWithIgnoreCase ("HKEY_LOCAL_MACHINE\\")) rootKey = HKEY_LOCAL_MACHINE;
|
||||
else if (name.startsWithIgnoreCase ("HKEY_CLASSES_ROOT\\")) rootKey = HKEY_CLASSES_ROOT;
|
||||
|
||||
if (rootKey != 0)
|
||||
{
|
||||
name = name.substring (name.indexOfChar ('\\') + 1);
|
||||
|
||||
const int lastSlash = name.lastIndexOfChar ('\\');
|
||||
valueName = name.substring (lastSlash + 1);
|
||||
wideCharValueName = valueName.toWideCharPointer();
|
||||
|
||||
name = name.substring (0, lastSlash);
|
||||
const wchar_t* const wideCharName = name.toWideCharPointer();
|
||||
DWORD result;
|
||||
|
||||
if (createForWriting)
|
||||
RegCreateKeyEx (rootKey, wideCharName, 0, 0, REG_OPTION_NON_VOLATILE,
|
||||
KEY_WRITE | KEY_QUERY_VALUE | wow64Flags, 0, &key, &result);
|
||||
else
|
||||
RegOpenKeyEx (rootKey, wideCharName, 0, KEY_READ | wow64Flags, &key);
|
||||
}
|
||||
}
|
||||
|
||||
~RegistryKeyWrapper()
|
||||
{
|
||||
if (key != 0)
|
||||
RegCloseKey (key);
|
||||
}
|
||||
|
||||
static bool setValue (const String& regValuePath, const DWORD type,
|
||||
const void* data, size_t dataSize)
|
||||
{
|
||||
const RegistryKeyWrapper key (regValuePath, true, 0);
|
||||
|
||||
return key.key != 0
|
||||
&& RegSetValueEx (key.key, key.wideCharValueName, 0, type,
|
||||
reinterpret_cast <const BYTE*> (data),
|
||||
(DWORD) dataSize) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static uint32 getBinaryValue (const String& regValuePath, MemoryBlock& result, DWORD wow64Flags)
|
||||
{
|
||||
const RegistryKeyWrapper key (regValuePath, false, wow64Flags);
|
||||
|
||||
if (key.key != 0)
|
||||
{
|
||||
for (unsigned long bufferSize = 1024; ; bufferSize *= 2)
|
||||
{
|
||||
result.setSize (bufferSize, false);
|
||||
DWORD type = REG_NONE;
|
||||
|
||||
const LONG err = RegQueryValueEx (key.key, key.wideCharValueName, 0, &type,
|
||||
(LPBYTE) result.getData(), &bufferSize);
|
||||
|
||||
if (err == ERROR_SUCCESS)
|
||||
{
|
||||
result.setSize (bufferSize, false);
|
||||
return type;
|
||||
}
|
||||
|
||||
if (err != ERROR_MORE_DATA)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return REG_NONE;
|
||||
}
|
||||
|
||||
static String getValue (const String& regValuePath, const String& defaultValue, DWORD wow64Flags)
|
||||
{
|
||||
MemoryBlock buffer;
|
||||
switch (getBinaryValue (regValuePath, buffer, wow64Flags))
|
||||
{
|
||||
case REG_SZ: return static_cast <const WCHAR*> (buffer.getData());
|
||||
case REG_DWORD: return String ((int) *reinterpret_cast<const DWORD*> (buffer.getData()));
|
||||
default: break;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
static bool valueExists (const String& regValuePath, const DWORD wow64Flags)
|
||||
{
|
||||
const RegistryKeyWrapper key (regValuePath, false, wow64Flags);
|
||||
|
||||
if (key.key == 0)
|
||||
return false;
|
||||
|
||||
unsigned char buffer [512];
|
||||
unsigned long bufferSize = sizeof (buffer);
|
||||
DWORD type = 0;
|
||||
|
||||
const LONG result = RegQueryValueEx (key.key, key.wideCharValueName,
|
||||
0, &type, buffer, &bufferSize);
|
||||
|
||||
return result == ERROR_SUCCESS || result == ERROR_MORE_DATA;
|
||||
}
|
||||
|
||||
HKEY key;
|
||||
const wchar_t* wideCharValueName;
|
||||
String valueName;
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE (RegistryKeyWrapper)
|
||||
};
|
||||
|
||||
uint32 WindowsRegistry::getBinaryValue (const String& regValuePath, MemoryBlock& result)
|
||||
{
|
||||
return RegistryKeyWrapper::getBinaryValue (regValuePath, result, 0);
|
||||
}
|
||||
|
||||
String WindowsRegistry::getValue (const String& regValuePath, const String& defaultValue)
|
||||
{
|
||||
return RegistryKeyWrapper::getValue (regValuePath, defaultValue, 0);
|
||||
}
|
||||
|
||||
String WindowsRegistry::getValueWow64 (const String& regValuePath, const String& defaultValue)
|
||||
{
|
||||
return RegistryKeyWrapper::getValue (regValuePath, defaultValue, 0x100 /*KEY_WOW64_64KEY*/);
|
||||
}
|
||||
|
||||
bool WindowsRegistry::valueExistsWow64 (const String& regValuePath)
|
||||
{
|
||||
return RegistryKeyWrapper::valueExists (regValuePath, 0x100 /*KEY_WOW64_64KEY*/);
|
||||
}
|
||||
|
||||
bool WindowsRegistry::setValue (const String& regValuePath, const String& value)
|
||||
{
|
||||
return RegistryKeyWrapper::setValue (regValuePath, REG_SZ, value.toWideCharPointer(),
|
||||
CharPointer_UTF16::getBytesRequiredFor (value.getCharPointer()));
|
||||
}
|
||||
|
||||
bool WindowsRegistry::setValue (const String& regValuePath, const uint32 value)
|
||||
{
|
||||
return RegistryKeyWrapper::setValue (regValuePath, REG_DWORD, &value, sizeof (value));
|
||||
}
|
||||
|
||||
bool WindowsRegistry::setValue (const String& regValuePath, const uint64 value)
|
||||
{
|
||||
return RegistryKeyWrapper::setValue (regValuePath, REG_QWORD, &value, sizeof (value));
|
||||
}
|
||||
|
||||
bool WindowsRegistry::setValue (const String& regValuePath, const MemoryBlock& value)
|
||||
{
|
||||
return RegistryKeyWrapper::setValue (regValuePath, REG_BINARY, value.getData(), value.getSize());
|
||||
}
|
||||
|
||||
bool WindowsRegistry::valueExists (const String& regValuePath)
|
||||
{
|
||||
return RegistryKeyWrapper::valueExists (regValuePath, 0);
|
||||
}
|
||||
|
||||
void WindowsRegistry::deleteValue (const String& regValuePath)
|
||||
{
|
||||
const RegistryKeyWrapper key (regValuePath, true, 0);
|
||||
|
||||
if (key.key != 0)
|
||||
RegDeleteValue (key.key, key.wideCharValueName);
|
||||
}
|
||||
|
||||
void WindowsRegistry::deleteKey (const String& regKeyPath)
|
||||
{
|
||||
const RegistryKeyWrapper key (regKeyPath, true, 0);
|
||||
|
||||
if (key.key != 0)
|
||||
RegDeleteKey (key.key, key.wideCharValueName);
|
||||
}
|
||||
|
||||
bool WindowsRegistry::registerFileAssociation (const String& fileExtension,
|
||||
const String& symbolicDescription,
|
||||
const String& fullDescription,
|
||||
const File& targetExecutable,
|
||||
const int iconResourceNumber,
|
||||
const bool registerForCurrentUserOnly)
|
||||
{
|
||||
const char* const root = registerForCurrentUserOnly ? "HKEY_CURRENT_USER\\Software\\Classes\\"
|
||||
: "HKEY_CLASSES_ROOT\\";
|
||||
const String key (root + symbolicDescription);
|
||||
|
||||
return setValue (root + fileExtension + "\\", symbolicDescription)
|
||||
&& setValue (key + "\\", fullDescription)
|
||||
&& setValue (key + "\\shell\\open\\command\\", targetExecutable.getFullPathName() + " \"%1\"")
|
||||
&& (iconResourceNumber == 0
|
||||
|| setValue (key + "\\DefaultIcon\\",
|
||||
targetExecutable.getFullPathName() + "," + String (-iconResourceNumber)));
|
||||
}
|
||||
413
modules/beast_core/native/beast_win32_SystemStats.cpp
Normal file
413
modules/beast_core/native/beast_win32_SystemStats.cpp
Normal file
@@ -0,0 +1,413 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
void Logger::outputDebugString (const String& text)
|
||||
{
|
||||
OutputDebugString ((text + "\n").toWideCharPointer());
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#ifdef BEAST_DLL_BUILD
|
||||
BEAST_API void* beastDLL_malloc (size_t sz) { return std::malloc (sz); }
|
||||
BEAST_API void beastDLL_free (void* block) { std::free (block); }
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#if BEAST_USE_INTRINSICS
|
||||
|
||||
// CPU info functions using intrinsics...
|
||||
|
||||
#pragma intrinsic (__cpuid)
|
||||
#pragma intrinsic (__rdtsc)
|
||||
|
||||
String SystemStats::getCpuVendor()
|
||||
{
|
||||
int info [4];
|
||||
__cpuid (info, 0);
|
||||
|
||||
char v [12];
|
||||
memcpy (v, info + 1, 4);
|
||||
memcpy (v + 4, info + 3, 4);
|
||||
memcpy (v + 8, info + 2, 4);
|
||||
|
||||
return String (v, 12);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
//==============================================================================
|
||||
// CPU info functions using old fashioned inline asm...
|
||||
|
||||
static void beast_getCpuVendor (char* const v)
|
||||
{
|
||||
int vendor[4] = { 0 };
|
||||
|
||||
#if ! BEAST_MINGW
|
||||
__try
|
||||
#endif
|
||||
{
|
||||
#if BEAST_GCC
|
||||
unsigned int dummy = 0;
|
||||
__asm__ ("cpuid" : "=a" (dummy), "=b" (vendor[0]), "=c" (vendor[2]),"=d" (vendor[1]) : "a" (0));
|
||||
#else
|
||||
__asm
|
||||
{
|
||||
mov eax, 0
|
||||
cpuid
|
||||
mov [vendor], ebx
|
||||
mov [vendor + 4], edx
|
||||
mov [vendor + 8], ecx
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#if ! BEAST_MINGW
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
memcpy (v, vendor, 16);
|
||||
}
|
||||
|
||||
String SystemStats::getCpuVendor()
|
||||
{
|
||||
char v [16];
|
||||
beast_getCpuVendor (v);
|
||||
return String (v, 16);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//==============================================================================
|
||||
SystemStats::CPUFlags::CPUFlags()
|
||||
{
|
||||
hasMMX = IsProcessorFeaturePresent (PF_MMX_INSTRUCTIONS_AVAILABLE) != 0;
|
||||
hasSSE = IsProcessorFeaturePresent (PF_XMMI_INSTRUCTIONS_AVAILABLE) != 0;
|
||||
hasSSE2 = IsProcessorFeaturePresent (PF_XMMI64_INSTRUCTIONS_AVAILABLE) != 0;
|
||||
#ifdef PF_AMD3D_INSTRUCTIONS_AVAILABLE
|
||||
has3DNow = IsProcessorFeaturePresent (PF_AMD3D_INSTRUCTIONS_AVAILABLE) != 0;
|
||||
#else
|
||||
has3DNow = IsProcessorFeaturePresent (PF_3DNOW_INSTRUCTIONS_AVAILABLE) != 0;
|
||||
#endif
|
||||
|
||||
SYSTEM_INFO systemInfo;
|
||||
GetNativeSystemInfo (&systemInfo);
|
||||
numCpus = (int) systemInfo.dwNumberOfProcessors;
|
||||
}
|
||||
|
||||
#if BEAST_MSVC && BEAST_CHECK_MEMORY_LEAKS
|
||||
struct DebugFlagsInitialiser
|
||||
{
|
||||
DebugFlagsInitialiser()
|
||||
{
|
||||
_CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
|
||||
}
|
||||
};
|
||||
|
||||
static DebugFlagsInitialiser debugFlagsInitialiser;
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
|
||||
{
|
||||
OSVERSIONINFO info;
|
||||
info.dwOSVersionInfoSize = sizeof (info);
|
||||
GetVersionEx (&info);
|
||||
|
||||
if (info.dwPlatformId == VER_PLATFORM_WIN32_NT)
|
||||
{
|
||||
if (info.dwMajorVersion == 5)
|
||||
return (info.dwMinorVersion == 0) ? Win2000 : WinXP;
|
||||
|
||||
if (info.dwMajorVersion == 6)
|
||||
{
|
||||
switch (info.dwMinorVersion)
|
||||
{
|
||||
case 0: return WinVista;
|
||||
case 1: return Windows7;
|
||||
case 2: return Windows8;
|
||||
|
||||
default:
|
||||
jassertfalse; // new version needs to be added here!
|
||||
return Windows8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jassertfalse; // need to support whatever new version is running!
|
||||
return UnknownOS;
|
||||
}
|
||||
|
||||
String SystemStats::getOperatingSystemName()
|
||||
{
|
||||
const char* name = "Unknown OS";
|
||||
|
||||
switch (getOperatingSystemType())
|
||||
{
|
||||
case Windows7: name = "Windows 7"; break;
|
||||
case Windows8: name = "Windows 8"; break;
|
||||
case WinVista: name = "Windows Vista"; break;
|
||||
case WinXP: name = "Windows XP"; break;
|
||||
case Win2000: name = "Windows 2000"; break;
|
||||
default: jassertfalse; break; // !! new type of OS?
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
bool SystemStats::isOperatingSystem64Bit()
|
||||
{
|
||||
#if BEAST_64BIT
|
||||
return true;
|
||||
#else
|
||||
typedef BOOL (WINAPI* LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
|
||||
|
||||
LPFN_ISWOW64PROCESS fnIsWow64Process
|
||||
= (LPFN_ISWOW64PROCESS) GetProcAddress (GetModuleHandleA ("kernel32"), "IsWow64Process");
|
||||
|
||||
BOOL isWow64 = FALSE;
|
||||
|
||||
return fnIsWow64Process != nullptr
|
||||
&& fnIsWow64Process (GetCurrentProcess(), &isWow64)
|
||||
&& isWow64 != FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
int SystemStats::getMemorySizeInMegabytes()
|
||||
{
|
||||
MEMORYSTATUSEX mem;
|
||||
mem.dwLength = sizeof (mem);
|
||||
GlobalMemoryStatusEx (&mem);
|
||||
return (int) (mem.ullTotalPhys / (1024 * 1024)) + 1;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String SystemStats::getEnvironmentVariable (const String& name, const String& defaultValue)
|
||||
{
|
||||
DWORD len = GetEnvironmentVariableW (name.toWideCharPointer(), nullptr, 0);
|
||||
if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
|
||||
return String (defaultValue);
|
||||
|
||||
HeapBlock<WCHAR> buffer (len);
|
||||
len = GetEnvironmentVariableW (name.toWideCharPointer(), buffer, len);
|
||||
|
||||
return String (CharPointer_wchar_t (buffer),
|
||||
CharPointer_wchar_t (buffer + len));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
uint32 beast_millisecondsSinceStartup() noexcept
|
||||
{
|
||||
return (uint32) timeGetTime();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class HiResCounterHandler
|
||||
{
|
||||
public:
|
||||
HiResCounterHandler()
|
||||
: hiResTicksOffset (0)
|
||||
{
|
||||
const MMRESULT res = timeBeginPeriod (1);
|
||||
(void) res;
|
||||
bassert (res == TIMERR_NOERROR);
|
||||
|
||||
LARGE_INTEGER f;
|
||||
QueryPerformanceFrequency (&f);
|
||||
hiResTicksPerSecond = f.QuadPart;
|
||||
hiResTicksScaleFactor = 1000.0 / hiResTicksPerSecond;
|
||||
}
|
||||
|
||||
inline int64 getHighResolutionTicks() noexcept
|
||||
{
|
||||
LARGE_INTEGER ticks;
|
||||
QueryPerformanceCounter (&ticks);
|
||||
|
||||
const int64 mainCounterAsHiResTicks = (beast_millisecondsSinceStartup() * hiResTicksPerSecond) / 1000;
|
||||
const int64 newOffset = mainCounterAsHiResTicks - ticks.QuadPart;
|
||||
|
||||
// fix for a very obscure PCI hardware bug that can make the counter
|
||||
// sometimes jump forwards by a few seconds..
|
||||
const int64 offsetDrift = abs64 (newOffset - hiResTicksOffset);
|
||||
|
||||
if (offsetDrift > (hiResTicksPerSecond >> 1))
|
||||
hiResTicksOffset = newOffset;
|
||||
|
||||
return ticks.QuadPart + hiResTicksOffset;
|
||||
}
|
||||
|
||||
inline double getMillisecondCounterHiRes() noexcept
|
||||
{
|
||||
return getHighResolutionTicks() * hiResTicksScaleFactor;
|
||||
}
|
||||
|
||||
int64 hiResTicksPerSecond, hiResTicksOffset;
|
||||
double hiResTicksScaleFactor;
|
||||
};
|
||||
|
||||
static HiResCounterHandler hiResCounterHandler;
|
||||
|
||||
int64 Time::getHighResolutionTicksPerSecond() noexcept { return hiResCounterHandler.hiResTicksPerSecond; }
|
||||
int64 Time::getHighResolutionTicks() noexcept { return hiResCounterHandler.getHighResolutionTicks(); }
|
||||
double Time::getMillisecondCounterHiRes() noexcept { return hiResCounterHandler.getMillisecondCounterHiRes(); }
|
||||
|
||||
//==============================================================================
|
||||
static int64 beast_getClockCycleCounter() noexcept
|
||||
{
|
||||
#if BEAST_USE_INTRINSICS
|
||||
// MS intrinsics version...
|
||||
return (int64) __rdtsc();
|
||||
|
||||
#elif BEAST_GCC
|
||||
// GNU inline asm version...
|
||||
unsigned int hi = 0, lo = 0;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"xor %%eax, %%eax \n\
|
||||
xor %%edx, %%edx \n\
|
||||
rdtsc \n\
|
||||
movl %%eax, %[lo] \n\
|
||||
movl %%edx, %[hi]"
|
||||
:
|
||||
: [hi] "m" (hi),
|
||||
[lo] "m" (lo)
|
||||
: "cc", "eax", "ebx", "ecx", "edx", "memory");
|
||||
|
||||
return (int64) ((((uint64) hi) << 32) | lo);
|
||||
#else
|
||||
// MSVC inline asm version...
|
||||
unsigned int hi = 0, lo = 0;
|
||||
|
||||
__asm
|
||||
{
|
||||
xor eax, eax
|
||||
xor edx, edx
|
||||
rdtsc
|
||||
mov lo, eax
|
||||
mov hi, edx
|
||||
}
|
||||
|
||||
return (int64) ((((uint64) hi) << 32) | lo);
|
||||
#endif
|
||||
}
|
||||
|
||||
int SystemStats::getCpuSpeedInMegaherz()
|
||||
{
|
||||
const int64 cycles = beast_getClockCycleCounter();
|
||||
const uint32 millis = Time::getMillisecondCounter();
|
||||
int lastResult = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int n = 1000000;
|
||||
while (--n > 0) {}
|
||||
|
||||
const uint32 millisElapsed = Time::getMillisecondCounter() - millis;
|
||||
const int64 cyclesNow = beast_getClockCycleCounter();
|
||||
|
||||
if (millisElapsed > 80)
|
||||
{
|
||||
const int newResult = (int) (((cyclesNow - cycles) / millisElapsed) / 1000);
|
||||
|
||||
if (millisElapsed > 500 || (lastResult == newResult && newResult > 100))
|
||||
return newResult;
|
||||
|
||||
lastResult = newResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
bool Time::setSystemTimeToThisTime() const
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
|
||||
st.wDayOfWeek = 0;
|
||||
st.wYear = (WORD) getYear();
|
||||
st.wMonth = (WORD) (getMonth() + 1);
|
||||
st.wDay = (WORD) getDayOfMonth();
|
||||
st.wHour = (WORD) getHours();
|
||||
st.wMinute = (WORD) getMinutes();
|
||||
st.wSecond = (WORD) getSeconds();
|
||||
st.wMilliseconds = (WORD) (millisSinceEpoch % 1000);
|
||||
|
||||
// do this twice because of daylight saving conversion problems - the
|
||||
// first one sets it up, the second one kicks it in.
|
||||
return SetLocalTime (&st) != 0
|
||||
&& SetLocalTime (&st) != 0;
|
||||
}
|
||||
|
||||
int SystemStats::getPageSize()
|
||||
{
|
||||
SYSTEM_INFO systemInfo;
|
||||
GetNativeSystemInfo (&systemInfo);
|
||||
|
||||
return (int) systemInfo.dwPageSize;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String SystemStats::getLogonName()
|
||||
{
|
||||
TCHAR text [256] = { 0 };
|
||||
DWORD len = (DWORD) numElementsInArray (text) - 1;
|
||||
GetUserName (text, &len);
|
||||
return String (text, len);
|
||||
}
|
||||
|
||||
String SystemStats::getFullUserName()
|
||||
{
|
||||
return getLogonName();
|
||||
}
|
||||
|
||||
String SystemStats::getComputerName()
|
||||
{
|
||||
TCHAR text [MAX_COMPUTERNAME_LENGTH + 1] = { 0 };
|
||||
DWORD len = (DWORD) numElementsInArray (text) - 1;
|
||||
GetComputerName (text, &len);
|
||||
return String (text, len);
|
||||
}
|
||||
|
||||
static String getLocaleValue (LCID locale, LCTYPE key, const char* defaultValue)
|
||||
{
|
||||
TCHAR buffer [256] = { 0 };
|
||||
if (GetLocaleInfo (locale, key, buffer, 255) > 0)
|
||||
return buffer;
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
String SystemStats::getUserLanguage() { return getLocaleValue (LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, "en"); }
|
||||
String SystemStats::getUserRegion() { return getLocaleValue (LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, "US"); }
|
||||
|
||||
String SystemStats::getDisplayLanguage()
|
||||
{
|
||||
DynamicLibrary dll ("kernel32.dll");
|
||||
BEAST_LOAD_WINAPI_FUNCTION (dll, GetUserDefaultUILanguage, getUserDefaultUILanguage, LANGID, (void))
|
||||
|
||||
if (getUserDefaultUILanguage != nullptr)
|
||||
return getLocaleValue (MAKELCID (getUserDefaultUILanguage(), SORT_DEFAULT), LOCALE_SISO639LANGNAME, "en");
|
||||
|
||||
return "en";
|
||||
}
|
||||
634
modules/beast_core/native/beast_win32_Threads.cpp
Normal file
634
modules/beast_core/native/beast_win32_Threads.cpp
Normal file
@@ -0,0 +1,634 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
HWND beast_messageWindowHandle = 0; // (this is used by other parts of the codebase)
|
||||
|
||||
//==============================================================================
|
||||
#if ! BEAST_USE_INTRINSICS
|
||||
// In newer compilers, the inline versions of these are used (in beast_Atomic.h), but in
|
||||
// older ones we have to actually call the ops as win32 functions..
|
||||
long beast_InterlockedExchange (volatile long* a, long b) noexcept { return InterlockedExchange (a, b); }
|
||||
long beast_InterlockedIncrement (volatile long* a) noexcept { return InterlockedIncrement (a); }
|
||||
long beast_InterlockedDecrement (volatile long* a) noexcept { return InterlockedDecrement (a); }
|
||||
long beast_InterlockedExchangeAdd (volatile long* a, long b) noexcept { return InterlockedExchangeAdd (a, b); }
|
||||
long beast_InterlockedCompareExchange (volatile long* a, long b, long c) noexcept { return InterlockedCompareExchange (a, b, c); }
|
||||
|
||||
__int64 beast_InterlockedCompareExchange64 (volatile __int64* value, __int64 newValue, __int64 valueToCompare) noexcept
|
||||
{
|
||||
jassertfalse; // This operation isn't available in old MS compiler versions!
|
||||
|
||||
__int64 oldValue = *value;
|
||||
if (oldValue == valueToCompare)
|
||||
*value = newValue;
|
||||
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
CriticalSection::CriticalSection() noexcept
|
||||
{
|
||||
// (just to check the MS haven't changed this structure and broken things...)
|
||||
#if BEAST_VC7_OR_EARLIER
|
||||
static_bassert (sizeof (CRITICAL_SECTION) <= 24);
|
||||
#else
|
||||
static_bassert (sizeof (CRITICAL_SECTION) <= sizeof (internal));
|
||||
#endif
|
||||
|
||||
InitializeCriticalSection ((CRITICAL_SECTION*) internal);
|
||||
}
|
||||
|
||||
CriticalSection::~CriticalSection() noexcept
|
||||
{
|
||||
DeleteCriticalSection ((CRITICAL_SECTION*) internal);
|
||||
}
|
||||
|
||||
void CriticalSection::enter() const noexcept
|
||||
{
|
||||
EnterCriticalSection ((CRITICAL_SECTION*) internal);
|
||||
}
|
||||
|
||||
bool CriticalSection::tryEnter() const noexcept
|
||||
{
|
||||
return TryEnterCriticalSection ((CRITICAL_SECTION*) internal) != FALSE;
|
||||
}
|
||||
|
||||
void CriticalSection::exit() const noexcept
|
||||
{
|
||||
LeaveCriticalSection ((CRITICAL_SECTION*) internal);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
WaitableEvent::WaitableEvent (const bool manualReset) noexcept
|
||||
: internal (CreateEvent (0, manualReset ? TRUE : FALSE, FALSE, 0))
|
||||
{
|
||||
}
|
||||
|
||||
WaitableEvent::~WaitableEvent() noexcept
|
||||
{
|
||||
CloseHandle (internal);
|
||||
}
|
||||
|
||||
bool WaitableEvent::wait (const int timeOutMillisecs) const noexcept
|
||||
{
|
||||
return WaitForSingleObject (internal, (DWORD) timeOutMillisecs) == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
void WaitableEvent::signal() const noexcept
|
||||
{
|
||||
SetEvent (internal);
|
||||
}
|
||||
|
||||
void WaitableEvent::reset() const noexcept
|
||||
{
|
||||
ResetEvent (internal);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void BEAST_API beast_threadEntryPoint (void*);
|
||||
|
||||
static unsigned int __stdcall threadEntryProc (void* userData)
|
||||
{
|
||||
if (beast_messageWindowHandle != 0)
|
||||
AttachThreadInput (GetWindowThreadProcessId (beast_messageWindowHandle, 0),
|
||||
GetCurrentThreadId(), TRUE);
|
||||
|
||||
beast_threadEntryPoint (userData);
|
||||
|
||||
_endthreadex (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Thread::launchThread()
|
||||
{
|
||||
unsigned int newThreadId;
|
||||
threadHandle = (void*) _beginthreadex (0, 0, &threadEntryProc, this, 0, &newThreadId);
|
||||
threadId = (ThreadID) newThreadId;
|
||||
}
|
||||
|
||||
void Thread::closeThreadHandle()
|
||||
{
|
||||
CloseHandle ((HANDLE) threadHandle);
|
||||
threadId = 0;
|
||||
threadHandle = 0;
|
||||
}
|
||||
|
||||
void Thread::killThread()
|
||||
{
|
||||
if (threadHandle != 0)
|
||||
{
|
||||
#if BEAST_DEBUG
|
||||
OutputDebugStringA ("** Warning - Forced thread termination **\n");
|
||||
#endif
|
||||
TerminateThread (threadHandle, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void Thread::setCurrentThreadName (const String& name)
|
||||
{
|
||||
#if BEAST_DEBUG && BEAST_MSVC
|
||||
struct
|
||||
{
|
||||
DWORD dwType;
|
||||
LPCSTR szName;
|
||||
DWORD dwThreadID;
|
||||
DWORD dwFlags;
|
||||
} info;
|
||||
|
||||
info.dwType = 0x1000;
|
||||
info.szName = name.toUTF8();
|
||||
info.dwThreadID = GetCurrentThreadId();
|
||||
info.dwFlags = 0;
|
||||
|
||||
__try
|
||||
{
|
||||
RaiseException (0x406d1388 /*MS_VC_EXCEPTION*/, 0, sizeof (info) / sizeof (ULONG_PTR), (ULONG_PTR*) &info);
|
||||
}
|
||||
__except (EXCEPTION_CONTINUE_EXECUTION)
|
||||
{}
|
||||
#else
|
||||
(void) name;
|
||||
#endif
|
||||
}
|
||||
|
||||
Thread::ThreadID Thread::getCurrentThreadId()
|
||||
{
|
||||
return (ThreadID) (pointer_sized_int) GetCurrentThreadId();
|
||||
}
|
||||
|
||||
bool Thread::setThreadPriority (void* handle, int priority)
|
||||
{
|
||||
int pri = THREAD_PRIORITY_TIME_CRITICAL;
|
||||
|
||||
if (priority < 1) pri = THREAD_PRIORITY_IDLE;
|
||||
else if (priority < 2) pri = THREAD_PRIORITY_LOWEST;
|
||||
else if (priority < 5) pri = THREAD_PRIORITY_BELOW_NORMAL;
|
||||
else if (priority < 7) pri = THREAD_PRIORITY_NORMAL;
|
||||
else if (priority < 9) pri = THREAD_PRIORITY_ABOVE_NORMAL;
|
||||
else if (priority < 10) pri = THREAD_PRIORITY_HIGHEST;
|
||||
|
||||
if (handle == 0)
|
||||
handle = GetCurrentThread();
|
||||
|
||||
return SetThreadPriority (handle, pri) != FALSE;
|
||||
}
|
||||
|
||||
void Thread::setCurrentThreadAffinityMask (const uint32 affinityMask)
|
||||
{
|
||||
SetThreadAffinityMask (GetCurrentThread(), affinityMask);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct SleepEvent
|
||||
{
|
||||
SleepEvent() noexcept
|
||||
: handle (CreateEvent (nullptr, FALSE, FALSE,
|
||||
#if BEAST_DEBUG
|
||||
_T("BEAST Sleep Event")))
|
||||
#else
|
||||
nullptr))
|
||||
#endif
|
||||
{}
|
||||
|
||||
~SleepEvent() noexcept
|
||||
{
|
||||
CloseHandle (handle);
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
HANDLE handle;
|
||||
};
|
||||
|
||||
static SleepEvent sleepEvent;
|
||||
|
||||
void BEAST_CALLTYPE Thread::sleep (const int millisecs)
|
||||
{
|
||||
if (millisecs >= 10 || sleepEvent.handle == 0)
|
||||
{
|
||||
Sleep ((DWORD) millisecs);
|
||||
}
|
||||
else
|
||||
{
|
||||
// unlike Sleep() this is guaranteed to return to the current thread after
|
||||
// the time expires, so we'll use this for short waits, which are more likely
|
||||
// to need to be accurate
|
||||
WaitForSingleObject (sleepEvent.handle, (DWORD) millisecs);
|
||||
}
|
||||
}
|
||||
|
||||
void Thread::yield()
|
||||
{
|
||||
Sleep (0);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static int lastProcessPriority = -1;
|
||||
|
||||
// called by WindowDriver because Windows does weird things to process priority
|
||||
// when you swap apps, and this forces an update when the app is brought to the front.
|
||||
void beast_repeatLastProcessPriority()
|
||||
{
|
||||
if (lastProcessPriority >= 0) // (avoid changing this if it's not been explicitly set by the app..)
|
||||
{
|
||||
DWORD p;
|
||||
|
||||
switch (lastProcessPriority)
|
||||
{
|
||||
case Process::LowPriority: p = IDLE_PRIORITY_CLASS; break;
|
||||
case Process::NormalPriority: p = NORMAL_PRIORITY_CLASS; break;
|
||||
case Process::HighPriority: p = HIGH_PRIORITY_CLASS; break;
|
||||
case Process::RealtimePriority: p = REALTIME_PRIORITY_CLASS; break;
|
||||
default: jassertfalse; return; // bad priority value
|
||||
}
|
||||
|
||||
SetPriorityClass (GetCurrentProcess(), p);
|
||||
}
|
||||
}
|
||||
|
||||
void Process::setPriority (ProcessPriority prior)
|
||||
{
|
||||
if (lastProcessPriority != (int) prior)
|
||||
{
|
||||
lastProcessPriority = (int) prior;
|
||||
beast_repeatLastProcessPriority();
|
||||
}
|
||||
}
|
||||
|
||||
BEAST_API bool BEAST_CALLTYPE beast_isRunningUnderDebugger()
|
||||
{
|
||||
return IsDebuggerPresent() != FALSE;
|
||||
}
|
||||
|
||||
bool BEAST_CALLTYPE Process::isRunningUnderDebugger()
|
||||
{
|
||||
return beast_isRunningUnderDebugger();
|
||||
}
|
||||
|
||||
static void* currentModuleHandle = nullptr;
|
||||
|
||||
void* Process::getCurrentModuleInstanceHandle() noexcept
|
||||
{
|
||||
if (currentModuleHandle == nullptr)
|
||||
currentModuleHandle = GetModuleHandleA (nullptr);
|
||||
|
||||
return currentModuleHandle;
|
||||
}
|
||||
|
||||
void Process::setCurrentModuleInstanceHandle (void* const newHandle) noexcept
|
||||
{
|
||||
currentModuleHandle = newHandle;
|
||||
}
|
||||
|
||||
void Process::raisePrivilege()
|
||||
{
|
||||
jassertfalse; // xxx not implemented
|
||||
}
|
||||
|
||||
void Process::lowerPrivilege()
|
||||
{
|
||||
jassertfalse; // xxx not implemented
|
||||
}
|
||||
|
||||
void Process::terminate()
|
||||
{
|
||||
#if BEAST_MSVC && BEAST_CHECK_MEMORY_LEAKS
|
||||
_CrtDumpMemoryLeaks();
|
||||
#endif
|
||||
|
||||
// bullet in the head in case there's a problem shutting down..
|
||||
ExitProcess (0);
|
||||
}
|
||||
|
||||
bool beast_isRunningInWine()
|
||||
{
|
||||
HMODULE ntdll = GetModuleHandleA ("ntdll");
|
||||
return ntdll != 0 && GetProcAddress (ntdll, "wine_get_version") != nullptr;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool DynamicLibrary::open (const String& name)
|
||||
{
|
||||
close();
|
||||
|
||||
BEAST_TRY
|
||||
{
|
||||
handle = LoadLibrary (name.toWideCharPointer());
|
||||
}
|
||||
BEAST_CATCH_ALL
|
||||
|
||||
return handle != nullptr;
|
||||
}
|
||||
|
||||
void DynamicLibrary::close()
|
||||
{
|
||||
BEAST_TRY
|
||||
{
|
||||
if (handle != nullptr)
|
||||
{
|
||||
FreeLibrary ((HMODULE) handle);
|
||||
handle = nullptr;
|
||||
}
|
||||
}
|
||||
BEAST_CATCH_ALL
|
||||
}
|
||||
|
||||
void* DynamicLibrary::getFunction (const String& functionName) noexcept
|
||||
{
|
||||
return handle != nullptr ? (void*) GetProcAddress ((HMODULE) handle, functionName.toUTF8()) // (void* cast is required for mingw)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class InterProcessLock::Pimpl
|
||||
{
|
||||
public:
|
||||
Pimpl (String name, const int timeOutMillisecs)
|
||||
: handle (0), refCount (1)
|
||||
{
|
||||
name = name.replaceCharacter ('\\', '/');
|
||||
handle = CreateMutexW (0, TRUE, ("Global\\" + name).toWideCharPointer());
|
||||
|
||||
// Not 100% sure why a global mutex sometimes can't be allocated, but if it fails, fall back to
|
||||
// a local one. (A local one also sometimes fails on other machines so neither type appears to be
|
||||
// universally reliable)
|
||||
if (handle == 0)
|
||||
handle = CreateMutexW (0, TRUE, ("Local\\" + name).toWideCharPointer());
|
||||
|
||||
if (handle != 0 && GetLastError() == ERROR_ALREADY_EXISTS)
|
||||
{
|
||||
if (timeOutMillisecs == 0)
|
||||
{
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (WaitForSingleObject (handle, timeOutMillisecs < 0 ? INFINITE : timeOutMillisecs))
|
||||
{
|
||||
case WAIT_OBJECT_0:
|
||||
case WAIT_ABANDONED:
|
||||
break;
|
||||
|
||||
case WAIT_TIMEOUT:
|
||||
default:
|
||||
close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~Pimpl()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
if (handle != 0)
|
||||
{
|
||||
ReleaseMutex (handle);
|
||||
CloseHandle (handle);
|
||||
handle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
HANDLE handle;
|
||||
int refCount;
|
||||
};
|
||||
|
||||
InterProcessLock::InterProcessLock (const String& name_)
|
||||
: name (name_)
|
||||
{
|
||||
}
|
||||
|
||||
InterProcessLock::~InterProcessLock()
|
||||
{
|
||||
}
|
||||
|
||||
bool InterProcessLock::enter (const int timeOutMillisecs)
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
|
||||
if (pimpl == nullptr)
|
||||
{
|
||||
pimpl = new Pimpl (name, timeOutMillisecs);
|
||||
|
||||
if (pimpl->handle == 0)
|
||||
pimpl = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
pimpl->refCount++;
|
||||
}
|
||||
|
||||
return pimpl != nullptr;
|
||||
}
|
||||
|
||||
void InterProcessLock::exit()
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
|
||||
// Trying to release the lock too many times!
|
||||
bassert (pimpl != nullptr);
|
||||
|
||||
if (pimpl != nullptr && --(pimpl->refCount) == 0)
|
||||
pimpl = nullptr;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class ChildProcess::ActiveProcess
|
||||
{
|
||||
public:
|
||||
ActiveProcess (const String& command)
|
||||
: ok (false), readPipe (0), writePipe (0)
|
||||
{
|
||||
SECURITY_ATTRIBUTES securityAtts = { 0 };
|
||||
securityAtts.nLength = sizeof (securityAtts);
|
||||
securityAtts.bInheritHandle = TRUE;
|
||||
|
||||
if (CreatePipe (&readPipe, &writePipe, &securityAtts, 0)
|
||||
&& SetHandleInformation (readPipe, HANDLE_FLAG_INHERIT, 0))
|
||||
{
|
||||
STARTUPINFOW startupInfo = { 0 };
|
||||
startupInfo.cb = sizeof (startupInfo);
|
||||
startupInfo.hStdError = writePipe;
|
||||
startupInfo.hStdOutput = writePipe;
|
||||
startupInfo.dwFlags = STARTF_USESTDHANDLES;
|
||||
|
||||
ok = CreateProcess (nullptr, const_cast <LPWSTR> (command.toWideCharPointer()),
|
||||
nullptr, nullptr, TRUE, CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT,
|
||||
nullptr, nullptr, &startupInfo, &processInfo) != FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
~ActiveProcess()
|
||||
{
|
||||
if (ok)
|
||||
{
|
||||
CloseHandle (processInfo.hThread);
|
||||
CloseHandle (processInfo.hProcess);
|
||||
}
|
||||
|
||||
if (readPipe != 0)
|
||||
CloseHandle (readPipe);
|
||||
|
||||
if (writePipe != 0)
|
||||
CloseHandle (writePipe);
|
||||
}
|
||||
|
||||
bool isRunning() const
|
||||
{
|
||||
return WaitForSingleObject (processInfo.hProcess, 0) != WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
int read (void* dest, int numNeeded) const
|
||||
{
|
||||
int total = 0;
|
||||
|
||||
while (ok && numNeeded > 0)
|
||||
{
|
||||
DWORD available = 0;
|
||||
|
||||
if (! PeekNamedPipe ((HANDLE) readPipe, nullptr, 0, nullptr, &available, nullptr))
|
||||
break;
|
||||
|
||||
const int numToDo = bmin ((int) available, numNeeded);
|
||||
|
||||
if (available == 0)
|
||||
{
|
||||
if (! isRunning())
|
||||
break;
|
||||
|
||||
Thread::yield();
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD numRead = 0;
|
||||
if (! ReadFile ((HANDLE) readPipe, dest, numToDo, &numRead, nullptr))
|
||||
break;
|
||||
|
||||
total += numRead;
|
||||
dest = addBytesToPointer (dest, numRead);
|
||||
numNeeded -= numRead;
|
||||
}
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
bool killProcess() const
|
||||
{
|
||||
return TerminateProcess (processInfo.hProcess, 0) != FALSE;
|
||||
}
|
||||
|
||||
bool ok;
|
||||
|
||||
private:
|
||||
HANDLE readPipe, writePipe;
|
||||
PROCESS_INFORMATION processInfo;
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ActiveProcess)
|
||||
};
|
||||
|
||||
bool ChildProcess::start (const String& command)
|
||||
{
|
||||
activeProcess = new ActiveProcess (command);
|
||||
|
||||
if (! activeProcess->ok)
|
||||
activeProcess = nullptr;
|
||||
|
||||
return activeProcess != nullptr;
|
||||
}
|
||||
|
||||
bool ChildProcess::start (const StringArray& args)
|
||||
{
|
||||
return start (args.joinIntoString (" "));
|
||||
}
|
||||
|
||||
bool ChildProcess::isRunning() const
|
||||
{
|
||||
return activeProcess != nullptr && activeProcess->isRunning();
|
||||
}
|
||||
|
||||
int ChildProcess::readProcessOutput (void* dest, int numBytes)
|
||||
{
|
||||
return activeProcess != nullptr ? activeProcess->read (dest, numBytes) : 0;
|
||||
}
|
||||
|
||||
bool ChildProcess::kill()
|
||||
{
|
||||
return activeProcess == nullptr || activeProcess->killProcess();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct HighResolutionTimer::Pimpl
|
||||
{
|
||||
Pimpl (HighResolutionTimer& t) noexcept : owner (t), periodMs (0)
|
||||
{
|
||||
}
|
||||
|
||||
~Pimpl()
|
||||
{
|
||||
bassert (periodMs == 0);
|
||||
}
|
||||
|
||||
void start (int newPeriod)
|
||||
{
|
||||
if (newPeriod != periodMs)
|
||||
{
|
||||
stop();
|
||||
periodMs = newPeriod;
|
||||
|
||||
TIMECAPS tc;
|
||||
if (timeGetDevCaps (&tc, sizeof (tc)) == TIMERR_NOERROR)
|
||||
{
|
||||
const int actualPeriod = blimit ((int) tc.wPeriodMin, (int) tc.wPeriodMax, newPeriod);
|
||||
|
||||
timerID = timeSetEvent (actualPeriod, tc.wPeriodMin, callbackFunction, (DWORD_PTR) this,
|
||||
TIME_PERIODIC | TIME_CALLBACK_FUNCTION | 0x100 /*TIME_KILL_SYNCHRONOUS*/);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
periodMs = 0;
|
||||
timeKillEvent (timerID);
|
||||
}
|
||||
|
||||
HighResolutionTimer& owner;
|
||||
int periodMs;
|
||||
|
||||
private:
|
||||
unsigned int timerID;
|
||||
|
||||
static void __stdcall callbackFunction (UINT, UINT, DWORD_PTR userInfo, DWORD_PTR, DWORD_PTR)
|
||||
{
|
||||
if (Pimpl* const timer = reinterpret_cast<Pimpl*> (userInfo))
|
||||
if (timer->periodMs != 0)
|
||||
timer->owner.hiResTimerCallback();
|
||||
}
|
||||
|
||||
BEAST_DECLARE_NON_COPYABLE (Pimpl)
|
||||
};
|
||||
697
modules/beast_core/native/java/BeastAppActivity.java
Normal file
697
modules/beast_core/native/java/BeastAppActivity.java
Normal file
@@ -0,0 +1,697 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
package com.beast;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.*;
|
||||
import android.view.inputmethod.BaseInputConnection;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.graphics.*;
|
||||
import android.opengl.*;
|
||||
import android.text.ClipboardManager;
|
||||
import android.text.InputType;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.net.HttpURLConnection;
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
import android.media.MediaScannerConnection;
|
||||
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
|
||||
|
||||
//==============================================================================
|
||||
public final class BeastAppActivity extends Activity
|
||||
{
|
||||
//==============================================================================
|
||||
static
|
||||
{
|
||||
System.loadLibrary ("beast_jni");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onCreate (Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate (savedInstanceState);
|
||||
|
||||
viewHolder = new ViewHolder (this);
|
||||
setContentView (viewHolder);
|
||||
|
||||
setVolumeControlStream (AudioManager.STREAM_MUSIC);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void onDestroy()
|
||||
{
|
||||
quitApp();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void onPause()
|
||||
{
|
||||
if (viewHolder != null)
|
||||
viewHolder.onPause();
|
||||
|
||||
suspendApp();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
|
||||
if (viewHolder != null)
|
||||
viewHolder.onResume();
|
||||
|
||||
resumeApp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged (Configuration cfg)
|
||||
{
|
||||
super.onConfigurationChanged (cfg);
|
||||
setContentView (viewHolder);
|
||||
}
|
||||
|
||||
private void callAppLauncher()
|
||||
{
|
||||
launchApp (getApplicationInfo().publicSourceDir,
|
||||
getApplicationInfo().dataDir);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
private native void launchApp (String appFile, String appDataDir);
|
||||
private native void quitApp();
|
||||
private native void suspendApp();
|
||||
private native void resumeApp();
|
||||
private native void setScreenSize (int screenWidth, int screenHeight);
|
||||
|
||||
//==============================================================================
|
||||
public native void deliverMessage (long value);
|
||||
private android.os.Handler messageHandler = new android.os.Handler();
|
||||
|
||||
public final void postMessage (long value)
|
||||
{
|
||||
messageHandler.post (new MessageCallback (value));
|
||||
}
|
||||
|
||||
private final class MessageCallback implements Runnable
|
||||
{
|
||||
public MessageCallback (long value_) { value = value_; }
|
||||
public final void run() { deliverMessage (value); }
|
||||
|
||||
private long value;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
private ViewHolder viewHolder;
|
||||
|
||||
public final ComponentPeerView createNewView (boolean opaque)
|
||||
{
|
||||
ComponentPeerView v = new ComponentPeerView (this, opaque);
|
||||
viewHolder.addView (v);
|
||||
return v;
|
||||
}
|
||||
|
||||
public final void deleteView (ComponentPeerView view)
|
||||
{
|
||||
ViewGroup group = (ViewGroup) (view.getParent());
|
||||
|
||||
if (group != null)
|
||||
group.removeView (view);
|
||||
}
|
||||
|
||||
final class ViewHolder extends ViewGroup
|
||||
{
|
||||
public ViewHolder (Context context)
|
||||
{
|
||||
super (context);
|
||||
setDescendantFocusability (ViewGroup.FOCUS_AFTER_DESCENDANTS);
|
||||
setFocusable (false);
|
||||
}
|
||||
|
||||
protected final void onLayout (boolean changed, int left, int top, int right, int bottom)
|
||||
{
|
||||
setScreenSize (getWidth(), getHeight());
|
||||
|
||||
if (isFirstResize)
|
||||
{
|
||||
isFirstResize = false;
|
||||
callAppLauncher();
|
||||
}
|
||||
}
|
||||
|
||||
public final void onPause()
|
||||
{
|
||||
for (int i = getChildCount(); --i >= 0;)
|
||||
{
|
||||
View v = getChildAt (i);
|
||||
|
||||
if (v instanceof ComponentPeerView)
|
||||
((ComponentPeerView) v).onPause();
|
||||
}
|
||||
}
|
||||
|
||||
public final void onResume()
|
||||
{
|
||||
for (int i = getChildCount(); --i >= 0;)
|
||||
{
|
||||
View v = getChildAt (i);
|
||||
|
||||
if (v instanceof ComponentPeerView)
|
||||
((ComponentPeerView) v).onResume();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isFirstResize = true;
|
||||
}
|
||||
|
||||
public final void excludeClipRegion (android.graphics.Canvas canvas, float left, float top, float right, float bottom)
|
||||
{
|
||||
canvas.clipRect (left, top, right, bottom, android.graphics.Region.Op.DIFFERENCE);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
public final String getClipboardContent()
|
||||
{
|
||||
ClipboardManager clipboard = (ClipboardManager) getSystemService (CLIPBOARD_SERVICE);
|
||||
return clipboard.getText().toString();
|
||||
}
|
||||
|
||||
public final void setClipboardContent (String newText)
|
||||
{
|
||||
ClipboardManager clipboard = (ClipboardManager) getSystemService (CLIPBOARD_SERVICE);
|
||||
clipboard.setText (newText);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
public final void showMessageBox (String title, String message, final long callback)
|
||||
{
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder (this);
|
||||
builder.setTitle (title)
|
||||
.setMessage (message)
|
||||
.setCancelable (true)
|
||||
.setPositiveButton ("OK", new DialogInterface.OnClickListener()
|
||||
{
|
||||
public void onClick (DialogInterface dialog, int id)
|
||||
{
|
||||
dialog.cancel();
|
||||
BeastAppActivity.this.alertDismissed (callback, 0);
|
||||
}
|
||||
});
|
||||
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
public final void showOkCancelBox (String title, String message, final long callback)
|
||||
{
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder (this);
|
||||
builder.setTitle (title)
|
||||
.setMessage (message)
|
||||
.setCancelable (true)
|
||||
.setPositiveButton ("OK", new DialogInterface.OnClickListener()
|
||||
{
|
||||
public void onClick (DialogInterface dialog, int id)
|
||||
{
|
||||
dialog.cancel();
|
||||
BeastAppActivity.this.alertDismissed (callback, 1);
|
||||
}
|
||||
})
|
||||
.setNegativeButton ("Cancel", new DialogInterface.OnClickListener()
|
||||
{
|
||||
public void onClick (DialogInterface dialog, int id)
|
||||
{
|
||||
dialog.cancel();
|
||||
BeastAppActivity.this.alertDismissed (callback, 0);
|
||||
}
|
||||
});
|
||||
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
public final void showYesNoCancelBox (String title, String message, final long callback)
|
||||
{
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder (this);
|
||||
builder.setTitle (title)
|
||||
.setMessage (message)
|
||||
.setCancelable (true)
|
||||
.setPositiveButton ("Yes", new DialogInterface.OnClickListener()
|
||||
{
|
||||
public void onClick (DialogInterface dialog, int id)
|
||||
{
|
||||
dialog.cancel();
|
||||
BeastAppActivity.this.alertDismissed (callback, 1);
|
||||
}
|
||||
})
|
||||
.setNegativeButton ("No", new DialogInterface.OnClickListener()
|
||||
{
|
||||
public void onClick (DialogInterface dialog, int id)
|
||||
{
|
||||
dialog.cancel();
|
||||
BeastAppActivity.this.alertDismissed (callback, 2);
|
||||
}
|
||||
})
|
||||
.setNeutralButton ("Cancel", new DialogInterface.OnClickListener()
|
||||
{
|
||||
public void onClick (DialogInterface dialog, int id)
|
||||
{
|
||||
dialog.cancel();
|
||||
BeastAppActivity.this.alertDismissed (callback, 0);
|
||||
}
|
||||
});
|
||||
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
public native void alertDismissed (long callback, int id);
|
||||
|
||||
//==============================================================================
|
||||
public final class ComponentPeerView extends ViewGroup
|
||||
implements View.OnFocusChangeListener
|
||||
{
|
||||
public ComponentPeerView (Context context, boolean opaque_)
|
||||
{
|
||||
super (context);
|
||||
setWillNotDraw (false);
|
||||
opaque = opaque_;
|
||||
|
||||
setFocusable (true);
|
||||
setFocusableInTouchMode (true);
|
||||
setOnFocusChangeListener (this);
|
||||
requestFocus();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
private native void handlePaint (Canvas canvas);
|
||||
|
||||
@Override
|
||||
public void draw (Canvas canvas)
|
||||
{
|
||||
super.draw (canvas);
|
||||
handlePaint (canvas);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpaque()
|
||||
{
|
||||
return opaque;
|
||||
}
|
||||
|
||||
private boolean opaque;
|
||||
|
||||
//==============================================================================
|
||||
private native void handleMouseDown (int index, float x, float y, long time);
|
||||
private native void handleMouseDrag (int index, float x, float y, long time);
|
||||
private native void handleMouseUp (int index, float x, float y, long time);
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent (MotionEvent event)
|
||||
{
|
||||
int action = event.getAction();
|
||||
long time = event.getEventTime();
|
||||
|
||||
switch (action & MotionEvent.ACTION_MASK)
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
handleMouseDown (event.getPointerId(0), event.getX(), event.getY(), time);
|
||||
return true;
|
||||
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
case MotionEvent.ACTION_UP:
|
||||
handleMouseUp (event.getPointerId(0), event.getX(), event.getY(), time);
|
||||
return true;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
{
|
||||
int n = event.getPointerCount();
|
||||
for (int i = 0; i < n; ++i)
|
||||
handleMouseDrag (event.getPointerId(i), event.getX(i), event.getY(i), time);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
{
|
||||
int i = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
|
||||
handleMouseUp (event.getPointerId(i), event.getX(i), event.getY(i), time);
|
||||
return true;
|
||||
}
|
||||
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
{
|
||||
int i = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
|
||||
handleMouseDown (event.getPointerId(i), event.getX(i), event.getY(i), time);
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
private native void handleKeyDown (int keycode, int textchar);
|
||||
private native void handleKeyUp (int keycode, int textchar);
|
||||
|
||||
public void showKeyboard (boolean shouldShow)
|
||||
{
|
||||
InputMethodManager imm = (InputMethodManager) getSystemService (Context.INPUT_METHOD_SERVICE);
|
||||
|
||||
if (imm != null)
|
||||
{
|
||||
if (shouldShow)
|
||||
imm.showSoftInput (this, InputMethodManager.SHOW_FORCED);
|
||||
else
|
||||
imm.hideSoftInputFromWindow (getWindowToken(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown (int keyCode, KeyEvent event)
|
||||
{
|
||||
handleKeyDown (keyCode, event.getUnicodeChar());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp (int keyCode, KeyEvent event)
|
||||
{
|
||||
handleKeyUp (keyCode, event.getUnicodeChar());
|
||||
return true;
|
||||
}
|
||||
|
||||
// this is here to make keyboard entry work on a Galaxy Tab2 10.1
|
||||
@Override
|
||||
public InputConnection onCreateInputConnection (EditorInfo outAttrs)
|
||||
{
|
||||
outAttrs.actionLabel = "";
|
||||
outAttrs.hintText = "";
|
||||
outAttrs.initialCapsMode = 0;
|
||||
outAttrs.initialSelEnd = outAttrs.initialSelStart = -1;
|
||||
outAttrs.label = "";
|
||||
outAttrs.imeOptions = EditorInfo.IME_ACTION_DONE | EditorInfo.IME_FLAG_NO_EXTRACT_UI;
|
||||
outAttrs.inputType = InputType.TYPE_NULL;
|
||||
|
||||
return new BaseInputConnection (this, false);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
@Override
|
||||
protected void onSizeChanged (int w, int h, int oldw, int oldh)
|
||||
{
|
||||
super.onSizeChanged (w, h, oldw, oldh);
|
||||
viewSizeChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout (boolean changed, int left, int top, int right, int bottom)
|
||||
{
|
||||
for (int i = getChildCount(); --i >= 0;)
|
||||
requestTransparentRegion (getChildAt (i));
|
||||
}
|
||||
|
||||
private native void viewSizeChanged();
|
||||
|
||||
@Override
|
||||
public void onFocusChange (View v, boolean hasFocus)
|
||||
{
|
||||
if (v == this)
|
||||
focusChanged (hasFocus);
|
||||
}
|
||||
|
||||
private native void focusChanged (boolean hasFocus);
|
||||
|
||||
public void setViewName (String newName) {}
|
||||
|
||||
public boolean isVisible() { return getVisibility() == VISIBLE; }
|
||||
public void setVisible (boolean b) { setVisibility (b ? VISIBLE : INVISIBLE); }
|
||||
|
||||
public boolean containsPoint (int x, int y)
|
||||
{
|
||||
return true; //xxx needs to check overlapping views
|
||||
}
|
||||
|
||||
public final void onPause()
|
||||
{
|
||||
for (int i = getChildCount(); --i >= 0;)
|
||||
{
|
||||
View v = getChildAt (i);
|
||||
|
||||
if (v instanceof OpenGLView)
|
||||
((OpenGLView) v).onPause();
|
||||
}
|
||||
}
|
||||
|
||||
public final void onResume()
|
||||
{
|
||||
for (int i = getChildCount(); --i >= 0;)
|
||||
{
|
||||
View v = getChildAt (i);
|
||||
|
||||
if (v instanceof OpenGLView)
|
||||
((OpenGLView) v).onResume();
|
||||
}
|
||||
}
|
||||
|
||||
public OpenGLView createGLView()
|
||||
{
|
||||
OpenGLView glView = new OpenGLView (getContext());
|
||||
addView (glView);
|
||||
return glView;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
public final class OpenGLView extends GLSurfaceView
|
||||
implements GLSurfaceView.Renderer
|
||||
{
|
||||
OpenGLView (Context context)
|
||||
{
|
||||
super (context);
|
||||
setEGLContextClientVersion (2);
|
||||
setRenderer (this);
|
||||
setRenderMode (RENDERMODE_WHEN_DIRTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceCreated (GL10 unused, EGLConfig config)
|
||||
{
|
||||
contextCreated();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceChanged (GL10 unused, int width, int height)
|
||||
{
|
||||
contextChangedSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrawFrame (GL10 unused)
|
||||
{
|
||||
render();
|
||||
}
|
||||
|
||||
private native void contextCreated();
|
||||
private native void contextChangedSize();
|
||||
private native void render();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
public final int[] renderGlyph (char glyph, Paint paint, android.graphics.Matrix matrix, Rect bounds)
|
||||
{
|
||||
Path p = new Path();
|
||||
paint.getTextPath (String.valueOf (glyph), 0, 1, 0.0f, 0.0f, p);
|
||||
|
||||
RectF boundsF = new RectF();
|
||||
p.computeBounds (boundsF, true);
|
||||
matrix.mapRect (boundsF);
|
||||
|
||||
boundsF.roundOut (bounds);
|
||||
bounds.left--;
|
||||
bounds.right++;
|
||||
|
||||
final int w = bounds.width();
|
||||
final int h = Math.max (1, bounds.height());
|
||||
|
||||
Bitmap bm = Bitmap.createBitmap (w, h, Bitmap.Config.ARGB_8888);
|
||||
|
||||
Canvas c = new Canvas (bm);
|
||||
matrix.postTranslate (-bounds.left, -bounds.top);
|
||||
c.setMatrix (matrix);
|
||||
c.drawPath (p, paint);
|
||||
|
||||
final int sizeNeeded = w * h;
|
||||
if (cachedRenderArray.length < sizeNeeded)
|
||||
cachedRenderArray = new int [sizeNeeded];
|
||||
|
||||
bm.getPixels (cachedRenderArray, 0, w, 0, 0, w, h);
|
||||
bm.recycle();
|
||||
return cachedRenderArray;
|
||||
}
|
||||
|
||||
private int[] cachedRenderArray = new int [256];
|
||||
|
||||
//==============================================================================
|
||||
public static class HTTPStream
|
||||
{
|
||||
public HTTPStream (HttpURLConnection connection_) throws IOException
|
||||
{
|
||||
connection = connection_;
|
||||
inputStream = new BufferedInputStream (connection.getInputStream());
|
||||
}
|
||||
|
||||
public final void release()
|
||||
{
|
||||
try
|
||||
{
|
||||
inputStream.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{}
|
||||
|
||||
connection.disconnect();
|
||||
}
|
||||
|
||||
public final int read (byte[] buffer, int numBytes)
|
||||
{
|
||||
int num = 0;
|
||||
|
||||
try
|
||||
{
|
||||
num = inputStream.read (buffer, 0, numBytes);
|
||||
}
|
||||
catch (IOException e)
|
||||
{}
|
||||
|
||||
if (num > 0)
|
||||
position += num;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
public final long getPosition() { return position; }
|
||||
public final long getTotalLength() { return -1; }
|
||||
public final boolean isExhausted() { return false; }
|
||||
public final boolean setPosition (long newPos) { return false; }
|
||||
|
||||
private HttpURLConnection connection;
|
||||
private InputStream inputStream;
|
||||
private long position;
|
||||
}
|
||||
|
||||
public static final HTTPStream createHTTPStream (String address, boolean isPost, byte[] postData,
|
||||
String headers, int timeOutMs,
|
||||
java.lang.StringBuffer responseHeaders)
|
||||
{
|
||||
try
|
||||
{
|
||||
HttpURLConnection connection = (HttpURLConnection) (new URL (address).openConnection());
|
||||
|
||||
if (connection != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (isPost)
|
||||
{
|
||||
connection.setConnectTimeout (timeOutMs);
|
||||
connection.setDoOutput (true);
|
||||
connection.setChunkedStreamingMode (0);
|
||||
|
||||
OutputStream out = connection.getOutputStream();
|
||||
out.write (postData);
|
||||
out.flush();
|
||||
}
|
||||
|
||||
return new HTTPStream (connection);
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable e)
|
||||
{}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public final void launchURL (String url)
|
||||
{
|
||||
startActivity (new Intent (Intent.ACTION_VIEW, Uri.parse (url)));
|
||||
}
|
||||
|
||||
public static final String getLocaleValue (boolean isRegion)
|
||||
{
|
||||
java.util.Locale locale = java.util.Locale.getDefault();
|
||||
|
||||
return isRegion ? locale.getDisplayCountry (java.util.Locale.US)
|
||||
: locale.getDisplayLanguage (java.util.Locale.US);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
private final class SingleMediaScanner implements MediaScannerConnectionClient
|
||||
{
|
||||
public SingleMediaScanner (Context context, String filename)
|
||||
{
|
||||
file = filename;
|
||||
msc = new MediaScannerConnection (context, this);
|
||||
msc.connect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMediaScannerConnected()
|
||||
{
|
||||
msc.scanFile (file, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScanCompleted (String path, Uri uri)
|
||||
{
|
||||
msc.disconnect();
|
||||
}
|
||||
|
||||
private MediaScannerConnection msc;
|
||||
private String file;
|
||||
}
|
||||
|
||||
public final void scanFile (String filename)
|
||||
{
|
||||
new SingleMediaScanner (this, filename);
|
||||
}
|
||||
}
|
||||
144
modules/beast_core/network/beast_IPAddress.cpp
Normal file
144
modules/beast_core/network/beast_IPAddress.cpp
Normal file
@@ -0,0 +1,144 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
IPAddress::IPAddress() noexcept
|
||||
{
|
||||
address[0] = 0; address[1] = 0;
|
||||
address[2] = 0; address[3] = 0;
|
||||
}
|
||||
|
||||
IPAddress::IPAddress (const uint8 bytes[4]) noexcept
|
||||
{
|
||||
address[0] = bytes[0]; address[1] = bytes[1];
|
||||
address[2] = bytes[2]; address[3] = bytes[3];
|
||||
}
|
||||
|
||||
IPAddress::IPAddress (uint8 a0, uint8 a1, uint8 a2, uint8 a3) noexcept
|
||||
{
|
||||
address[0] = a0; address[1] = a1;
|
||||
address[2] = a2; address[3] = a3;
|
||||
}
|
||||
|
||||
IPAddress::IPAddress (uint32 n) noexcept
|
||||
{
|
||||
address[0] = (n >> 24);
|
||||
address[1] = (n >> 16) & 255;
|
||||
address[2] = (n >> 8) & 255;
|
||||
address[3] = (n & 255);
|
||||
}
|
||||
|
||||
IPAddress::IPAddress (const String& adr)
|
||||
{
|
||||
StringArray tokens;
|
||||
tokens.addTokens (adr, ".", String::empty);
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
address[i] = (uint8) tokens[i].getIntValue();
|
||||
}
|
||||
|
||||
String IPAddress::toString() const
|
||||
{
|
||||
String s ((int) address[0]);
|
||||
|
||||
for (int i = 1; i < 4; ++i)
|
||||
s << '.' << (int) address[i];
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
IPAddress IPAddress::any() noexcept { return IPAddress(); }
|
||||
IPAddress IPAddress::broadcast() noexcept { return IPAddress (255, 255, 255, 255); }
|
||||
IPAddress IPAddress::local() noexcept { return IPAddress (127, 0, 0, 1); }
|
||||
|
||||
bool IPAddress::operator== (const IPAddress& other) const noexcept
|
||||
{
|
||||
return address[0] == other.address[0]
|
||||
&& address[1] == other.address[1]
|
||||
&& address[2] == other.address[2]
|
||||
&& address[3] == other.address[3];
|
||||
}
|
||||
|
||||
bool IPAddress::operator!= (const IPAddress& other) const noexcept
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
#if ! BEAST_WINDOWS
|
||||
static void addAddress (const sockaddr_in* addr_in, Array<IPAddress>& result)
|
||||
{
|
||||
in_addr_t addr = addr_in->sin_addr.s_addr;
|
||||
|
||||
if (addr != INADDR_NONE)
|
||||
result.addIfNotAlreadyThere (IPAddress (ntohl (addr)));
|
||||
}
|
||||
|
||||
static void findIPAddresses (int sock, Array<IPAddress>& result)
|
||||
{
|
||||
ifconf cfg;
|
||||
HeapBlock<char> buffer;
|
||||
size_t bufferSize = 1024;
|
||||
|
||||
do
|
||||
{
|
||||
bufferSize *= 2;
|
||||
buffer.calloc (bufferSize);
|
||||
|
||||
cfg.ifc_len = bufferSize;
|
||||
cfg.ifc_buf = buffer;
|
||||
|
||||
if (ioctl (sock, SIOCGIFCONF, &cfg) < 0 && errno != EINVAL)
|
||||
return;
|
||||
|
||||
} while (bufferSize < cfg.ifc_len + 2 * (IFNAMSIZ + sizeof (struct sockaddr_in6)));
|
||||
|
||||
#if BEAST_MAC || BEAST_IOS
|
||||
while (cfg.ifc_len >= (int) (IFNAMSIZ + sizeof (struct sockaddr_in)))
|
||||
{
|
||||
if (cfg.ifc_req->ifr_addr.sa_family == AF_INET) // Skip non-internet addresses
|
||||
addAddress ((const sockaddr_in*) &cfg.ifc_req->ifr_addr, result);
|
||||
|
||||
cfg.ifc_len -= IFNAMSIZ + cfg.ifc_req->ifr_addr.sa_len;
|
||||
cfg.ifc_buf += IFNAMSIZ + cfg.ifc_req->ifr_addr.sa_len;
|
||||
}
|
||||
#else
|
||||
for (int i = 0; i < cfg.ifc_len / sizeof (struct ifreq); ++i)
|
||||
{
|
||||
const ifreq& item = cfg.ifc_req[i];
|
||||
|
||||
if (item.ifr_addr.sa_family == AF_INET)
|
||||
addAddress ((const sockaddr_in*) &item.ifr_addr, result);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void IPAddress::findAllAddresses (Array<IPAddress>& result)
|
||||
{
|
||||
const int sock = socket (AF_INET, SOCK_DGRAM, 0); // a dummy socket to execute the IO control
|
||||
|
||||
if (sock >= 0)
|
||||
{
|
||||
findIPAddresses (sock, result);
|
||||
::close (sock);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
77
modules/beast_core/network/beast_IPAddress.h
Normal file
77
modules/beast_core/network/beast_IPAddress.h
Normal file
@@ -0,0 +1,77 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_IPADDRESS_BEASTHEADER
|
||||
#define BEAST_IPADDRESS_BEASTHEADER
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
An IPV4 address.
|
||||
*/
|
||||
class BEAST_API IPAddress
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Populates a list of all the IP addresses that this machine is using. */
|
||||
static void findAllAddresses (Array<IPAddress>& results);
|
||||
|
||||
//==============================================================================
|
||||
/** Creates a null address (0.0.0.0). */
|
||||
IPAddress() noexcept;
|
||||
|
||||
/** Creates an address from 4 bytes. */
|
||||
explicit IPAddress (const uint8 bytes[4]) noexcept;
|
||||
|
||||
/** Creates an address from 4 bytes. */
|
||||
IPAddress (uint8 address1, uint8 address2, uint8 address3, uint8 address4) noexcept;
|
||||
|
||||
/** Creates an address from a packed 32-bit integer, where the MSB is
|
||||
the first number in the address, and the LSB is the last.
|
||||
*/
|
||||
explicit IPAddress (uint32 asNativeEndian32Bit) noexcept;
|
||||
|
||||
/** Parses a string IP address of the form "a.b.c.d". */
|
||||
explicit IPAddress (const String& address);
|
||||
|
||||
/** Returns a dot-separated string in the form "1.2.3.4" */
|
||||
String toString() const;
|
||||
|
||||
/** Returns an address meaning "any" (0.0.0.0) */
|
||||
static IPAddress any() noexcept;
|
||||
|
||||
/** Returns an address meaning "broadcast" (255.255.255.255) */
|
||||
static IPAddress broadcast() noexcept;
|
||||
|
||||
/** Returns an address meaning "localhost" (127.0.0.1) */
|
||||
static IPAddress local() noexcept;
|
||||
|
||||
bool operator== (const IPAddress& other) const noexcept;
|
||||
bool operator!= (const IPAddress& other) const noexcept;
|
||||
|
||||
/** The elements of the IP address. */
|
||||
uint8 address[4];
|
||||
};
|
||||
|
||||
|
||||
#endif // BEAST_IPADDRESS_BEASTHEADER
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user