Browse Source

Add juce_core module code

tags/1.9.4
falkTX 12 years ago
parent
commit
585aff42fa
100 changed files with 30360 additions and 0 deletions
  1. +35
    -0
      source/modules/JuceHeader.h
  2. +98
    -0
      source/modules/juce_core/AppConfig.h
  3. +88
    -0
      source/modules/juce_core/Makefile
  4. +234
    -0
      source/modules/juce_core/containers/juce_AbstractFifo.cpp
  5. +222
    -0
      source/modules/juce_core/containers/juce_AbstractFifo.h
  6. +1064
    -0
      source/modules/juce_core/containers/juce_Array.h
  7. +140
    -0
      source/modules/juce_core/containers/juce_ArrayAllocationBase.h
  8. +79
    -0
      source/modules/juce_core/containers/juce_DynamicObject.cpp
  9. +126
    -0
      source/modules/juce_core/containers/juce_DynamicObject.h
  10. +279
    -0
      source/modules/juce_core/containers/juce_ElementComparator.h
  11. +460
    -0
      source/modules/juce_core/containers/juce_HashMap.h
  12. +371
    -0
      source/modules/juce_core/containers/juce_LinkedListPointer.h
  13. +309
    -0
      source/modules/juce_core/containers/juce_NamedValueSet.cpp
  14. +169
    -0
      source/modules/juce_core/containers/juce_NamedValueSet.h
  15. +897
    -0
      source/modules/juce_core/containers/juce_OwnedArray.h
  16. +223
    -0
      source/modules/juce_core/containers/juce_PropertySet.cpp
  17. +219
    -0
      source/modules/juce_core/containers/juce_PropertySet.h
  18. +872
    -0
      source/modules/juce_core/containers/juce_ReferenceCountedArray.h
  19. +100
    -0
      source/modules/juce_core/containers/juce_ScopedValueSetter.h
  20. +497
    -0
      source/modules/juce_core/containers/juce_SortedSet.h
  21. +301
    -0
      source/modules/juce_core/containers/juce_SparseSet.h
  22. +709
    -0
      source/modules/juce_core/containers/juce_Variant.cpp
  23. +307
    -0
      source/modules/juce_core/containers/juce_Variant.h
  24. +159
    -0
      source/modules/juce_core/files/juce_DirectoryIterator.cpp
  25. +162
    -0
      source/modules/juce_core/files/juce_DirectoryIterator.h
  26. +1091
    -0
      source/modules/juce_core/files/juce_File.cpp
  27. +959
    -0
      source/modules/juce_core/files/juce_File.h
  28. +95
    -0
      source/modules/juce_core/files/juce_FileInputStream.cpp
  29. +99
    -0
      source/modules/juce_core/files/juce_FileInputStream.h
  30. +135
    -0
      source/modules/juce_core/files/juce_FileOutputStream.cpp
  31. +119
    -0
      source/modules/juce_core/files/juce_FileOutputStream.h
  32. +171
    -0
      source/modules/juce_core/files/juce_FileSearchPath.cpp
  33. +169
    -0
      source/modules/juce_core/files/juce_FileSearchPath.h
  34. +116
    -0
      source/modules/juce_core/files/juce_MemoryMappedFile.h
  35. +117
    -0
      source/modules/juce_core/files/juce_TemporaryFile.cpp
  36. +171
    -0
      source/modules/juce_core/files/juce_TemporaryFile.h
  37. +650
    -0
      source/modules/juce_core/json/juce_JSON.cpp
  38. +118
    -0
      source/modules/juce_core/json/juce_JSON.h
  39. +218
    -0
      source/modules/juce_core/juce_core.cpp
  40. +253
    -0
      source/modules/juce_core/juce_core.h
  41. +29
    -0
      source/modules/juce_core/juce_core.mm
  42. +38
    -0
      source/modules/juce_core/juce_module_info
  43. +134
    -0
      source/modules/juce_core/logging/juce_FileLogger.cpp
  44. +139
    -0
      source/modules/juce_core/logging/juce_FileLogger.h
  45. +63
    -0
      source/modules/juce_core/logging/juce_Logger.cpp
  46. +99
    -0
      source/modules/juce_core/logging/juce_Logger.h
  47. +1021
    -0
      source/modules/juce_core/maths/juce_BigInteger.cpp
  48. +334
    -0
      source/modules/juce_core/maths/juce_BigInteger.h
  49. +1185
    -0
      source/modules/juce_core/maths/juce_Expression.cpp
  50. +274
    -0
      source/modules/juce_core/maths/juce_Expression.h
  51. +514
    -0
      source/modules/juce_core/maths/juce_MathsFunctions.h
  52. +190
    -0
      source/modules/juce_core/maths/juce_Random.cpp
  53. +143
    -0
      source/modules/juce_core/maths/juce_Random.h
  54. +264
    -0
      source/modules/juce_core/maths/juce_Range.h
  55. +396
    -0
      source/modules/juce_core/memory/juce_Atomic.h
  56. +186
    -0
      source/modules/juce_core/memory/juce_ByteOrder.h
  57. +308
    -0
      source/modules/juce_core/memory/juce_HeapBlock.h
  58. +149
    -0
      source/modules/juce_core/memory/juce_LeakedObjectDetector.h
  59. +126
    -0
      source/modules/juce_core/memory/juce_Memory.h
  60. +421
    -0
      source/modules/juce_core/memory/juce_MemoryBlock.cpp
  61. +260
    -0
      source/modules/juce_core/memory/juce_MemoryBlock.h
  62. +188
    -0
      source/modules/juce_core/memory/juce_OptionalScopedPointer.h
  63. +400
    -0
      source/modules/juce_core/memory/juce_ReferenceCountedObject.h
  64. +253
    -0
      source/modules/juce_core/memory/juce_ScopedPointer.h
  65. +292
    -0
      source/modules/juce_core/memory/juce_Singleton.h
  66. +214
    -0
      source/modules/juce_core/memory/juce_WeakReference.h
  67. +83
    -0
      source/modules/juce_core/misc/juce_Result.cpp
  68. +127
    -0
      source/modules/juce_core/misc/juce_Result.h
  69. +114
    -0
      source/modules/juce_core/misc/juce_Uuid.cpp
  70. +114
    -0
      source/modules/juce_core/misc/juce_Uuid.h
  71. +130
    -0
      source/modules/juce_core/misc/juce_WindowsRegistry.h
  72. +707
    -0
      source/modules/juce_core/native/java/JuceAppActivity.java
  73. +223
    -0
      source/modules/juce_core/native/juce_BasicNativeHeaders.h
  74. +241
    -0
      source/modules/juce_core/native/juce_android_Files.cpp
  75. +407
    -0
      source/modules/juce_core/native/juce_android_JNIHelpers.h
  76. +32
    -0
      source/modules/juce_core/native/juce_android_Misc.cpp
  77. +175
    -0
      source/modules/juce_core/native/juce_android_Network.cpp
  78. +307
    -0
      source/modules/juce_core/native/juce_android_SystemStats.cpp
  79. +81
    -0
      source/modules/juce_core/native/juce_android_Threads.cpp
  80. +378
    -0
      source/modules/juce_core/native/juce_linux_Files.cpp
  81. +462
    -0
      source/modules/juce_core/native/juce_linux_Network.cpp
  82. +181
    -0
      source/modules/juce_core/native/juce_linux_SystemStats.cpp
  83. +94
    -0
      source/modules/juce_core/native/juce_linux_Threads.cpp
  84. +485
    -0
      source/modules/juce_core/native/juce_mac_Files.mm
  85. +432
    -0
      source/modules/juce_core/native/juce_mac_Network.mm
  86. +96
    -0
      source/modules/juce_core/native/juce_mac_Strings.mm
  87. +292
    -0
      source/modules/juce_core/native/juce_mac_SystemStats.mm
  88. +98
    -0
      source/modules/juce_core/native/juce_mac_Threads.mm
  89. +167
    -0
      source/modules/juce_core/native/juce_osx_ObjCHelpers.h
  90. +219
    -0
      source/modules/juce_core/native/juce_posix_NamedPipe.cpp
  91. +1275
    -0
      source/modules/juce_core/native/juce_posix_SharedCode.h
  92. +170
    -0
      source/modules/juce_core/native/juce_win32_ComSmartPtr.h
  93. +961
    -0
      source/modules/juce_core/native/juce_win32_Files.cpp
  94. +469
    -0
      source/modules/juce_core/native/juce_win32_Network.cpp
  95. +236
    -0
      source/modules/juce_core/native/juce_win32_Registry.cpp
  96. +435
    -0
      source/modules/juce_core/native/juce_win32_SystemStats.cpp
  97. +639
    -0
      source/modules/juce_core/native/juce_win32_Threads.cpp
  98. +149
    -0
      source/modules/juce_core/network/juce_IPAddress.cpp
  99. +82
    -0
      source/modules/juce_core/network/juce_IPAddress.h
  100. +78
    -0
      source/modules/juce_core/network/juce_MACAddress.cpp

+ 35
- 0
source/modules/JuceHeader.h View File

@@ -0,0 +1,35 @@
/*
* Carla Juce setup
* Copyright (C) 2013 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/
#ifndef CARLA_JUCE_HEADER_H_INCLUDED
#define CARLA_JUCE_HEADER_H_INCLUDED
#include "juce_core/AppConfig.h"
#include "juce_core/juce_core.h"
//#include "modules/juce_audio_basics/juce_audio_basics.h"
//#include "modules/juce_audio_devices/juce_audio_devices.h"
//#include "modules/juce_audio_formats/juce_audio_formats.h"
//#include "modules/juce_audio_processors/juce_audio_processors.h"
//#include "modules/juce_audio_utils/juce_audio_utils.h"
//#include "modules/juce_data_structures/juce_data_structures.h"
//#include "modules/juce_events/juce_events.h"
//#include "modules/juce_graphics/juce_graphics.h"
//#include "modules/juce_gui_basics/juce_gui_basics.h"
//#include "modules/juce_gui_extra/juce_gui_extra.h"
#endif // CARLA_JUCE_HEADER_H_INCLUDED

+ 98
- 0
source/modules/juce_core/AppConfig.h View File

@@ -0,0 +1,98 @@
/*
==============================================================================
Build options for juce_core static library
==============================================================================
*/
#ifndef CARLA_JUCE_CORE_APPCONFIG_H_INCLUDED
#define CARLA_JUCE_CORE_APPCONFIG_H_INCLUDED
//=============================================================================
/** Config: JUCE_FORCE_DEBUG
Normally, JUCE_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.
*/
#if DEBUG
#define JUCE_FORCE_DEBUG 1
#else
#define JUCE_FORCE_DEBUG 0
#endif
//=============================================================================
/** Config: JUCE_LOG_ASSERTIONS
If this flag is enabled, the the jassert 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 jassert and jassertfalse macros will not be compiled in a
release build.
@see jassert, jassertfalse, Logger
*/
#if DEBUG
#define JUCE_LOG_ASSERTIONS 1
#else
#define JUCE_LOG_ASSERTIONS 0
#endif
//=============================================================================
/** Config: JUCE_CHECK_MEMORY_LEAKS
Enables a memory-leak check for certain objects when the app terminates. See the LeakedObjectDetector
class and the JUCE_LEAK_DETECTOR macro for more details about enabling leak checking for specific classes.
*/
//#if DEBUG
#define JUCE_CHECK_MEMORY_LEAKS 1
//#else
// #define JUCE_CHECK_MEMORY_LEAKS 0
//#endif
//=============================================================================
/** Config: JUCE_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.
*/
#define JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES 0
/* Config: JUCE_INCLUDE_ZLIB_CODE
This can be used to disable Juce'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 JUCE_ZLIB_INCLUDE_PATH, to
specify the path where your zlib headers live.
*/
#define JUCE_INCLUDE_ZLIB_CODE 1
//#define JUCE_ZLIB_INCLUDE_PATH <zlib.h>
/* Config: JUCE_CATCH_UNHANDLED_EXCEPTIONS
If enabled, this will add some exception-catching code to forward unhandled exceptions
to your JUCEApplication::unhandledException() callback.
*/
#if DEBUG
#define JUCE_CATCH_UNHANDLED_EXCEPTIONS 1
#else
#define JUCE_CATCH_UNHANDLED_EXCEPTIONS 0
#endif
#define JUCE_MODULE_AVAILABLE_juce_audio_basics 1
#define JUCE_MODULE_AVAILABLE_juce_audio_devices 1
#define JUCE_MODULE_AVAILABLE_juce_audio_formats 1
#define JUCE_MODULE_AVAILABLE_juce_audio_processors 0
#define JUCE_MODULE_AVAILABLE_juce_audio_utils 0
#define JUCE_MODULE_AVAILABLE_juce_core 1
#define JUCE_MODULE_AVAILABLE_juce_cryptography 0
#define JUCE_MODULE_AVAILABLE_juce_data_structures 0
#define JUCE_MODULE_AVAILABLE_juce_events 1
#define JUCE_MODULE_AVAILABLE_juce_graphics 0
#define JUCE_MODULE_AVAILABLE_juce_gui_basics 0
#define JUCE_MODULE_AVAILABLE_juce_gui_extra 0
#define JUCE_MODULE_AVAILABLE_juce_opengl 0
#define JUCE_MODULE_AVAILABLE_juce_video 0
#endif // CARLA_JUCE_CORE_APPCONFIG_H_INCLUDED

+ 88
- 0
source/modules/juce_core/Makefile View File

@@ -0,0 +1,88 @@
#!/usr/bin/make -f
# Makefile for juce_core #
# ---------------------- #
# Created by falkTX
#

include ../../Makefile.mk

# --------------------------------------------------------------

BUILD_CXX_FLAGS += -I.

ifeq ($(MACOS),true)
BUILD_CXX_FLAGS += -objc++
OBJS = juce_core.mm.o
OBJS_posix32 = juce_core.mm.posix32.o
OBJS_posix64 = juce_core.mm.posix64.o
else
OBJS = juce_core.cpp.o
OBJS_posix32 = juce_core.cpp.posix32.o
OBJS_posix64 = juce_core.cpp.posix64.o
endif

OBJS_win32 = juce_core.cpp.win32.o
OBJS_win64 = juce_core.cpp.win64.o

# --------------------------------------------------------------

all: ../juce_core.a

posix32: ../juce_core.posix32.a
posix64: ../juce_core.posix64.a
win32: ../juce_core.win32.a
win64: ../juce_core.win64.a

# --------------------------------------------------------------

../juce_core.a: $(OBJS)
$(AR) rs $@ $^

../juce_core.posix32.a: $(OBJS_posix32)
$(AR) rs $@ $^

../juce_core.posix64.a: $(OBJS_posix64)
$(AR) rs $@ $^

../juce_core.win32.a: $(OBJS_win32)
$(AR) rs $@ $^

../juce_core.win64.a: $(OBJS_win64)
$(AR) rs $@ $^

../juce_core.dll: $(OBJS)
$(CXX) $^ -shared $(LINK_FLAGS) -o $@ $(CMD_STRIP) $@

../juce_core.dylib: $(OBJS)
$(CXX) $^ -dynamiclib $(LINK_FLAGS) -o $@ $(CMD_STRIP) $@

../juce_core.so: $(OBJS)
$(CXX) $^ -shared $(LINK_FLAGS) -o $@ $(CMD_STRIP) $@

# --------------------------------------------------------------

%.cpp.o: %.cpp
$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@

%.mm.o: %.mm
$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@

%.posix32.o: %
$(CXX) $< $(BUILD_CXX_FLAGS) $(32BIT_FLAGS) -c -o $@

%.posix64.o: %
$(CXX) $< $(BUILD_CXX_FLAGS) $(64BIT_FLAGS) -c -o $@

%.win32.o: %
$(CXX) $< $(BUILD_CXX_FLAGS) $(32BIT_FLAGS) -c -o $@

%.win64.o: %
$(CXX) $< $(BUILD_CXX_FLAGS) $(64BIT_FLAGS) -c -o $@

# --------------------------------------------------------------

clean:
rm -f *.o ../juce_core.*

debug:
$(MAKE) DEBUG=true

+ 234
- 0
source/modules/juce_core/containers/juce_AbstractFifo.cpp View File

@@ -0,0 +1,234 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
AbstractFifo::AbstractFifo (const int capacity) noexcept
: bufferSize (capacity)
{
jassert (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
{
jassert (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 = jmin (numToWrite, freeSpace - 1);
if (numToWrite <= 0)
{
startIndex1 = 0;
startIndex2 = 0;
blockSize1 = 0;
blockSize2 = 0;
}
else
{
startIndex1 = ve;
startIndex2 = 0;
blockSize1 = jmin (bufferSize - ve, numToWrite);
numToWrite -= blockSize1;
blockSize2 = numToWrite <= 0 ? 0 : jmin (numToWrite, vs);
}
}
void AbstractFifo::finishedWrite (int numWritten) noexcept
{
jassert (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 = jmin (numWanted, numReady);
if (numWanted <= 0)
{
startIndex1 = 0;
startIndex2 = 0;
blockSize1 = 0;
blockSize2 = 0;
}
else
{
startIndex1 = vs;
startIndex2 = 0;
blockSize1 = jmin (bufferSize - vs, numWanted);
numWanted -= blockSize1;
blockSize2 = numWanted <= 0 ? 0 : jmin (numWanted, ve);
}
}
void AbstractFifo::finishedRead (int numRead) noexcept
{
jassert (numRead >= 0 && numRead <= bufferSize);
int newStart = validStart.value + numRead;
if (newStart >= bufferSize)
newStart -= bufferSize;
validStart = newStart;
}
//==============================================================================
//==============================================================================
#if JUCE_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);
jassert (size1 >= 0 && size2 >= 0);
jassert (size1 == 0 || (start1 >= 0 && start1 < fifo.getTotalSize()));
jassert (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

+ 222
- 0
source/modules/juce_core/containers/juce_AbstractFifo.h View File

@@ -0,0 +1,222 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_ABSTRACTFIFO_H_INCLUDED
#define JUCE_ABSTRACTFIFO_H_INCLUDED
#include "../memory/juce_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 JUCE_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;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AbstractFifo)
};
#endif // JUCE_ABSTRACTFIFO_H_INCLUDED

+ 1064
- 0
source/modules/juce_core/containers/juce_Array.h
File diff suppressed because it is too large
View File


+ 140
- 0
source/modules/juce_core/containers/juce_ArrayAllocationBase.h View File

@@ -0,0 +1,140 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_ARRAYALLOCATIONBASE_H_INCLUDED
#define JUCE_ARRAYALLOCATIONBASE_H_INCLUDED
#include "../memory/juce_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 JUCE_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);
jassert (numAllocated <= 0 || elements != nullptr);
}
/** 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:
JUCE_DECLARE_NON_COPYABLE (ArrayAllocationBase)
};
#endif // JUCE_ARRAYALLOCATIONBASE_H_INCLUDED

+ 79
- 0
source/modules/juce_core/containers/juce_DynamicObject.cpp View File

@@ -0,0 +1,79 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
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();
}

+ 126
- 0
source/modules/juce_core/containers/juce_DynamicObject.h View File

@@ -0,0 +1,126 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_DYNAMICOBJECT_H_INCLUDED
#define JUCE_DYNAMICOBJECT_H_INCLUDED
#include "juce_NamedValueSet.h"
#include "../memory/juce_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 JUCE_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;
JUCE_LEAK_DETECTOR (DynamicObject)
};
#endif // JUCE_DYNAMICOBJECT_H_INCLUDED

+ 279
- 0
source/modules/juce_core/containers/juce_ElementComparator.h View File

@@ -0,0 +1,279 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_ELEMENTCOMPARATOR_H_INCLUDED
#define JUCE_ELEMENTCOMPARATOR_H_INCLUDED
//==============================================================================
/**
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;
jassert (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)
{
jassert (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 // JUCE_ELEMENTCOMPARATOR_H_INCLUDED

+ 460
- 0
source/modules/juce_core/containers/juce_HashMap.h View File

@@ -0,0 +1,460 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_HASHMAP_H_INCLUDED
#define JUCE_HASHMAP_H_INCLUDED
#include "juce_OwnedArray.h"
#include "juce_LinkedListPointer.h"
#include "../memory/juce_ScopedPointer.h"
//==============================================================================
/**
A simple class to generate hash functions for some primitive types, intended for
use with the HashMap class.
@see HashMap
*/
struct DefaultHashFunctions
{
/** Generates a simple hash from an integer. */
int generateHash (const int key, const int upperLimit) const noexcept { return std::abs (key) % upperLimit; }
/** Generates a simple hash from an int64. */
int generateHash (const int64 key, const int upperLimit) const noexcept { return std::abs ((int) key) % upperLimit; }
/** Generates a simple hash from a string. */
int generateHash (const String& key, const int upperLimit) const noexcept { return (int) (((uint32) key.hashCode()) % (uint32) upperLimit); }
/** Generates a simple hash from a variant. */
int generateHash (const var& key, const int upperLimit) const 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
{
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 HashFunctionType 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
@tparam HashFunctionType The class of hash function, which must be copy-constructible.
@see CriticalSection, DefaultHashFunctions, NamedValueSet, SortedSet
*/
template <typename KeyType,
typename ValueType,
class HashFunctionType = 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().
@param hashFunction An instance of HashFunctionType, which will be copied and
stored to use with the HashMap. This parameter can be omitted
if HashFunctionType has a default constructor.
*/
explicit HashMap (int numberOfSlots = defaultHashTableSize,
HashFunctionType hashFunction = HashFunctionType())
: hashFunctionToUse (hashFunction), 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. */
template <class OtherHashMapType>
void swapWith (OtherHashMapType& otherHashMap) noexcept
{
const ScopedLockType lock1 (getLock());
const typename OtherHashMapType::ScopedLockType lock2 (otherHashMap.getLock());
slots.swapWith (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;
JUCE_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;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Iterator)
};
private:
//==============================================================================
enum { defaultHashTableSize = 101 };
friend class Iterator;
HashFunctionType hashFunctionToUse;
Array <HashEntry*> slots;
int totalNumItems;
TypeOfCriticalSectionToUse lock;
int generateHashFor (KeyTypeParameter key) const
{
const int hash = hashFunctionToUse.generateHash (key, getNumSlots());
jassert (isPositiveAndBelow (hash, getNumSlots())); // your hash function is generating out-of-range numbers!
return hash;
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HashMap)
};
#endif // JUCE_HASHMAP_H_INCLUDED

+ 371
- 0
source/modules/juce_core/containers/juce_LinkedListPointer.h View File

@@ -0,0 +1,371 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_LINKEDLISTPOINTER_H_INCLUDED
#define JUCE_LINKEDLISTPOINTER_H_INCLUDED
//==============================================================================
/**
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 JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
LinkedListPointer (LinkedListPointer&& other) noexcept
: item (other.item)
{
other.item = nullptr;
}
LinkedListPointer& operator= (LinkedListPointer&& other) noexcept
{
jassert (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)
{
jassert (newItem != nullptr);
jassert (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)
{
jassert (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
{
jassert (newItem != nullptr);
jassert (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
{
jassert (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.
jassert (endOfListPointer.item == nullptr);
}
/** Appends an item to the list. */
void append (ObjectType* const newItem) noexcept
{
*endOfList = newItem;
endOfList = &(newItem->nextListItem);
}
private:
LinkedListPointer* endOfList;
JUCE_DECLARE_NON_COPYABLE (Appender)
};
private:
//==============================================================================
ObjectType* item;
JUCE_DECLARE_NON_COPYABLE (LinkedListPointer)
};
#endif // JUCE_LINKEDLISTPOINTER_H_INCLUDED

+ 309
- 0
source/modules/juce_core/containers/juce_NamedValueSet.cpp View File

@@ -0,0 +1,309 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
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 JUCE_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 JUCE_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 JUCE_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];
jassert (v != nullptr);
return v->name;
}
const var& NamedValueSet::getValueAt (const int index) const
{
const NamedValue* const v = values[index];
jassert (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!
jassert (! i->value.isObject());
jassert (! i->value.isMethod());
jassert (! i->value.isArray());
xml.setAttribute (i->name.toString(),
i->value.toString());
}
}
}

+ 169
- 0
source/modules/juce_core/containers/juce_NamedValueSet.h View File

@@ -0,0 +1,169 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_NAMEDVALUESET_H_INCLUDED
#define JUCE_NAMEDVALUESET_H_INCLUDED
#include "juce_Variant.h"
#include "../containers/juce_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 JUCE_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 JUCE_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 JUCE_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 JUCE_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:
JUCE_LEAK_DETECTOR (NamedValue)
};
friend class LinkedListPointer<NamedValue>;
LinkedListPointer<NamedValue> values;
friend class JSONFormatter;
};
#endif // JUCE_NAMEDVALUESET_H_INCLUDED

+ 897
- 0
source/modules/juce_core/containers/juce_OwnedArray.h View File

@@ -0,0 +1,897 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_OWNEDARRAY_H_INCLUDED
#define JUCE_OWNEDARRAY_H_INCLUDED
#include "juce_ArrayAllocationBase.h"
#include "juce_ElementComparator.h"
#include "../threads/juce_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 JUCE_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 (bool deleteObjects = true)
{
const ScopedLockType lock (getLock());
if (deleteObjects)
deleteAllObjects();
data.setAllocatedSize (0);
numUsed = 0;
}
//==============================================================================
/** Clears the array, optionally deleting the objects inside it first. */
void clearQuick (bool deleteObjects)
{
const ScopedLockType lock (getLock());
if (deleteObjects)
deleteAllObjects();
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());
if (isPositiveAndBelow (index, numUsed))
{
jassert (data.elements != nullptr);
return data.elements [index];
}
return 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());
jassert (isPositiveAndBelow (index, numUsed) && data.elements != nullptr);
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
*/
ObjectClass* add (ObjectClass* const newObject) noexcept
{
const ScopedLockType lock (getLock());
data.ensureAllocatedSize (numUsed + 1);
jassert (data.elements != nullptr);
data.elements [numUsed++] = const_cast <ObjectClass*> (newObject);
return 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,
ObjectClass* const newObject) noexcept
{
if (indexToInsertAt >= 0)
{
const ScopedLockType lock (getLock());
if (indexToInsertAt > numUsed)
indexToInsertAt = numUsed;
data.ensureAllocatedSize (numUsed + 1);
jassert (data.elements != nullptr);
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 (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);
jassert (numElementsToAdd <= 0 || data.elements != nullptr);
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);
jassert (numElementsToAdd <= 0 || data.elements != nullptr);
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 = jlimit (0, numUsed, startIndex + numberToRemove);
startIndex = jlimit (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.
*/
template <class OtherArrayType>
void swapWith (OtherArrayType& otherArray) noexcept
{
const ScopedLockType lock1 (getLock());
const typename OtherArrayType::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;
//==============================================================================
// Note that the swapWithArray method has been replaced by a more flexible templated version,
// and renamed "swapWith" to be more consistent with the names used in other classes.
JUCE_DEPRECATED_WITH_BODY (void swapWithArray (OwnedArray& other) noexcept, { swapWith (other); })
private:
//==============================================================================
ArrayAllocationBase <ObjectClass*, TypeOfCriticalSectionToUse> data;
int numUsed;
void deleteAllObjects()
{
while (numUsed > 0)
delete data.elements [--numUsed];
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OwnedArray)
};
#endif // JUCE_OWNEDARRAY_H_INCLUDED

+ 223
- 0
source/modules/juce_core/containers/juce_PropertySet.cpp View File

@@ -0,0 +1,223 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
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)
{
jassert (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()
{
}

+ 219
- 0
source/modules/juce_core/containers/juce_PropertySet.h View File

@@ -0,0 +1,219 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_PROPERTYSET_H_INCLUDED
#define JUCE_PROPERTYSET_H_INCLUDED
#include "../text/juce_StringPairArray.h"
#include "../xml/juce_XmlElement.h"
#include "../containers/juce_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 JUCE_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;
JUCE_LEAK_DETECTOR (PropertySet)
};
#endif // JUCE_PROPERTYSET_H_INCLUDED

+ 872
- 0
source/modules/juce_core/containers/juce_ReferenceCountedArray.h View File

@@ -0,0 +1,872 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_REFERENCECOUNTEDARRAY_H_INCLUDED
#define JUCE_REFERENCECOUNTEDARRAY_H_INCLUDED
#include "../memory/juce_ReferenceCountedObject.h"
#include "juce_ArrayAllocationBase.h"
#include "juce_ElementComparator.h"
#include "../threads/juce_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);
swapWith (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);
swapWith (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();
jassert (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());
jassert (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
*/
ObjectClass* add (ObjectClass* const newObject) noexcept
{
const ScopedLockType lock (getLock());
data.ensureAllocatedSize (numUsed + 1);
jassert (data.elements != nullptr);
data.elements [numUsed++] = newObject;
if (newObject != nullptr)
newObject->incReferenceCount();
return newObject;
}
/** 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
*/
ObjectClass* insert (int indexToInsertAt,
ObjectClass* const newObject) noexcept
{
if (indexToInsertAt >= 0)
{
const ScopedLockType lock (getLock());
if (indexToInsertAt > numUsed)
indexToInsertAt = numUsed;
data.ensureAllocatedSize (numUsed + 1);
jassert (data.elements != nullptr);
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;
return newObject;
}
else
{
return 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);
jassert (data.elements != nullptr);
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 = jlimit (0, numUsed, startIndex);
const int endIndex = jlimit (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.
*/
template <class OtherArrayType>
void swapWith (OtherArrayType& otherArray) noexcept
{
const ScopedLockType lock1 (getLock());
const typename OtherArrayType::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;
//==============================================================================
// Note that the swapWithArray method has been replaced by a more flexible templated version,
// and renamed "swapWith" to be more consistent with the names used in other classes.
JUCE_DEPRECATED_WITH_BODY (void swapWithArray (ReferenceCountedArray& other) noexcept, { swapWith (other); })
private:
//==============================================================================
ArrayAllocationBase <ObjectClass*, TypeOfCriticalSectionToUse> data;
int numUsed;
};
#endif // JUCE_REFERENCECOUNTEDARRAY_H_INCLUDED

+ 100
- 0
source/modules/juce_core/containers/juce_ScopedValueSetter.h View File

@@ -0,0 +1,100 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_SCOPEDVALUESETTER_H_INCLUDED
#define JUCE_SCOPEDVALUESETTER_H_INCLUDED
//==============================================================================
/**
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;
JUCE_DECLARE_NON_COPYABLE (ScopedValueSetter)
};
#endif // JUCE_SCOPEDVALUESETTER_H_INCLUDED

+ 497
- 0
source/modules/juce_core/containers/juce_SortedSet.h View File

@@ -0,0 +1,497 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_SORTEDSET_H_INCLUDED
#define JUCE_SORTEDSET_H_INCLUDED
#include "juce_ArrayAllocationBase.h"
#include "../threads/juce_CriticalSection.h"
#if JUCE_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());
jassert (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.
*/
template <class OtherSetType>
void swapWith (OtherSetType& otherSet) noexcept
{
data.swapWith (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 JUCE_MSVC
#pragma warning (pop)
#endif
#endif // JUCE_SORTEDSET_H_INCLUDED

+ 301
- 0
source/modules/juce_core/containers/juce_SparseSet.h View File

@@ -0,0 +1,301 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_SPARSESET_H_INCLUDED
#define JUCE_SPARSESET_H_INCLUDED
#include "../maths/juce_Range.h"
#include "../threads/juce_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)
{
jassert ((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)
{
jassert (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)
{
jassert (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 (jmin (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()
{
jassert ((values.size() & 1) == 0);
for (int i = values.size(); --i > 0;)
if (values.getUnchecked(i) == values.getUnchecked (i - 1))
values.removeRange (--i, 2);
}
};
#endif // JUCE_SPARSESET_H_INCLUDED

+ 709
- 0
source/modules/juce_core/containers/juce_Variant.cpp View File

@@ -0,0 +1,709 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
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 ? (juce_wchar) '1' : (juce_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 JUCE_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
{
jassert (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!
jassert (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!
jassert (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;
}

+ 307
- 0
source/modules/juce_core/containers/juce_Variant.h View File

@@ -0,0 +1,307 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_VARIANT_H_INCLUDED
#define JUCE_VARIANT_H_INCLUDED
#include "../text/juce_Identifier.h"
#include "../streams/juce_OutputStream.h"
#include "../streams/juce_InputStream.h"
#include "../containers/juce_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 JUCE_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 JUCE_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 // JUCE_VARIANT_H_INCLUDED

+ 159
- 0
source/modules/juce_core/files/juce_DirectoryIterator.cpp View File

@@ -0,0 +1,159 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
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!
jassert ((type & (File::findFiles | File::findDirectories)) != 0);
jassert (type > 0 && type <= 7);
}
DirectoryIterator::~DirectoryIterator()
{
}
StringArray DirectoryIterator::parseWildcards (const String& pattern)
{
StringArray s;
s.addTokens (pattern, ";,", "\"'");
s.trim();
s.removeEmptyStrings();
return s;
}
bool DirectoryIterator::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;
}
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!
jassert (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;
}

+ 162
- 0
source/modules/juce_core/files/juce_DirectoryIterator.h View File

@@ -0,0 +1,162 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_DIRECTORYITERATOR_H_INCLUDED
#define JUCE_DIRECTORYITERATOR_H_INCLUDED
#include "juce_File.h"
#include "../memory/juce_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 JUCE_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;
JUCE_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;
static StringArray parseWildcards (const String& pattern);
static bool fileMatches (const StringArray& wildCards, const String& filename);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DirectoryIterator)
};
#endif // JUCE_DIRECTORYITERATOR_H_INCLUDED

+ 1091
- 0
source/modules/juce_core/files/juce_File.cpp
File diff suppressed because it is too large
View File


+ 959
- 0
source/modules/juce_core/files/juce_File.h View File

@@ -0,0 +1,959 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_FILE_H_INCLUDED
#define JUCE_FILE_H_INCLUDED
#include "../containers/juce_Array.h"
#include "../time/juce_Time.h"
#include "../text/juce_StringArray.h"
#include "../memory/juce_MemoryBlock.h"
#include "../memory/juce_ScopedPointer.h"
#include "../misc/juce_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 JUCE_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& absolutePath);
/** Creates a copy of another file object. */
File (const File&);
/** 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& newAbsolutePath);
/** Copies from another file object. */
File& operator= (const File& otherFile);
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
File (File&&) noexcept;
File& operator= (File&&) 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. 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 that represents a relative (or absolute) sub-path of the current one.
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 ("haddock/foo.txt") will produce "/moose/fish/haddock/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 relativeOrAbsolutePath) 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&) const;
/** Compares the pathnames for two files. */
bool operator!= (const File&) const;
/** Compares the pathnames for two files. */
bool operator< (const File&) const;
/** Compares the pathnames for two files. */
bool operator> (const File&) 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 JUCE_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 juce_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;
//==============================================================================
/** Returns a version of a filename with any illegal characters removed.
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 - use
createLegalPathName() for that.
@see createLegalPathName
*/
static String createLegalFileName (const String& fileNameToFix);
/** Returns a version of a path with any illegal characters removed.
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& absolutePath) 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 JUCE_MAC || JUCE_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 JUCE_MAC || DOXYGEN
/** OSX ONLY - Adds this file to the OSX dock */
void addToDock() const;
#endif
#if JUCE_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;
};
#endif // JUCE_FILE_H_INCLUDED

+ 95
- 0
source/modules/juce_core/files/juce_FileInputStream.cpp View File

@@ -0,0 +1,95 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
int64 juce_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)
{
jassert (openedOk());
jassert (buffer != nullptr && bytesToRead >= 0);
if (needToSeek)
{
if (juce_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)
{
jassert (openedOk());
if (pos != currentPosition)
{
pos = jlimit ((int64) 0, getTotalLength(), pos);
needToSeek |= (currentPosition != pos);
currentPosition = pos;
}
return true;
}

+ 99
- 0
source/modules/juce_core/files/juce_FileInputStream.h View File

@@ -0,0 +1,99 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_FILEINPUTSTREAM_H_INCLUDED
#define JUCE_FILEINPUTSTREAM_H_INCLUDED
#include "juce_File.h"
#include "../streams/juce_InputStream.h"
//==============================================================================
/**
An input stream that reads from a local file.
@see InputStream, FileOutputStream, File::createInputStream
*/
class JUCE_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() override;
int read (void* destBuffer, int maxBytesToRead) override;
bool isExhausted() override;
int64 getPosition() override;
bool setPosition (int64 pos) override;
private:
//==============================================================================
File file;
void* fileHandle;
int64 currentPosition;
Result status;
bool needToSeek;
void openHandle();
void closeHandle();
size_t readInternal (void* buffer, size_t numBytes);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileInputStream)
};
#endif // JUCE_FILEINPUTSTREAM_H_INCLUDED

+ 135
- 0
source/modules/juce_core/files/juce_FileOutputStream.cpp View File

@@ -0,0 +1,135 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
int64 juce_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) jmax (bufferSize_, 16))
{
openHandle();
}
FileOutputStream::~FileOutputStream()
{
flushBuffer();
flushInternal();
closeHandle();
}
int64 FileOutputStream::getPosition()
{
return currentPosition;
}
bool FileOutputStream::setPosition (int64 newPosition)
{
if (newPosition != currentPosition)
{
flushBuffer();
currentPosition = juce_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)
{
jassert (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;
}
bool FileOutputStream::writeRepeatedByte (uint8 byte, size_t numBytes)
{
jassert (((ssize_t) numBytes) >= 0);
if (bytesInBuffer + numBytes < bufferSize)
{
memset (buffer + bytesInBuffer, byte, numBytes);
bytesInBuffer += numBytes;
currentPosition += numBytes;
return true;
}
return OutputStream::writeRepeatedByte (byte, numBytes);
}

+ 119
- 0
source/modules/juce_core/files/juce_FileOutputStream.h View File

@@ -0,0 +1,119 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_FILEOUTPUTSTREAM_H_INCLUDED
#define JUCE_FILEOUTPUTSTREAM_H_INCLUDED
#include "juce_File.h"
#include "../streams/juce_OutputStream.h"
//==============================================================================
/**
An output stream that writes into a local file.
@see OutputStream, FileInputStream, File::createOutputStream
*/
class JUCE_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() override;
int64 getPosition() override;
bool setPosition (int64) override;
bool write (const void*, size_t) override;
bool writeRepeatedByte (uint8 byte, size_t numTimesToRepeat) override;
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);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileOutputStream)
};
#endif // JUCE_FILEOUTPUTSTREAM_H_INCLUDED

+ 171
- 0
source/modules/juce_core/files/juce_FileSearchPath.cpp View File

@@ -0,0 +1,171 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
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;
}

+ 169
- 0
source/modules/juce_core/files/juce_FileSearchPath.h View File

@@ -0,0 +1,169 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_FILESEARCHPATH_H_INCLUDED
#define JUCE_FILESEARCHPATH_H_INCLUDED
#include "juce_File.h"
#include "../text/juce_StringArray.h"
//==============================================================================
/**
Encapsulates a set of folders that make up a search path.
@see File
*/
class JUCE_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);
JUCE_LEAK_DETECTOR (FileSearchPath)
};
#endif // JUCE_FILESEARCHPATH_H_INCLUDED

+ 116
- 0
source/modules/juce_core/files/juce_MemoryMappedFile.h View File

@@ -0,0 +1,116 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_MEMORYMAPPEDFILE_H_INCLUDED
#define JUCE_MEMORYMAPPEDFILE_H_INCLUDED
#include "juce_File.h"
//==============================================================================
/**
Maps a file into virtual memory for easy reading and/or writing.
*/
class JUCE_API MemoryMappedFile
{
public:
/** The read/write flags used when opening a memory mapped file. */
enum AccessMode
{
readOnly, /**< Indicates that the memory can only be read. */
readWrite /**< Indicates that the memory can be read and written to - changes that are
made will be flushed back to disk at the whim of the OS. */
};
/** Opens a file and maps it to an area of virtual memory.
The file should already exist, and should already be the size that you want to work with
when you call this. If the file is resized after being opened, the behaviour is undefined.
If the file exists and the operation succeeds, the getData() and getSize() methods will
return the location and size of the data that can be read or written. Note that the entire
file is not read into memory immediately - the OS simply creates a virtual mapping, which
will lazily pull the data into memory when blocks are accessed.
If the file can't be opened for some reason, the getData() method will return a null pointer.
*/
MemoryMappedFile (const File& file, AccessMode mode);
/** 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 JUCE_WINDOWS
void* fileHandle;
#else
int fileHandle;
#endif
void openInternal (const File&, AccessMode);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryMappedFile)
};
#endif // JUCE_MEMORYMAPPEDFILE_H_INCLUDED

+ 117
- 0
source/modules/juce_core/files/juce_TemporaryFile.cpp View File

@@ -0,0 +1,117 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
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!
jassert (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!
jassert (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;
}

+ 171
- 0
source/modules/juce_core/files/juce_TemporaryFile.h View File

@@ -0,0 +1,171 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_TEMPORARYFILE_H_INCLUDED
#define JUCE_TEMPORARYFILE_H_INCLUDED
#include "juce_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 JUCE_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;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TemporaryFile)
};
#endif // JUCE_TEMPORARYFILE_H_INCLUDED

+ 650
- 0
source/modules/juce_core/json/juce_JSON.cpp View File

@@ -0,0 +1,650 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
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';
jassert (intValue >= 0 && intValue < 10);
for (;;)
{
String::CharPointerType previousChar (t);
const juce_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 juce_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 juce_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 juce_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 juce_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 juce_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 (;;)
{
juce_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 = (juce_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!
jassert (! (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 juce_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 JUCE_UNIT_TESTS
class JSONTests : public UnitTest
{
public:
JSONTests() : UnitTest ("JSON") {}
static String createRandomWideCharString (Random& r)
{
juce_wchar buffer[40] = { 0 };
for (int i = 0; i < numElementsInArray (buffer) - 1; ++i)
{
if (r.nextBool())
{
do
{
buffer[i] = (juce_wchar) (1 + r.nextInt (0x10ffff - 1));
}
while (! CharPointer_UTF16::canRepresent (buffer[i]));
}
else
buffer[i] = (juce_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

+ 118
- 0
source/modules/juce_core/json/juce_JSON.h View File

@@ -0,0 +1,118 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_JSON_H_INCLUDED
#define JUCE_JSON_H_INCLUDED
#include "../misc/juce_Result.h"
#include "../containers/juce_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 JUCE_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 // JUCE_JSON_H_INCLUDED

+ 218
- 0
source/modules/juce_core/juce_core.cpp View File

@@ -0,0 +1,218 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#if defined (JUCE_CORE_H_INCLUDED) && ! JUCE_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 JUCE cpp file"
#endif
// Your project must contain an AppConfig.h file with your project-specific settings in it,
// and your header search path must make it accessible to the module's files.
#include "AppConfig.h"
//==============================================================================
#include "native/juce_BasicNativeHeaders.h"
#include "juce_core.h"
#include <locale>
#include <cctype>
#include <sys/timeb.h>
#if ! JUCE_ANDROID
#include <cwctype>
#endif
#if JUCE_WINDOWS
#include <ctime>
#include <winsock2.h>
#include <ws2tcpip.h>
#if ! JUCE_MINGW
#include <Dbghelp.h>
#if ! JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
#pragma comment (lib, "DbgHelp.lib")
#endif
#endif
#if JUCE_MINGW
#include <ws2spi.h>
#endif
#else
#if JUCE_LINUX || JUCE_ANDROID
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <unistd.h>
#include <netinet/in.h>
#endif
#if JUCE_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 ! JUCE_ANDROID
#include <execinfo.h>
#endif
#endif
#if JUCE_MAC || JUCE_IOS
#include <xlocale.h>
#include <mach/mach.h>
#endif
#if JUCE_ANDROID
#include <android/log.h>
#endif
//==============================================================================
namespace juce
{
#include "containers/juce_AbstractFifo.cpp"
#include "containers/juce_DynamicObject.cpp"
#include "containers/juce_NamedValueSet.cpp"
#include "containers/juce_PropertySet.cpp"
#include "containers/juce_Variant.cpp"
#include "files/juce_DirectoryIterator.cpp"
#include "files/juce_File.cpp"
#include "files/juce_FileInputStream.cpp"
#include "files/juce_FileOutputStream.cpp"
#include "files/juce_FileSearchPath.cpp"
#include "files/juce_TemporaryFile.cpp"
#include "json/juce_JSON.cpp"
#include "logging/juce_FileLogger.cpp"
#include "logging/juce_Logger.cpp"
#include "maths/juce_BigInteger.cpp"
#include "maths/juce_Expression.cpp"
#include "maths/juce_Random.cpp"
#include "memory/juce_MemoryBlock.cpp"
#include "misc/juce_Result.cpp"
#include "misc/juce_Uuid.cpp"
#include "network/juce_MACAddress.cpp"
#include "network/juce_NamedPipe.cpp"
#include "network/juce_Socket.cpp"
#include "network/juce_URL.cpp"
#include "network/juce_IPAddress.cpp"
#include "streams/juce_BufferedInputStream.cpp"
#include "streams/juce_FileInputSource.cpp"
#include "streams/juce_InputStream.cpp"
#include "streams/juce_MemoryInputStream.cpp"
#include "streams/juce_MemoryOutputStream.cpp"
#include "streams/juce_OutputStream.cpp"
#include "streams/juce_SubregionStream.cpp"
#include "system/juce_SystemStats.cpp"
#include "text/juce_CharacterFunctions.cpp"
#include "text/juce_Identifier.cpp"
#include "text/juce_LocalisedStrings.cpp"
#include "text/juce_String.cpp"
#include "text/juce_StringArray.cpp"
#include "text/juce_StringPairArray.cpp"
#include "text/juce_StringPool.cpp"
#include "text/juce_TextDiff.cpp"
#include "threads/juce_ChildProcess.cpp"
#include "threads/juce_ReadWriteLock.cpp"
#include "threads/juce_Thread.cpp"
#include "threads/juce_ThreadPool.cpp"
#include "threads/juce_TimeSliceThread.cpp"
#include "time/juce_PerformanceCounter.cpp"
#include "time/juce_RelativeTime.cpp"
#include "time/juce_Time.cpp"
#include "unit_tests/juce_UnitTest.cpp"
#include "xml/juce_XmlDocument.cpp"
#include "xml/juce_XmlElement.cpp"
#include "zip/juce_GZIPDecompressorInputStream.cpp"
#include "zip/juce_GZIPCompressorOutputStream.cpp"
#include "zip/juce_ZipFile.cpp"
//==============================================================================
#if JUCE_MAC || JUCE_IOS
#include "native/juce_osx_ObjCHelpers.h"
#endif
#if JUCE_ANDROID
#include "native/juce_android_JNIHelpers.h"
#endif
#if ! JUCE_WINDOWS
#include "native/juce_posix_SharedCode.h"
#include "native/juce_posix_NamedPipe.cpp"
#endif
//==============================================================================
#if JUCE_MAC || JUCE_IOS
#include "native/juce_mac_Files.mm"
#include "native/juce_mac_Network.mm"
#include "native/juce_mac_Strings.mm"
#include "native/juce_mac_SystemStats.mm"
#include "native/juce_mac_Threads.mm"
//==============================================================================
#elif JUCE_WINDOWS
#include "native/juce_win32_ComSmartPtr.h"
#include "native/juce_win32_Files.cpp"
#include "native/juce_win32_Network.cpp"
#include "native/juce_win32_Registry.cpp"
#include "native/juce_win32_SystemStats.cpp"
#include "native/juce_win32_Threads.cpp"
//==============================================================================
#elif JUCE_LINUX
#include "native/juce_linux_Files.cpp"
#include "native/juce_linux_Network.cpp"
#include "native/juce_linux_SystemStats.cpp"
#include "native/juce_linux_Threads.cpp"
//==============================================================================
#elif JUCE_ANDROID
#include "native/juce_android_Files.cpp"
#include "native/juce_android_Misc.cpp"
#include "native/juce_android_Network.cpp"
#include "native/juce_android_SystemStats.cpp"
#include "native/juce_android_Threads.cpp"
#endif
#include "threads/juce_HighResolutionTimer.cpp"
}

+ 253
- 0
source/modules/juce_core/juce_core.h View File

@@ -0,0 +1,253 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_CORE_H_INCLUDED
#define JUCE_CORE_H_INCLUDED
#ifndef JUCE_MODULE_AVAILABLE_juce_core
/* If you fail to make sure that all your compile units are building JUCE 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 Introjucer-generated AppConfig.h
file before any juce headers.
Note that if you do have an AppConfig.h file and hit this warning, it means that it doesn't
contain the JUCE_MODULE_AVAILABLE_xxx flags, which are necessary for some inter-module
functionality to work correctly. In that case, you should either rebuild your AppConfig.h with
the latest introjucer, or fix it manually to contain these flags.
*/
#ifdef _MSC_VER
#pragma message ("Have you included your AppConfig.h file before including the JUCE headers?")
#else
#warning "Have you included your AppConfig.h file before including the JUCE headers?"
#endif
#endif
//==============================================================================
#include "system/juce_TargetPlatform.h"
//=============================================================================
/** Config: JUCE_FORCE_DEBUG
Normally, JUCE_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 JUCE_FORCE_DEBUG
//#define JUCE_FORCE_DEBUG 0
#endif
//=============================================================================
/** Config: JUCE_LOG_ASSERTIONS
If this flag is enabled, the the jassert 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 jassert and jassertfalse macros will not be compiled in a
release build.
@see jassert, jassertfalse, Logger
*/
#ifndef JUCE_LOG_ASSERTIONS
#if JUCE_ANDROID
#define JUCE_LOG_ASSERTIONS 1
#else
#define JUCE_LOG_ASSERTIONS 0
#endif
#endif
//=============================================================================
/** Config: JUCE_CHECK_MEMORY_LEAKS
Enables a memory-leak check for certain objects when the app terminates. See the LeakedObjectDetector
class and the JUCE_LEAK_DETECTOR macro for more details about enabling leak checking for specific classes.
*/
#if JUCE_DEBUG && ! defined (JUCE_CHECK_MEMORY_LEAKS)
#define JUCE_CHECK_MEMORY_LEAKS 1
#endif
//=============================================================================
/** Config: JUCE_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 JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
#define JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES 0
#endif
/** Config: JUCE_INCLUDE_ZLIB_CODE
This can be used to disable Juce'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 JUCE_ZLIB_INCLUDE_PATH, to
specify the path where your zlib headers live.
*/
#ifndef JUCE_INCLUDE_ZLIB_CODE
#define JUCE_INCLUDE_ZLIB_CODE 1
#endif
#ifndef JUCE_ZLIB_INCLUDE_PATH
#define JUCE_ZLIB_INCLUDE_PATH <zlib.h>
#endif
/* Config: JUCE_CATCH_UNHANDLED_EXCEPTIONS
If enabled, this will add some exception-catching code to forward unhandled exceptions
to your JUCEApplication::unhandledException() callback.
*/
#ifndef JUCE_CATCH_UNHANDLED_EXCEPTIONS
//#define JUCE_CATCH_UNHANDLED_EXCEPTIONS 1
#endif
//=============================================================================
//=============================================================================
#if JUCE_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/juce_StandardHeader.h"
namespace juce
{
// START_AUTOINCLUDE containers, files, json, logging, maths, memory, misc, network,
// streams, system, text, threads, time, unit_tests, xml, zip
#include "containers/juce_AbstractFifo.h"
#include "containers/juce_Array.h"
#include "containers/juce_ArrayAllocationBase.h"
#include "containers/juce_DynamicObject.h"
#include "containers/juce_ElementComparator.h"
#include "containers/juce_HashMap.h"
#include "containers/juce_LinkedListPointer.h"
#include "containers/juce_NamedValueSet.h"
#include "containers/juce_OwnedArray.h"
#include "containers/juce_PropertySet.h"
#include "containers/juce_ReferenceCountedArray.h"
#include "containers/juce_ScopedValueSetter.h"
#include "containers/juce_SortedSet.h"
#include "containers/juce_SparseSet.h"
#include "containers/juce_Variant.h"
#include "files/juce_DirectoryIterator.h"
#include "files/juce_File.h"
#include "files/juce_FileInputStream.h"
#include "files/juce_FileOutputStream.h"
#include "files/juce_FileSearchPath.h"
#include "files/juce_MemoryMappedFile.h"
#include "files/juce_TemporaryFile.h"
#include "json/juce_JSON.h"
#include "logging/juce_FileLogger.h"
#include "logging/juce_Logger.h"
#include "maths/juce_BigInteger.h"
#include "maths/juce_Expression.h"
#include "maths/juce_MathsFunctions.h"
#include "maths/juce_Random.h"
#include "maths/juce_Range.h"
#include "memory/juce_Atomic.h"
#include "memory/juce_ByteOrder.h"
#include "memory/juce_HeapBlock.h"
#include "memory/juce_LeakedObjectDetector.h"
#include "memory/juce_Memory.h"
#include "memory/juce_MemoryBlock.h"
#include "memory/juce_OptionalScopedPointer.h"
#include "memory/juce_ReferenceCountedObject.h"
#include "memory/juce_ScopedPointer.h"
#include "memory/juce_Singleton.h"
#include "memory/juce_WeakReference.h"
#include "misc/juce_Result.h"
#include "misc/juce_Uuid.h"
#include "misc/juce_WindowsRegistry.h"
#include "network/juce_IPAddress.h"
#include "network/juce_MACAddress.h"
#include "network/juce_NamedPipe.h"
#include "network/juce_Socket.h"
#include "network/juce_URL.h"
#include "streams/juce_BufferedInputStream.h"
#include "streams/juce_FileInputSource.h"
#include "streams/juce_InputSource.h"
#include "streams/juce_InputStream.h"
#include "streams/juce_MemoryInputStream.h"
#include "streams/juce_MemoryOutputStream.h"
#include "streams/juce_OutputStream.h"
#include "streams/juce_SubregionStream.h"
#include "system/juce_PlatformDefs.h"
#include "system/juce_StandardHeader.h"
#include "system/juce_SystemStats.h"
#include "system/juce_TargetPlatform.h"
#include "text/juce_CharacterFunctions.h"
#include "text/juce_CharPointer_ASCII.h"
#include "text/juce_CharPointer_UTF16.h"
#include "text/juce_CharPointer_UTF32.h"
#include "text/juce_CharPointer_UTF8.h"
#include "text/juce_Identifier.h"
#include "text/juce_LocalisedStrings.h"
#include "text/juce_NewLine.h"
#include "text/juce_String.h"
#include "text/juce_StringArray.h"
#include "text/juce_StringPairArray.h"
#include "text/juce_StringPool.h"
#include "text/juce_TextDiff.h"
#include "threads/juce_ChildProcess.h"
#include "threads/juce_CriticalSection.h"
#include "threads/juce_DynamicLibrary.h"
#include "threads/juce_HighResolutionTimer.h"
#include "threads/juce_InterProcessLock.h"
#include "threads/juce_Process.h"
#include "threads/juce_ReadWriteLock.h"
#include "threads/juce_ScopedLock.h"
#include "threads/juce_ScopedReadLock.h"
#include "threads/juce_ScopedWriteLock.h"
#include "threads/juce_SpinLock.h"
#include "threads/juce_Thread.h"
#include "threads/juce_ThreadLocalValue.h"
#include "threads/juce_ThreadPool.h"
#include "threads/juce_TimeSliceThread.h"
#include "threads/juce_WaitableEvent.h"
#include "time/juce_PerformanceCounter.h"
#include "time/juce_RelativeTime.h"
#include "time/juce_Time.h"
#include "unit_tests/juce_UnitTest.h"
#include "xml/juce_XmlDocument.h"
#include "xml/juce_XmlElement.h"
#include "zip/juce_GZIPCompressorOutputStream.h"
#include "zip/juce_GZIPDecompressorInputStream.h"
#include "zip/juce_ZipFile.h"
// END_AUTOINCLUDE
}
#if JUCE_MSVC
#pragma warning (pop)
#endif
#endif // JUCE_CORE_H_INCLUDED

+ 29
- 0
source/modules/juce_core/juce_core.mm View File

@@ -0,0 +1,29 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#include "juce_core.cpp"

+ 38
- 0
source/modules/juce_core/juce_module_info View File

@@ -0,0 +1,38 @@
{
"id": "juce_core",
"name": "JUCE core classes",
"version": "2.1.2",
"description": "The essential set of basic JUCE classes, as required by all the other JUCE modules. Includes text, container, memory, threading and i/o functionality.",
"website": "http://www.juce.com/juce",
"license": "ISC Permissive",
"dependencies": [],
"include": "juce_core.h",
"compile": [ { "file": "juce_core.cpp", "target": "! xcode" },
{ "file": "juce_core.mm", "target": "xcode" } ],
"browse": [ "text/*",
"maths/*",
"memory/*",
"containers/*",
"threads/*",
"time/*",
"files/*",
"network/*",
"streams/*",
"logging/*",
"system/*",
"xml/*",
"json/*",
"zip/*",
"unit_tests/*",
"misc/*",
"native/*" ],
"OSXFrameworks": "Cocoa IOKit",
"iOSFrameworks": "Foundation",
"LinuxLibs": "rt dl pthread",
"mingwLibs": "uuid wsock32 wininet version ole32 ws2_32 oleaut32 imm32 comdlg32 shlwapi rpcrt4 winmm"
}

+ 134
- 0
source/modules/juce_core/logging/juce_FileLogger.cpp View File

@@ -0,0 +1,134 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
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 JUCE_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);
}

+ 139
- 0
source/modules/juce_core/logging/juce_FileLogger.h View File

@@ -0,0 +1,139 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_FILELOGGER_H_INCLUDED
#define JUCE_FILELOGGER_H_INCLUDED
#include "juce_Logger.h"
#include "../files/juce_File.h"
#include "../memory/juce_ScopedPointer.h"
//==============================================================================
/**
A simple implementation of a Logger that writes to a file.
@see Logger
*/
class JUCE_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;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileLogger)
};
#endif // JUCE_FILELOGGER_H_INCLUDED

+ 63
- 0
source/modules/juce_core/logging/juce_Logger.cpp View File

@@ -0,0 +1,63 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
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.
jassert (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 JUCE_LOG_ASSERTIONS || JUCE_DEBUG
void JUCE_API JUCE_CALLTYPE logAssertion (const char* const filename, const int lineNum) noexcept
{
String m ("JUCE Assertion failure in ");
m << File::createFileWithoutCheckingPath (filename).getFileName() << ':' << lineNum;
#if JUCE_LOG_ASSERTIONS
Logger::writeToLog (m);
#else
DBG (m);
#endif
}
#endif

+ 99
- 0
source/modules/juce_core/logging/juce_Logger.h View File

@@ -0,0 +1,99 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_LOGGER_H_INCLUDED
#define JUCE_LOGGER_H_INCLUDED
#include "../text/juce_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 JUCE_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 JUCE_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 JUCE_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
juce_PlatformDefs.h (which will avoid calling the method in non-debug builds).
*/
static void JUCE_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 // JUCE_LOGGER_H_INCLUDED

+ 1021
- 0
source/modules/juce_core/maths/juce_BigInteger.cpp
File diff suppressed because it is too large
View File


+ 334
- 0
source/modules/juce_core/maths/juce_BigInteger.h View File

@@ -0,0 +1,334 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_BIGINTEGER_H_INCLUDED
#define JUCE_BIGINTEGER_H_INCLUDED
#include "../text/juce_String.h"
#include "../memory/juce_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 JUCE_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 JUCE_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);
JUCE_LEAK_DETECTOR (BigInteger)
};
/** Writes a BigInteger to an OutputStream as a UTF8 decimal string. */
OutputStream& JUCE_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 // JUCE_BIGINTEGER_H_INCLUDED

+ 1185
- 0
source/modules/juce_core/maths/juce_Expression.cpp
File diff suppressed because it is too large
View File


+ 274
- 0
source/modules/juce_core/maths/juce_Expression.h View File

@@ -0,0 +1,274 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_EXPRESSION_H_INCLUDED
#define JUCE_EXPRESSION_H_INCLUDED
#include "../memory/juce_ReferenceCountedObject.h"
#include "../containers/juce_Array.h"
#include "../memory/juce_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 JUCE_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 JUCE_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 JUCE_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 // JUCE_EXPRESSION_H_INCLUDED

+ 514
- 0
source/modules/juce_core/maths/juce_MathsFunctions.h View File

@@ -0,0 +1,514 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_MATHSFUNCTIONS_H_INCLUDED
#define JUCE_MATHSFUNCTIONS_H_INCLUDED
//==============================================================================
/*
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 JUCE_MSVC
/** A platform-independent 64-bit integer type. */
typedef __int64 int64;
/** A platform-independent 64-bit unsigned integer type. */
typedef unsigned __int64 uint64;
#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;
#endif
#ifndef DOXYGEN
/** A macro for creating 64-bit literals.
Historically, this was needed to support portability with MSVC6, and is kept here
so that old code will still compile, but nowadays every compiler will support the
LL and ULL suffixes, so you should use those in preference to this macro.
*/
#define literal64bit(longLiteral) (longLiteral##LL)
#endif
#if JUCE_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 JUCE_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 JUCE_MSVC
typedef pointer_sized_int ssize_t;
#endif
//==============================================================================
// Some indispensible min/max functions
/** Returns the larger of two values. */
template <typename Type>
inline Type jmax (const Type a, const Type b) { return (a < b) ? b : a; }
/** Returns the larger of three values. */
template <typename Type>
inline Type jmax (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 jmax (const Type a, const Type b, const Type c, const Type d) { return jmax (a, jmax (b, c, d)); }
/** Returns the smaller of two values. */
template <typename Type>
inline Type jmin (const Type a, const Type b) { return (b < a) ? b : a; }
/** Returns the smaller of three values. */
template <typename Type>
inline Type jmin (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 jmin (const Type a, const Type b, const Type c, const Type d) { return jmin (a, jmin (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 jmax (lowerLimit, jmin (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, jmin, jmax
*/
template <typename Type>
inline Type jlimit (const Type lowerLimit,
const Type upperLimit,
const Type valueToConstrain) noexcept
{
jassert (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
{
jassert (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
{
jassert (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
{
jassert (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
{
jassert (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 juce_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 juce_hypot (Type a, Type b) noexcept
{
#if JUCE_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 juce_isfinite (FloatingPointType value)
{
#if JUCE_WINDOWS
return _finite (value);
#elif JUCE_ANDROID
return isfinite (value);
#else
return std::isfinite (value);
#endif
}
//==============================================================================
#if JUCE_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 JUCE_BIG_ENDIAN
return n.asInt [1];
#else
return n.asInt [0];
#endif
}
#if JUCE_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
{
jassert (divisor > 0);
dividend %= divisor;
return (dividend < 0) ? (dividend + divisor) : dividend;
}
//==============================================================================
#if (JUCE_INTEL && JUCE_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 JUCE_UNDENORMALISE(x) x += 1.0f; x -= 1.0f;
#else
#define JUCE_UNDENORMALISE(x)
#endif
//==============================================================================
/** This namespace contains a few template classes for helping work out class type variations.
*/
namespace TypeHelpers
{
#if JUCE_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 // JUCE_MATHSFUNCTIONS_H_INCLUDED

+ 190
- 0
source/modules/juce_core/maths/juce_Random.cpp View File

@@ -0,0 +1,190 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
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 * 0x5deece66dLL + 11) & 0xffffffffffffLL;
return (int) (seed >> 16);
}
int Random::nextInt (const int maxValue) noexcept
{
jassert (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 (void* const buffer, size_t bytes)
{
int* d = static_cast<int*> (buffer);
for (; bytes >= sizeof (int); bytes -= sizeof (int))
*d++ = nextInt();
if (bytes > 0)
{
const int lastBytes = nextInt();
memcpy (d, &lastBytes, bytes);
}
}
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 JUCE_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

+ 143
- 0
source/modules/juce_core/maths/juce_Random.h View File

@@ -0,0 +1,143 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_RANDOM_H_INCLUDED
#define JUCE_RANDOM_H_INCLUDED
#include "juce_BigInteger.h"
//==============================================================================
/**
A random number generator.
You can create a Random object and use it to generate a sequence of random numbers.
*/
class JUCE_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);
/** Fills a block of memory with random values. */
void fillBitsRandomly (void* bufferToFill, size_t sizeInBytes);
/** 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;
JUCE_LEAK_DETECTOR (Random)
};
#endif // JUCE_RANDOM_H_INCLUDED

+ 264
- 0
source/modules/juce_core/maths/juce_Range.h View File

@@ -0,0 +1,264 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_RANGE_H_INCLUDED
#define JUCE_RANGE_H_INCLUDED
//==============================================================================
/** 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 (jmax (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, jmax (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 (jmin (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 + jmax (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 jlimit (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 (jmax (start, other.start),
jmin (end, other.end));
}
/** Returns the smallest range that contains both this one and the other one. */
Range getUnionWith (Range other) const noexcept
{
return Range (jmin (start, other.start),
jmax (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 (jlimit (start, end - otherLen, rangeToConstrain.getStart()));
}
private:
//==============================================================================
ValueType start, end;
};
#endif // JUCE_RANGE_H_INCLUDED

+ 396
- 0
source/modules/juce_core/memory/juce_Atomic.h View File

@@ -0,0 +1,396 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_ATOMIC_H_INCLUDED
#define JUCE_ATOMIC_H_INCLUDED
//==============================================================================
/**
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 explicit 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_jassert (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 JUCE_64BIT
JUCE_ALIGN (8)
#else
JUCE_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:
template <typename Dest, typename Source>
static inline Dest castTo (Source value) noexcept { union { Dest d; Source s; } u; u.s = value; return u.d; }
static inline Type castFrom32Bit (int32 value) noexcept { return castTo <Type, int32> (value); }
static inline Type castFrom64Bit (int64 value) noexcept { return castTo <Type, int64> (value); }
static inline int32 castTo32Bit (Type value) noexcept { return castTo <int32, Type> (value); }
static inline int64 castTo64Bit (Type value) noexcept { return castTo <int64, Type> (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 JUCE_IOS || (JUCE_MAC && (JUCE_PPC || JUCE_CLANG || __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2)))
#define JUCE_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 JUCE_MAC_ATOMICS_VOLATILE
#else
#define JUCE_MAC_ATOMICS_VOLATILE volatile
#endif
#if JUCE_PPC || JUCE_IOS
// None of these atomics are available for PPC or for iOS 3.1 or earlier!!
template <typename Type> static Type OSAtomicAdd64Barrier (Type b, JUCE_MAC_ATOMICS_VOLATILE Type* a) noexcept { jassertfalse; return *a += b; }
template <typename Type> static Type OSAtomicIncrement64Barrier (JUCE_MAC_ATOMICS_VOLATILE Type* a) noexcept { jassertfalse; return ++*a; }
template <typename Type> static Type OSAtomicDecrement64Barrier (JUCE_MAC_ATOMICS_VOLATILE Type* a) noexcept { jassertfalse; return --*a; }
template <typename Type> static bool OSAtomicCompareAndSwap64Barrier (Type old, Type newValue, JUCE_MAC_ATOMICS_VOLATILE Type* value) noexcept
{ jassertfalse; if (old == *value) { *value = newValue; return true; } return false; }
#define JUCE_64BIT_ATOMICS_UNAVAILABLE 1
#endif
//==============================================================================
#elif JUCE_GCC
#define JUCE_ATOMICS_GCC 1 // GCC with intrinsics
#if JUCE_IOS || JUCE_ANDROID // (64-bit ops will compile but not link on these mobile OSes)
#define JUCE_64BIT_ATOMICS_UNAVAILABLE 1
#endif
//==============================================================================
#else
#define JUCE_ATOMICS_WINDOWS 1 // Windows with intrinsics
#if JUCE_USE_INTRINSICS
#ifndef __INTEL_COMPILER
#pragma intrinsic (_InterlockedExchange, _InterlockedIncrement, _InterlockedDecrement, _InterlockedCompareExchange, \
_InterlockedCompareExchange64, _InterlockedExchangeAdd, _ReadWriteBarrier)
#endif
#define juce_InterlockedExchange(a, b) _InterlockedExchange(a, b)
#define juce_InterlockedIncrement(a) _InterlockedIncrement(a)
#define juce_InterlockedDecrement(a) _InterlockedDecrement(a)
#define juce_InterlockedExchangeAdd(a, b) _InterlockedExchangeAdd(a, b)
#define juce_InterlockedCompareExchange(a, b, c) _InterlockedCompareExchange(a, b, c)
#define juce_InterlockedCompareExchange64(a, b, c) _InterlockedCompareExchange64(a, b, c)
#define juce_MemoryBarrier _ReadWriteBarrier
#else
long juce_InterlockedExchange (volatile long* a, long b) noexcept;
long juce_InterlockedIncrement (volatile long* a) noexcept;
long juce_InterlockedDecrement (volatile long* a) noexcept;
long juce_InterlockedExchangeAdd (volatile long* a, long b) noexcept;
long juce_InterlockedCompareExchange (volatile long* a, long b, long c) noexcept;
__int64 juce_InterlockedCompareExchange64 (volatile __int64* a, __int64 b, __int64 c) noexcept;
inline void juce_MemoryBarrier() noexcept { long x = 0; juce_InterlockedIncrement (&x); }
#endif
#if JUCE_64BIT
#ifndef __INTEL_COMPILER
#pragma intrinsic (_InterlockedExchangeAdd64, _InterlockedExchange64, _InterlockedIncrement64, _InterlockedDecrement64)
#endif
#define juce_InterlockedExchangeAdd64(a, b) _InterlockedExchangeAdd64(a, b)
#define juce_InterlockedExchange64(a, b) _InterlockedExchange64(a, b)
#define juce_InterlockedIncrement64(a) _InterlockedIncrement64(a)
#define juce_InterlockedDecrement64(a) _InterlockedDecrement64(a)
#else
// None of these atomics are available in a 32-bit Windows build!!
template <typename Type> static Type juce_InterlockedExchangeAdd64 (volatile Type* a, Type b) noexcept { jassertfalse; Type old = *a; *a += b; return old; }
template <typename Type> static Type juce_InterlockedExchange64 (volatile Type* a, Type b) noexcept { jassertfalse; Type old = *a; *a = b; return old; }
template <typename Type> static Type juce_InterlockedIncrement64 (volatile Type* a) noexcept { jassertfalse; return ++*a; }
template <typename Type> static Type juce_InterlockedDecrement64 (volatile Type* a) noexcept { jassertfalse; return --*a; }
#define JUCE_64BIT_ATOMICS_UNAVAILABLE 1
#endif
#endif
#if JUCE_MSVC
#pragma warning (push)
#pragma warning (disable: 4311) // (truncation warning)
#endif
//==============================================================================
template <typename Type>
inline Type Atomic<Type>::get() const noexcept
{
#if JUCE_ATOMICS_MAC
return sizeof (Type) == 4 ? castFrom32Bit ((int32) OSAtomicAdd32Barrier ((int32_t) 0, (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value))
: castFrom64Bit ((int64) OSAtomicAdd64Barrier ((int64_t) 0, (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value));
#elif JUCE_ATOMICS_WINDOWS
return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedExchangeAdd ((volatile long*) &value, (long) 0))
: castFrom64Bit ((int64) juce_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) 0));
#elif JUCE_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 JUCE_ATOMICS_MAC || JUCE_ATOMICS_GCC
Type currentVal = value;
while (! compareAndSetBool (newValue, currentVal)) { currentVal = value; }
return currentVal;
#elif JUCE_ATOMICS_WINDOWS
return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedExchange ((volatile long*) &value, (long) castTo32Bit (newValue)))
: castFrom64Bit ((int64) juce_InterlockedExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue)));
#endif
}
template <typename Type>
inline Type Atomic<Type>::operator+= (const Type amountToAdd) noexcept
{
#if JUCE_ATOMICS_MAC
return sizeof (Type) == 4 ? (Type) OSAtomicAdd32Barrier ((int32_t) castTo32Bit (amountToAdd), (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value)
: (Type) OSAtomicAdd64Barrier ((int64_t) amountToAdd, (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value);
#elif JUCE_ATOMICS_WINDOWS
return sizeof (Type) == 4 ? (Type) (juce_InterlockedExchangeAdd ((volatile long*) &value, (long) amountToAdd) + (long) amountToAdd)
: (Type) (juce_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) amountToAdd) + (__int64) amountToAdd);
#elif JUCE_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 JUCE_ATOMICS_MAC
return sizeof (Type) == 4 ? (Type) OSAtomicIncrement32Barrier ((JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value)
: (Type) OSAtomicIncrement64Barrier ((JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value);
#elif JUCE_ATOMICS_WINDOWS
return sizeof (Type) == 4 ? (Type) juce_InterlockedIncrement ((volatile long*) &value)
: (Type) juce_InterlockedIncrement64 ((volatile __int64*) &value);
#elif JUCE_ATOMICS_GCC
return (Type) __sync_add_and_fetch (&value, 1);
#endif
}
template <typename Type>
inline Type Atomic<Type>::operator--() noexcept
{
#if JUCE_ATOMICS_MAC
return sizeof (Type) == 4 ? (Type) OSAtomicDecrement32Barrier ((JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value)
: (Type) OSAtomicDecrement64Barrier ((JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value);
#elif JUCE_ATOMICS_WINDOWS
return sizeof (Type) == 4 ? (Type) juce_InterlockedDecrement ((volatile long*) &value)
: (Type) juce_InterlockedDecrement64 ((volatile __int64*) &value);
#elif JUCE_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 JUCE_ATOMICS_MAC
return sizeof (Type) == 4 ? OSAtomicCompareAndSwap32Barrier ((int32_t) castTo32Bit (valueToCompare), (int32_t) castTo32Bit (newValue), (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value)
: OSAtomicCompareAndSwap64Barrier ((int64_t) castTo64Bit (valueToCompare), (int64_t) castTo64Bit (newValue), (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value);
#elif JUCE_ATOMICS_WINDOWS
return compareAndSetValue (newValue, valueToCompare) == valueToCompare;
#elif JUCE_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 JUCE_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 JUCE_ATOMICS_WINDOWS
return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedCompareExchange ((volatile long*) &value, (long) castTo32Bit (newValue), (long) castTo32Bit (valueToCompare)))
: castFrom64Bit ((int64) juce_InterlockedCompareExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue), (__int64) castTo64Bit (valueToCompare)));
#elif JUCE_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 JUCE_ATOMICS_MAC
OSMemoryBarrier();
#elif JUCE_ATOMICS_GCC
__sync_synchronize();
#elif JUCE_ATOMICS_WINDOWS
juce_MemoryBarrier();
#endif
}
#if JUCE_MSVC
#pragma warning (pop)
#endif
#endif // JUCE_ATOMIC_H_INCLUDED

+ 186
- 0
source/modules/juce_core/memory/juce_ByteOrder.h View File

@@ -0,0 +1,186 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_BYTEORDER_H_INCLUDED
#define JUCE_BYTEORDER_H_INCLUDED
//==============================================================================
/** Contains static methods for converting the byte order between different
endiannesses.
*/
class JUCE_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();
JUCE_DECLARE_NON_COPYABLE (ByteOrder)
};
//==============================================================================
#if JUCE_USE_INTRINSICS && ! defined (__INTEL_COMPILER)
#pragma intrinsic (_byteswap_ulong)
#endif
inline uint16 ByteOrder::swap (uint16 n)
{
#if JUCE_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 JUCE_MAC || JUCE_IOS
return OSSwapInt32 (n);
#elif JUCE_GCC && JUCE_INTEL && ! JUCE_NO_INLINE_ASM
asm("bswap %%eax" : "=a"(n) : "a"(n));
return n;
#elif JUCE_USE_INTRINSICS
return _byteswap_ulong (n);
#elif JUCE_MSVC && ! JUCE_NO_INLINE_ASM
__asm {
mov eax, n
bswap eax
mov n, eax
}
return n;
#elif JUCE_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 JUCE_MAC || JUCE_IOS
return OSSwapInt64 (value);
#elif JUCE_USE_INTRINSICS
return _byteswap_uint64 (value);
#else
return (((int64) swap ((uint32) value)) << 32) | swap ((uint32) (value >> 32));
#endif
}
#if JUCE_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 // JUCE_BYTEORDER_H_INCLUDED

+ 308
- 0
source/modules/juce_core/memory/juce_HeapBlock.h View File

@@ -0,0 +1,308 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_HEAPBLOCK_H_INCLUDED
#define JUCE_HEAPBLOCK_H_INCLUDED
#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 JUCE_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 (JUCE_DLL) || defined (JUCE_DLL_BUILD))
JUCE_DECLARE_NON_COPYABLE (HeapBlock)
JUCE_PREVENT_HEAP_ALLOCATION // Creating a 'new HeapBlock' would be missing the point!
#endif
};
#endif // JUCE_HEAPBLOCK_H_INCLUDED

+ 149
- 0
source/modules/juce_core/memory/juce_LeakedObjectDetector.h View File

@@ -0,0 +1,149 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_LEAKEDOBJECTDETECTOR_H_INCLUDED
#define JUCE_LEAKEDOBJECTDETECTOR_H_INCLUDED
#include "../text/juce_String.h"
#include "juce_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 JUCE_LEAK_DETECTOR macro as a simple way to put one in your
class declaration. Have a look through the juce 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 (JUCE_LEAK_DETECTOR)
#if (DOXYGEN || JUCE_CHECK_MEMORY_LEAKS)
/** This macro lets you embed a leak-detecting object inside a class.
To use it, simply declare a JUCE_LEAK_DETECTOR(YourClassName) inside a private section
of the class declaration. E.g.
@code
class MyClass
{
public:
MyClass();
void blahBlah();
private:
JUCE_LEAK_DETECTOR (MyClass)
};
@endcode
@see JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR, LeakedObjectDetector
*/
#define JUCE_LEAK_DETECTOR(OwnerClass) \
friend class juce::LeakedObjectDetector<OwnerClass>; \
static const char* getLeakedObjectClassName() noexcept { return #OwnerClass; } \
juce::LeakedObjectDetector<OwnerClass> JUCE_JOIN_MACRO (leakDetector, __LINE__);
#else
#define JUCE_LEAK_DETECTOR(OwnerClass)
#endif
#endif
#endif // JUCE_LEAKEDOBJECTDETECTOR_H_INCLUDED

+ 126
- 0
source/modules/juce_core/memory/juce_Memory.h View File

@@ -0,0 +1,126 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_MEMORY_H_INCLUDED
#define JUCE_MEMORY_H_INCLUDED
//==============================================================================
/** 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 JUCE_MAC || JUCE_IOS || DOXYGEN
/** A handy C++ wrapper that creates and deletes an NSAutoreleasePool object using RAII.
You should use the JUCE_AUTORELEASEPOOL macro to create a local auto-release pool on the stack.
*/
class JUCE_API ScopedAutoReleasePool
{
public:
ScopedAutoReleasePool();
~ScopedAutoReleasePool();
private:
void* pool;
JUCE_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 (JUCE_COMPILER_SUPPORTS_ARC && defined (__OBJC__)) || DOXYGEN
#define JUCE_AUTORELEASEPOOL @autoreleasepool
#else
#define JUCE_AUTORELEASEPOOL const juce::ScopedAutoReleasePool JUCE_JOIN_MACRO (autoReleasePool_, __LINE__);
#endif
#else
#define JUCE_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 juce 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 JUCE_LEAK_DETECTOR macro, these allocators can be injected into most juce classes.
*/
#if JUCE_MSVC && (defined (JUCE_DLL) || defined (JUCE_DLL_BUILD)) && ! (JUCE_DISABLE_DLL_ALLOCATORS || DOXYGEN)
extern JUCE_API void* juceDLL_malloc (size_t);
extern JUCE_API void juceDLL_free (void*);
#define JUCE_LEAK_DETECTOR(OwnerClass) public:\
static void* operator new (size_t sz) { return juce::juceDLL_malloc (sz); } \
static void* operator new (size_t, void* p) { return p; } \
static void operator delete (void* p) { juce::juceDLL_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 JUCE_LEAK_DETECTOR instead.
*/
#ifndef juce_UseDebuggingNewOperator
#define juce_UseDebuggingNewOperator
#endif
#endif // JUCE_MEMORY_H_INCLUDED

+ 421
- 0
source/modules/juce_core/memory/juce_MemoryBlock.cpp View File

@@ -0,0 +1,421 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
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)
{
jassert (other.data != nullptr);
data.malloc (size);
memcpy (data, other.data, size);
}
}
MemoryBlock::MemoryBlock (const void* const dataToInitialiseFrom, const size_t sizeInBytes)
: size (sizeInBytes)
{
jassert (((ssize_t) sizeInBytes) >= 0);
if (size > 0)
{
jassert (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 JUCE_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)
{
jassert (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)
{
jassert (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)
{
jassert (srcData != nullptr); // this must not be null!
insertPosition = jmin (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 = jmin ((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 = jmin ((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 juce_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 ((juce_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;
}

+ 260
- 0
source/modules/juce_core/memory/juce_MemoryBlock.h View File

@@ -0,0 +1,260 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_MEMORYBLOCK_H_INCLUDED
#define JUCE_MEMORYBLOCK_H_INCLUDED
#include "../text/juce_String.h"
#include "../memory/juce_HeapBlock.h"
//==============================================================================
/**
A class to hold a resizable block of raw data.
*/
class JUCE_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 JUCE_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;
JUCE_LEAK_DETECTOR (MemoryBlock)
};
#endif // JUCE_MEMORYBLOCK_H_INCLUDED

+ 188
- 0
source/modules/juce_core/memory/juce_OptionalScopedPointer.h View File

@@ -0,0 +1,188 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_OPTIONALSCOPEDPOINTER_H_INCLUDED
#define JUCE_OPTIONALSCOPEDPOINTER_H_INCLUDED
#include "juce_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 // JUCE_OPTIONALSCOPEDPOINTER_H_INCLUDED

+ 400
- 0
source/modules/juce_core/memory/juce_ReferenceCountedObject.h View File

@@ -0,0 +1,400 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_REFERENCECOUNTEDOBJECT_H_INCLUDED
#define JUCE_REFERENCECOUNTEDOBJECT_H_INCLUDED
#include "juce_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 JUCE_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
{
jassert (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!
jassert (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;
JUCE_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 JUCE_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
{
jassert (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!
jassert (getReferenceCount() == 0);
}
private:
//==============================================================================
int refCount;
JUCE_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 JUCE_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 JUCE_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 // JUCE_REFERENCECOUNTEDOBJECT_H_INCLUDED

+ 253
- 0
source/modules/juce_core/memory/juce_ScopedPointer.h View File

@@ -0,0 +1,253 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_SCOPEDPOINTER_H_INCLUDED
#define JUCE_SCOPEDPOINTER_H_INCLUDED
//==============================================================================
/**
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:
//==============================================================================
/** Creates a ScopedPointer containing a null pointer. */
inline ScopedPointer() noexcept : object (nullptr)
{
}
/** Creates a ScopedPointer that owns the specified object. */
inline ScopedPointer (ObjectType* const objectToTakePossessionOf) noexcept
: object (objectToTakePossessionOf)
{
}
/** 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 = 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!
jassert (object == nullptr || object != objectToTransferFrom.object);
ObjectType* const oldObject = object;
object = objectToTransferFrom.object;
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)
{
ObjectType* const oldObject = object;
object = newObjectToTakePossessionOf;
delete oldObject;
}
return *this;
}
#if JUCE_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!
jassert (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;
// (Required as an alternative to the overloaded & operator).
const ScopedPointer* getAddress() const noexcept { return this; }
#if ! JUCE_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.
*/
JUCE_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) 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) 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_jassert (sizeof (Type) == 12345); }
#endif
#endif // JUCE_SCOPEDPOINTER_H_INCLUDED

+ 292
- 0
source/modules/juce_core/memory/juce_Singleton.h View File

@@ -0,0 +1,292 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_SINGLETON_H_INCLUDED
#define JUCE_SINGLETON_H_INCLUDED
//==============================================================================
/**
Macro to declare member variables and methods for a singleton class.
To use this, add the line juce_DeclareSingleton (MyClass, doNotRecreateAfterDeletion)
to the class's definition.
Then put a macro juce_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();
}
juce_DeclareSingleton (MySingleton, false)
};
juce_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 juce_DeclareSingleton_SingleThreaded() macro instead
of this one.
@see juce_ImplementSingleton, juce_DeclareSingleton_SingleThreaded
*/
#define juce_DeclareSingleton(classname, doNotRecreateAfterDeletion) \
\
static classname* _singletonInstance; \
static juce::CriticalSection _singletonLock; \
\
static classname* JUCE_CALLTYPE getInstance() \
{ \
if (_singletonInstance == nullptr) \
{\
const juce::ScopedLock sl (_singletonLock); \
\
if (_singletonInstance == nullptr) \
{ \
static bool alreadyInside = false; \
static bool createdOnceAlready = false; \
\
const bool problem = alreadyInside || ((doNotRecreateAfterDeletion) && createdOnceAlready); \
jassert (! 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* JUCE_CALLTYPE getInstanceWithoutCreating() noexcept\
{ \
return _singletonInstance; \
} \
\
static void JUCE_CALLTYPE deleteInstance() \
{ \
const juce::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 juce_DeclareSingleton macro.
After adding the juce_DeclareSingleton to the class definition, this macro has
to be used in the cpp file.
*/
#define juce_ImplementSingleton(classname) \
\
classname* classname::_singletonInstance = nullptr; \
juce::CriticalSection classname::_singletonLock;
//==============================================================================
/**
Macro to declare member variables and methods for a singleton class.
This is exactly the same as juce_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 juce_DeclareSingleton for more information about
how to use it, the only difference being that you have to use
juce_ImplementSingleton_SingleThreaded instead of juce_ImplementSingleton.
@see juce_ImplementSingleton_SingleThreaded, juce_DeclareSingleton, juce_DeclareSingleton_SingleThreaded_Minimal
*/
#define juce_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); \
jassert (! 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 juce_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.
Juce use the normal juce_ImplementSingleton_SingleThreaded as the counterpart
to this declaration, as you would with juce_DeclareSingleton_SingleThreaded.
See the documentation for juce_DeclareSingleton for more information about
how to use it, the only difference being that you have to use
juce_ImplementSingleton_SingleThreaded instead of juce_ImplementSingleton.
@see juce_ImplementSingleton_SingleThreaded, juce_DeclareSingleton
*/
#define juce_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 juce_DeclareSingleton_SingleThreaded macro.
After adding juce_DeclareSingleton_SingleThreaded or juce_DeclareSingleton_SingleThreaded_Minimal
to the class definition, this macro has to be used somewhere in the cpp file.
*/
#define juce_ImplementSingleton_SingleThreaded(classname) \
\
classname* classname::_singletonInstance = nullptr;
#endif // JUCE_SINGLETON_H_INCLUDED

+ 214
- 0
source/modules/juce_core/memory/juce_WeakReference.h View File

@@ -0,0 +1,214 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_WEAKREFERENCE_H_INCLUDED
#define JUCE_WEAKREFERENCE_H_INCLUDED
#include "juce_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 JUCE_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;
JUCE_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.
jassert (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!!
jassert (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;
JUCE_DECLARE_NON_COPYABLE (Master)
};
private:
SharedRef holder;
static inline SharedPointer* getRef (ObjectType* const o)
{
return (o != nullptr) ? o->masterReference.getSharedPointer (o) : nullptr;
}
};
#endif // JUCE_WEAKREFERENCE_H_INCLUDED

+ 83
- 0
source/modules/juce_core/misc/juce_Result.cpp View File

@@ -0,0 +1,83 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
Result::Result() noexcept {}
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 JUCE_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::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(); }

+ 127
- 0
source/modules/juce_core/misc/juce_Result.h View File

@@ -0,0 +1,127 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_RESULT_H_INCLUDED
#define JUCE_RESULT_H_INCLUDED
#include "../text/juce_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 JUCE_API Result
{
public:
//==============================================================================
/** Creates and returns a 'successful' result. */
static Result ok() noexcept { return Result(); }
/** 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&);
Result& operator= (const Result&);
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
Result (Result&&) noexcept;
Result& operator= (Result&&) noexcept;
#endif
bool operator== (const Result& other) const noexcept;
bool operator!= (const Result& other) const noexcept;
private:
String errorMessage;
// The default constructor is not for public use!
// Instead, use Result::ok() or Result::fail()
Result() noexcept;
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 // JUCE_RESULT_H_INCLUDED

+ 114
- 0
source/modules/juce_core/misc/juce_Uuid.cpp View File

@@ -0,0 +1,114 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
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;
}

+ 114
- 0
source/modules/juce_core/misc/juce_Uuid.h View File

@@ -0,0 +1,114 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_UUID_H_INCLUDED
#define JUCE_UUID_H_INCLUDED
#include "../text/juce_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 JUCE_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];
JUCE_LEAK_DETECTOR (Uuid)
};
#endif // JUCE_UUID_H_INCLUDED

+ 130
- 0
source/modules/juce_core/misc/juce_WindowsRegistry.h View File

@@ -0,0 +1,130 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_WINDOWSREGISTRY_H_INCLUDED
#define JUCE_WINDOWSREGISTRY_H_INCLUDED
#if JUCE_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);
/** Returns true if the given key exists in the registry. */
static bool keyExists (const String& regValuePath);
/** Returns true if the given key exists in the registry. */
static bool keyExistsWow64 (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();
JUCE_DECLARE_NON_COPYABLE (WindowsRegistry)
};
#endif
#endif // JUCE_WINDOWSREGISTRY_H_INCLUDED

+ 707
- 0
source/modules/juce_core/native/java/JuceAppActivity.java View File

@@ -0,0 +1,707 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
package com.juce;
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 android.util.DisplayMetrics;
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.AudioManager;
import android.media.MediaScannerConnection;
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
//==============================================================================
public final class JuceAppActivity extends Activity
{
//==============================================================================
static
{
System.loadLibrary ("juce_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, int dpi);
//==============================================================================
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(), getDPI());
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 final int getDPI()
{
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics (metrics);
return metrics.densityDpi;
}
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();
JuceAppActivity.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();
JuceAppActivity.this.alertDismissed (callback, 1);
}
})
.setNegativeButton ("Cancel", new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
JuceAppActivity.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();
JuceAppActivity.this.alertDismissed (callback, 1);
}
})
.setNegativeButton ("No", new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
JuceAppActivity.this.alertDismissed (callback, 2);
}
})
.setNeutralButton ("Cancel", new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
JuceAppActivity.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);
}
}

+ 223
- 0
source/modules/juce_core/native/juce_BasicNativeHeaders.h View File

@@ -0,0 +1,223 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_BASICNATIVEHEADERS_H_INCLUDED
#define JUCE_BASICNATIVEHEADERS_H_INCLUDED
#include "../system/juce_TargetPlatform.h"
#undef T
//==============================================================================
#if JUCE_MAC || JUCE_IOS
#if JUCE_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 JUCE_WINDOWS
#if JUCE_MSVC
#ifndef _CPPRTTI
#error "You're compiling without RTTI enabled! This is needed for a lot of JUCE classes, please update your compiler settings!"
#endif
#ifndef _CPPUNWIND
#error "You're compiling without exceptions enabled! This is needed for a lot of JUCE 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
#if JUCE_MINGW
#define _WIN32_WINNT 0x0501
#else
#define _WIN32_WINNT 0x0600
#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 JUCE_MINGW
#include <basetyps.h>
#else
#include <crtdbg.h>
#include <comutil.h>
#endif
#undef PACKED
#if JUCE_MSVC
#pragma warning (pop)
#pragma warning (4: 4511 4512 4100 /*4365*/) // (enable some warnings that are turned off in VC8)
#endif
#if JUCE_MSVC && ! JUCE_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 JUCE_LOAD_WINAPI_FUNCTION(dll, functionName, localFunctionName, returnType, params) \
typedef returnType (WINAPI *type##localFunctionName) params; \
type##localFunctionName localFunctionName = (type##localFunctionName) dll.getFunction (#functionName);
//==============================================================================
#elif JUCE_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 JUCE_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 // JUCE_BASICNATIVEHEADERS_H_INCLUDED

+ 241
- 0
source/modules/juce_core/native/juce_android_Files.cpp View File

@@ -0,0 +1,241 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
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 juce_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 juce_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 juce_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;
JUCE_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 (JuceAppActivity.launchURL, t.get());
}
void File::revealToUser() const
{
}

+ 407
- 0
source/modules/juce_core/native/juce_android_JNIHelpers.h View File

@@ -0,0 +1,407 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_ANDROID_JNIHELPERS_H_INCLUDED
#define JUCE_ANDROID_JNIHELPERS_H_INCLUDED
#if ! (defined (JUCE_ANDROID_ACTIVITY_CLASSNAME) && defined (JUCE_ANDROID_ACTIVITY_CLASSPATH))
#error "The JUCE_ANDROID_ACTIVITY_CLASSNAME and JUCE_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 juceString (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 juceString (jstring s)
{
return juceString (getEnv(), s);
}
LocalRef<jstring> javaString (const String& s)
{
return LocalRef<jstring> (getEnv()->NewStringUTF (s.toUTF8()));
}
LocalRef<jstring> javaStringFromChar (const juce_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*);
JUCE_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 JUCE_JNI_CALLBACK(className, methodName, returnType, params) \
extern "C" __attribute__ ((visibility("default"))) returnType JUCE_JOIN_MACRO (JUCE_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, dpi;
};
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();
jassert (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" JUCE_ANDROID_ACTIVITY_CLASSPATH "$ComponentPeerView;") \
METHOD (deleteView, "deleteView", "(L" JUCE_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" JUCE_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 (JuceAppActivity, JUCE_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 // JUCE_ANDROID_JNIHELPERS_H_INCLUDED

+ 32
- 0
source/modules/juce_core/native/juce_android_Misc.cpp View File

@@ -0,0 +1,32 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
void Logger::outputDebugString (const String& text)
{
__android_log_print (ANDROID_LOG_INFO, "JUCE", text.toUTF8());
}

+ 175
- 0
source/modules/juce_core/native/juce_android_Network.cpp View File

@@ -0,0 +1,175 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
//==============================================================================
#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, JUCE_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 (JuceAppActivity,
JuceAppActivity.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 (juceString (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() override { return stream != nullptr && stream.callBooleanMethod (HTTPStream.isExhausted); }
int64 getTotalLength() override { return stream != nullptr ? stream.callLongMethod (HTTPStream.getTotalLength) : 0; }
int64 getPosition() override { return stream != nullptr ? stream.callLongMethod (HTTPStream.getPosition) : 0; }
bool setPosition (int64 wantedPos) override { return stream != nullptr && stream.callBooleanMethod (HTTPStream.setPosition, (jlong) wantedPos); }
int read (void* buffer, int bytesToRead) override
{
jassert (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:
JUCE_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
- 0
source/modules/juce_core/native/juce_android_SystemStats.cpp View File

@@ -0,0 +1,307 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
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));
jassert (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);
jassert (m != 0);
return m;
}
jmethodID JNIClassBase::resolveStaticMethod (JNIEnv* env, const char* methodName, const char* params)
{
jmethodID m = env->GetStaticMethodID (classRef, methodName, params);
jassert (m != 0);
return m;
}
jfieldID JNIClassBase::resolveField (JNIEnv* env, const char* fieldName, const char* signature)
{
jfieldID f = env->GetFieldID (classRef, fieldName, signature);
jassert (f != 0);
return f;
}
jfieldID JNIClassBase::resolveStaticField (JNIEnv* env, const char* fieldName, const char* signature)
{
jfieldID f = env->GetStaticFieldID (classRef, fieldName, signature);
jassert (f != 0);
return f;
}
//==============================================================================
ThreadLocalJNIEnvHolder threadLocalJNIEnvHolder;
#if JUCE_DEBUG
static bool systemInitialised = false;
#endif
JNIEnv* getEnv() noexcept
{
#if JUCE_DEBUG
if (! systemInitialised)
{
DBG ("*** Call to getEnv() when system not initialised");
jassertfalse;
std::exit (EXIT_FAILURE);
}
#endif
return threadLocalJNIEnvHolder.getOrAttach();
}
extern "C" jint JNI_OnLoad (JavaVM*, void*)
{
return JNI_VERSION_1_2;
}
//==============================================================================
AndroidSystem::AndroidSystem() : screenWidth (0), screenHeight (0), dpi (160)
{
}
void AndroidSystem::initialise (JNIEnv* env, jobject activity_,
jstring appFile_, jstring appDataDir_)
{
screenWidth = screenHeight = 0;
dpi = 160;
JNIClassBase::initialiseAllClasses (env);
threadLocalJNIEnvHolder.initialise (env);
#if JUCE_DEBUG
systemInitialised = true;
#endif
activity = GlobalRef (activity_);
appFile = juceString (env, appFile_);
appDataDir = juceString (env, appDataDir_);
}
void AndroidSystem::shutdown (JNIEnv* env)
{
activity.clear();
#if JUCE_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 juceString (LocalRef<jstring> ((jstring) getEnv()->CallStaticObjectMethod (SystemClass,
SystemClass.getProperty,
javaString (name).get())));
}
//==============================================================================
String getLocaleValue (bool isRegion)
{
return juceString (LocalRef<jstring> ((jstring) getEnv()->CallStaticObjectMethod (JuceAppActivity,
JuceAppActivity.getLocaleValue,
isRegion)));
}
}
//==============================================================================
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
{
return Android;
}
String SystemStats::getOperatingSystemName()
{
return "Android " + AndroidStatsHelpers::getSystemProperty ("os.version");
}
bool SystemStats::isOperatingSystem64Bit()
{
#if JUCE_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(); }
//==============================================================================
void CPUInformation::initialise() noexcept
{
numCpus = jmax (1, sysconf (_SC_NPROCESSORS_ONLN));
}
//==============================================================================
uint32 juce_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;
}

+ 81
- 0
source/modules/juce_core/native/juce_android_Threads.cpp View File

@@ -0,0 +1,81 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
/*
Note that a lot of methods that you'd expect to find in this file actually
live in juce_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, &param);
}
void Process::terminate()
{
std::exit (EXIT_FAILURE);
}
JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger()
{
return false;
}
JUCE_API bool JUCE_CALLTYPE Process::isRunningUnderDebugger()
{
return juce_isRunningUnderDebugger();
}
void Process::raisePrivilege() {}
void Process::lowerPrivilege() {}

+ 378
- 0
source/modules/juce_core/native/juce_linux_Files.cpp View File

@@ -0,0 +1,378 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
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 juce_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 juce_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* juce_argv = nullptr;
int juce_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 (juce_argv != nullptr && juce_argc > 0)
return File (CharPointer_UTF8 (juce_argv[0]));
// deliberate fall-through...
case currentExecutableFile:
case currentApplicationFile:
return juce_getExecutableFile();
case hostApplicationPath:
return juce_readlink ("/proc/self/exe", juce_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;
JUCE_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)
{
juce_statStruct info;
return juce_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();
}

+ 462
- 0
source/modules/juce_core/native/juce_linux_Network.cpp View File

@@ -0,0 +1,462 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
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() override { return finished; }
int64 getPosition() override { return position; }
int64 getTotalLength() override
{
//xxx to do
return -1;
}
int read (void* buffer, int bytesToRead) override
{
if (finished || isError())
return 0;
fd_set readbits;
FD_ZERO (&readbits);
FD_SET (socketHandle, &readbits);
struct timeval tv;
tv.tv_sec = jmax (1, timeOutMs / 1000);
tv.tv_usec = 0;
if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0)
return 0; // (timeout)
const int bytesRead = jmax (0, (int) recv (socketHandle, buffer, bytesToRead, MSG_WAITALL));
if (bytesRead == 0)
finished = true;
position += bytesRead;
return bytesRead;
}
bool setPosition (int64 wantedPos) override
{
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 JUCE_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 = jmax (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:", "JUCE/" JUCE_STRINGIFY(JUCE_MAJOR_VERSION)
"." JUCE_STRINGIFY(JUCE_MINOR_VERSION)
"." JUCE_STRINGIFY(JUCE_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 = jmin (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;
}
JUCE_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();
}

+ 181
- 0
source/modules/juce_core/native/juce_linux_SystemStats.cpp View File

@@ -0,0 +1,181 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
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 JUCE_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)
if (passwd* const pw = getpwuid (getuid()))
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;
}
static String getLocaleValue (nl_item key)
{
const char* oldLocale = ::setlocale (LC_ALL, "");
String result (String::fromUTF8 (nl_langinfo (key)));
::setlocale (LC_ALL, oldLocale);
return result;
}
String SystemStats::getUserLanguage() { return getLocaleValue (_NL_IDENTIFICATION_LANGUAGE); }
String SystemStats::getUserRegion() { return getLocaleValue (_NL_IDENTIFICATION_TERRITORY); }
String SystemStats::getDisplayLanguage() { return getUserLanguage(); }
//==============================================================================
void CPUInformation::initialise() noexcept
{
const String flags (LinuxStatsHelpers::getCpuInfo ("flags"));
hasMMX = flags.contains ("mmx");
hasSSE = flags.contains ("sse");
hasSSE2 = flags.contains ("sse2");
hasSSE3 = flags.contains ("sse3");
has3DNow = flags.contains ("3dnow");
numCpus = LinuxStatsHelpers::getCpuInfo ("processor").getIntValue() + 1;
}
//==============================================================================
uint32 juce_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;
}

+ 94
- 0
source/modules/juce_core/native/juce_linux_Threads.cpp View File

@@ -0,0 +1,94 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
/*
Note that a lot of methods that you'd expect to find in this file actually
live in juce_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, &param);
}
void Process::terminate()
{
std::exit (EXIT_FAILURE);
}
JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger()
{
#if JUCE_BSD
return false;
#else
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;
#endif
}
JUCE_API bool JUCE_CALLTYPE Process::isRunningUnderDebugger()
{
return juce_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(); }

+ 485
- 0
source/modules/juce_core/native/juce_mac_Files.mm View File

@@ -0,0 +1,485 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
/*
Note that a lot of methods that you'd expect to find in this file actually
live in juce_posix_SharedCode.h!
*/
//==============================================================================
bool File::copyInternal (const File& dest) const
{
JUCE_AUTORELEASEPOOL
{
NSFileManager* fm = [NSFileManager defaultManager];
return [fm fileExistsAtPath: juceStringToNS (fullPath)]
#if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
&& [fm copyItemAtPath: juceStringToNS (fullPath)
toPath: juceStringToNS (dest.getFullPathName())
error: nil];
#else
&& [fm copyPath: juceStringToNS (fullPath)
toPath: juceStringToNS (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 (juce_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
JUCE_AUTORELEASEPOOL
{
NSNumber* hidden = nil;
NSError* err = nil;
return [[NSURL fileURLWithPath: juceStringToNS (path)]
getResourceValue: &hidden forKey: NSURLIsHiddenKey error: &err]
&& [hidden boolValue];
}
#elif JUCE_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 JUCE_IOS
String getIOSSystemLocation (NSSearchPathDirectory type)
{
return nsStringToJuce ([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 JUCE_IOS
return false; // xxx is this possible?
#else
JUCE_AUTORELEASEPOOL
{
BOOL removable = false;
[[NSWorkspace sharedWorkspace]
getFileSystemInfoForPath: juceStringToNS (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* juce_argv = nullptr;
int juce_argc = 0;
File File::getSpecialLocation (const SpecialLocationType type)
{
JUCE_AUTORELEASEPOOL
{
String resultPath;
switch (type)
{
case userHomeDirectory: resultPath = nsStringToJuce (NSHomeDirectory()); break;
#if JUCE_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 (juce_getExecutableFile().getFileNameWithoutExtension());
tmp.createDirectory();
return tmp.getFullPathName();
}
#else
case userDocumentsDirectory: resultPath = "~/Documents"; break;
case userDesktopDirectory: resultPath = "~/Desktop"; break;
case tempDirectory:
{
File tmp ("~/Library/Caches/" + juce_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 (juce_argv != nullptr && juce_argc > 0)
return File (CharPointer_UTF8 (juce_argv[0]));
// deliberate fall-through...
case currentExecutableFile:
return juce_getExecutableFile();
case currentApplicationFile:
{
const File exe (juce_getExecutableFile());
const File parent (exe.getParentDirectory());
#if JUCE_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
{
JUCE_AUTORELEASEPOOL
{
if (NSBundle* bundle = [NSBundle bundleWithPath: juceStringToNS (getFullPathName())])
if (NSDictionary* info = [bundle infoDictionary])
if (NSString* name = [info valueForKey: nsStringLiteral ("CFBundleShortVersionString")])
return nsStringToJuce (name);
}
return String::empty;
}
//==============================================================================
File File::getLinkedTarget() const
{
#if JUCE_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: juceStringToNS (getFullPathName()) error: nil];
#else
// (the cast here avoids a deprecation warning)
NSString* dest = [((id) [NSFileManager defaultManager]) pathContentOfSymbolicLinkAtPath: juceStringToNS (getFullPathName())];
#endif
if (dest != nil)
return File (nsStringToJuce (dest));
return *this;
}
//==============================================================================
bool File::moveToTrash() const
{
if (! exists())
return true;
#if JUCE_IOS
return deleteFile(); //xxx is there a trashcan on the iOS?
#else
JUCE_AUTORELEASEPOOL
{
NSString* p = juceStringToNS (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)
{
JUCE_AUTORELEASEPOOL
{
enumerator = [[[NSFileManager defaultManager] enumeratorAtPath: juceStringToNS (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)
{
JUCE_AUTORELEASEPOOL
{
const char* wildcardUTF8 = nullptr;
for (;;)
{
NSString* file;
if (enumerator == nil || (file = [enumerator nextObject]) == nil)
return false;
[enumerator skipDescendents];
filenameFound = nsStringToJuce (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;
JUCE_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 JUCE_IOS
return [[UIApplication sharedApplication] openURL: [NSURL URLWithString: juceStringToNS (fileName)]];
#else
JUCE_AUTORELEASEPOOL
{
if (parameters.isEmpty())
{
return [[NSWorkspace sharedWorkspace] openFile: juceStringToNS (fileName)]
|| [[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString: juceStringToNS (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: juceStringToNS (docs[i])];
ok = [[NSWorkspace sharedWorkspace] openURLs: urls
withAppBundleIdentifier: [[NSBundle bundleWithPath: juceStringToNS (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 ! JUCE_IOS
if (exists())
[[NSWorkspace sharedWorkspace] selectFile: juceStringToNS (getFullPathName()) inFileViewerRootedAtPath: nsEmptyString()];
else if (getParentDirectory().exists())
getParentDirectory().revealToUser();
#endif
}
//==============================================================================
OSType File::getMacOSType() const
{
JUCE_AUTORELEASEPOOL
{
#if JUCE_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: juceStringToNS (getFullPathName()) error: nil];
#else
// (the cast here avoids a deprecation warning)
NSDictionary* fileDict = [((id) [NSFileManager defaultManager]) fileAttributesAtPath: juceStringToNS (getFullPathName()) traverseLink: NO];
#endif
return [fileDict fileHFSTypeCode];
}
}
bool File::isBundle() const
{
#if JUCE_IOS
return false; // xxx can't find a sensible way to do this without trying to open the bundle..
#else
JUCE_AUTORELEASEPOOL
{
return [[NSWorkspace sharedWorkspace] isFilePackageAtPath: juceStringToNS (getFullPathName())];
}
#endif
}
#if JUCE_MAC
void File::addToDock() const
{
// check that it's not already there...
if (! juce_getOutputFromCommand ("defaults read com.apple.dock persistent-apps").containsIgnoreCase (getFullPathName()))
{
juce_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>\"");
juce_runSystemCommand ("osascript -e \"tell application \\\"Dock\\\" to quit\"");
}
}
#endif

+ 432
- 0
source/modules/juce_core/native/juce_mac_Network.mm View File

@@ -0,0 +1,432 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
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 JUCE_IOS
//xxx probably need to use MFMailComposeViewController
jassertfalse;
return false;
#else
JUCE_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: juceStringToNS (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 = jmin (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 (nsStringToJuce ([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() override
{
connection = [[NSURLConnection alloc] initWithRequest: request
delegate: delegate];
while (! threadShouldExit())
{
JUCE_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> ("JUCEAppDelegate_")
{
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();
}
};
JUCE_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_)
{
JUCE_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 (nsStringToJuce (key),
nsStringToJuce ((NSString*) [connection->headers objectForKey: key]));
}
}
}
//==============================================================================
bool isError() const { return connection == nullptr; }
int64 getTotalLength() override { return connection == nullptr ? -1 : connection->contentLength; }
bool isExhausted() override { return finished; }
int64 getPosition() override { return position; }
int read (void* buffer, int bytesToRead) override
{
jassert (buffer != nullptr && bytesToRead >= 0);
if (finished || isError())
return 0;
JUCE_AUTORELEASEPOOL
{
const int bytesRead = connection->read (static_cast <char*> (buffer), bytesToRead);
position += bytesRead;
if (bytesRead == 0)
finished = true;
return bytesRead;
}
}
bool setPosition (int64 wantedPos) override
{
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)
{
jassert (connection == nullptr);
NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL: [NSURL URLWithString: juceStringToNS (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: juceStringToNS (value) forHTTPHeaderField: juceStringToNS (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;
}
}
JUCE_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();
}

+ 96
- 0
source/modules/juce_core/native/juce_mac_Strings.mm View File

@@ -0,0 +1,96 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
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 JUCE_IOS
JUCE_AUTORELEASEPOOL
{
return nsStringToJuce ([juceStringToNS (*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
}

+ 292
- 0
source/modules/juce_core/native/juce_mac_SystemStats.mm View File

@@ -0,0 +1,292 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
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 JUCE_INTEL && ! JUCE_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 JUCE_64BIT
, "b" (lb), "c" (lc), "d" (ld)
#endif
);
a = la; b = lb; c = lc; d = ld;
}
#endif
}
//==============================================================================
void CPUInformation::initialise() noexcept
{
#if JUCE_INTEL && ! JUCE_NO_INLINE_ASM
uint32 a = 0, b = 0, d = 0, c = 0;
SystemStatsHelpers::doCPUID (a, b, c, d, 1);
hasMMX = (d & (1u << 23)) != 0;
hasSSE = (d & (1u << 25)) != 0;
hasSSE2 = (d & (1u << 26)) != 0;
has3DNow = (b & (1u << 31)) != 0;
hasSSE3 = (c & (1u << 0)) != 0;
#endif
#if JUCE_IOS || (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
numCpus = (int) [[NSProcessInfo processInfo] activeProcessorCount];
#else
numCpus = (int) MPProcessors();
#endif
}
#if JUCE_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 ! JUCE_IOS
static String getOSXVersion()
{
JUCE_AUTORELEASEPOOL
{
NSDictionary* dict = [NSDictionary dictionaryWithContentsOfFile:
nsStringLiteral ("/System/Library/CoreServices/SystemVersion.plist")];
return nsStringToJuce ([dict objectForKey: nsStringLiteral ("ProductVersion")]);
}
}
#endif
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
{
#if JUCE_IOS
return iOS;
#else
StringArray parts;
parts.addTokens (getOSXVersion(), ".", String::empty);
jassert (parts[0].getIntValue() == 10);
const int major = parts[1].getIntValue();
jassert (major > 2);
return (OperatingSystemType) (major + MacOSX_10_4 - 4);
#endif
}
String SystemStats::getOperatingSystemName()
{
#if JUCE_IOS
return "iOS " + nsStringToJuce ([[UIDevice currentDevice] systemVersion]);
#else
return "Mac OSX " + getOSXVersion();
#endif
}
bool SystemStats::isOperatingSystem64Bit()
{
#if JUCE_IOS
return false;
#elif JUCE_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 JUCE_INTEL && ! JUCE_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 JUCE_BIG_ENDIAN
if (speedSize == 4)
speedHz >>= 32;
#endif
return (int) (speedHz / 1000000);
}
//==============================================================================
String SystemStats::getLogonName()
{
return nsStringToJuce (NSUserName());
}
String SystemStats::getFullUserName()
{
return nsStringToJuce (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 juce_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();
}

+ 98
- 0
source/modules/juce_core/native/juce_mac_Threads.mm View File

@@ -0,0 +1,98 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
/*
Note that a lot of methods that you'd expect to find in this file actually
live in juce_posix_SharedCode.h!
*/
//==============================================================================
bool Process::isForegroundProcess()
{
#if JUCE_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 JUCE_MAC
[NSApp activateIgnoringOtherApps: YES];
#endif
}
void Process::hide()
{
#if JUCE_MAC
[NSApp hide: nil];
#endif
}
void Process::raisePrivilege()
{
jassertfalse;
}
void Process::lowerPrivilege()
{
jassertfalse;
}
void Process::terminate()
{
std::exit (EXIT_FAILURE);
}
void Process::setPriority (ProcessPriority)
{
// xxx
}
//==============================================================================
JUCE_API bool JUCE_CALLTYPE juce_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;
}
JUCE_API bool JUCE_CALLTYPE Process::isRunningUnderDebugger()
{
return juce_isRunningUnderDebugger();
}

+ 167
- 0
source/modules/juce_core/native/juce_osx_ObjCHelpers.h View File

@@ -0,0 +1,167 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_OSX_OBJCHELPERS_H_INCLUDED
#define JUCE_OSX_OBJCHELPERS_H_INCLUDED
/* 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 nsStringToJuce (NSString* s)
{
return CharPointer_UTF8 ([s UTF8String]);
}
static inline NSString* juceStringToNS (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 RectangleType>
static NSRect makeNSRect (const RectangleType& r) noexcept
{
return NSMakeRect (static_cast <CGFloat> (r.getX()),
static_cast <CGFloat> (r.getY()),
static_cast <CGFloat> (r.getWidth()),
static_cast <CGFloat> (r.getHeight()));
}
}
//==============================================================================
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));
jassert (b); (void) b;
}
template <typename FunctionType>
void addMethod (SEL selector, FunctionType callbackFn, const char* signature)
{
BOOL b = class_addMethod (cls, selector, (IMP) callbackFn, signature);
jassert (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);
jassert (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 (juce::Random::getSystemRandom().nextInt64());
}
JUCE_DECLARE_NON_COPYABLE (ObjCClass)
};
#endif // JUCE_OSX_OBJCHELPERS_H_INCLUDED

+ 219
- 0
source/modules/juce_core/native/juce_posix_NamedPipe.cpp View File

@@ -0,0 +1,219 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
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);
juce_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
: jmin (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);
}
JUCE_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 JUCE_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;
}

+ 1275
- 0
source/modules/juce_core/native/juce_posix_SharedCode.h
File diff suppressed because it is too large
View File


+ 170
- 0
source/modules/juce_core/native/juce_win32_ComSmartPtr.h View File

@@ -0,0 +1,170 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_WIN32_COMSMARTPTR_H_INCLUDED
#define JUCE_WIN32_COMSMARTPTR_H_INCLUDED
#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());
jassert (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 JUCE_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;
JUCE_COMRESULT QueryInterface (REFIID refId, void** result)
{
if (refId == IID_IUnknown)
return castToType <IUnknown> (result);
*result = 0;
return E_NOINTERFACE;
}
template <class Type>
JUCE_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() {}
JUCE_COMRESULT QueryInterface (REFIID refId, void** result)
{
if (refId == __uuidof (ComClass))
return this->template castToType <ComClass> (result);
return ComBaseClassHelperBase <ComClass>::QueryInterface (refId, result);
}
};
#endif // JUCE_WIN32_COMSMARTPTR_H_INCLUDED

+ 961
- 0
source/modules/juce_core/native/juce_win32_Files.cpp View File

@@ -0,0 +1,961 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#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_jassert (sizeof (ULARGE_INTEGER) == sizeof (FILETIME)); // tell me if this fails!
return (int64) ((reinterpret_cast<const ULARGE_INTEGER*> (ft)->QuadPart - 116444736000000000LL) / 10000);
}
FILETIME* timeToFileTime (const int64 time, FILETIME* const ft) noexcept
{
if (time <= 0)
return nullptr;
reinterpret_cast<ULARGE_INTEGER*> (ft)->QuadPart = (ULONGLONG) (time * 10000 + 116444736000000000LL);
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 juce_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 juce_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)
{
jassert (mode == readOnly || mode == readWrite);
if (range.getStart() > 0)
{
SYSTEM_INFO systemInfo;
GetNativeSystemInfo (&systemInfo);
range.setStart (range.getStart() - (range.getStart() % systemInfo.dwAllocationGranularity));
}
DWORD accessMode = GENERIC_READ, createType = OPEN_EXISTING;
DWORD protect = PAGE_READONLY, access = FILE_MAP_READ;
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 JUCE_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;
JUCE_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;
JUCE_TRY
{
hInstance = ShellExecute (0, 0, fileName.toWideCharPointer(),
parameters.toWideCharPointer(), 0, SW_SHOWDEFAULT);
}
JUCE_CATCH_ALL
return hInstance > (HINSTANCE) 32;
}
void File::revealToUser() const
{
DynamicLibrary dll ("Shell32.dll");
JUCE_LOAD_WINAPI_FUNCTION (dll, ILCreateFromPathW, ilCreateFromPathW, ITEMIDLIST*, (LPCWSTR))
JUCE_LOAD_WINAPI_FUNCTION (dll, ILFree, ilFree, void, (ITEMIDLIST*))
JUCE_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;
}
JUCE_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;
}

+ 469
- 0
source/modules/juce_core/native/juce_win32_Network.cpp View File

@@ -0,0 +1,469 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#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)
{
jassert (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("juce"), 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 = jmin (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();
}
JUCE_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");
JUCE_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");
JUCE_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");
JUCE_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;
}

+ 236
- 0
source/modules/juce_core/native/juce_win32_Registry.cpp View File

@@ -0,0 +1,236 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
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 keyExists (const String& regValuePath, const DWORD wow64Flags)
{
return RegistryKeyWrapper (regValuePath, false, wow64Flags).key != 0;
}
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;
JUCE_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::keyExistsWow64 (const String& regValuePath)
{
return RegistryKeyWrapper::keyExists (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);
}
bool WindowsRegistry::keyExists (const String& regValuePath)
{
return RegistryKeyWrapper::keyExists (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)));
}

+ 435
- 0
source/modules/juce_core/native/juce_win32_SystemStats.cpp View File

@@ -0,0 +1,435 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
void Logger::outputDebugString (const String& text)
{
OutputDebugString ((text + "\n").toWideCharPointer());
}
//==============================================================================
#ifdef JUCE_DLL_BUILD
JUCE_API void* juceDLL_malloc (size_t sz) { return std::malloc (sz); }
JUCE_API void juceDLL_free (void* block) { std::free (block); }
#endif
//==============================================================================
#if JUCE_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 juce_getCpuVendor (char* const v)
{
int vendor[4] = { 0 };
#if ! JUCE_MINGW
__try
#endif
{
#if JUCE_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 ! JUCE_MINGW
__except (EXCEPTION_EXECUTE_HANDLER)
{
}
#endif
memcpy (v, vendor, 16);
}
String SystemStats::getCpuVendor()
{
char v [16];
juce_getCpuVendor (v);
return String (v, 16);
}
#endif
//==============================================================================
void CPUInformation::initialise() noexcept
{
hasMMX = IsProcessorFeaturePresent (PF_MMX_INSTRUCTIONS_AVAILABLE) != 0;
hasSSE = IsProcessorFeaturePresent (PF_XMMI_INSTRUCTIONS_AVAILABLE) != 0;
hasSSE2 = IsProcessorFeaturePresent (PF_XMMI64_INSTRUCTIONS_AVAILABLE) != 0;
hasSSE3 = IsProcessorFeaturePresent (13 /*PF_SSE3_INSTRUCTIONS_AVAILABLE*/) != 0;
has3DNow = IsProcessorFeaturePresent (7 /*PF_AMD3D_INSTRUCTIONS_AVAILABLE*/) != 0;
SYSTEM_INFO systemInfo;
GetNativeSystemInfo (&systemInfo);
numCpus = (int) systemInfo.dwNumberOfProcessors;
}
#if JUCE_MSVC && JUCE_CHECK_MEMORY_LEAKS
struct DebugFlagsInitialiser
{
DebugFlagsInitialiser()
{
_CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
}
};
static DebugFlagsInitialiser debugFlagsInitialiser;
#endif
//==============================================================================
static bool isWindowsVersionOrLater (SystemStats::OperatingSystemType target)
{
OSVERSIONINFOEX info;
zerostruct (info);
info.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
if (target >= SystemStats::WinVista)
{
info.dwMajorVersion = 6;
switch (target)
{
case SystemStats::WinVista: info.dwMinorVersion = 0; break;
case SystemStats::Windows7: info.dwMinorVersion = 1; break;
case SystemStats::Windows8: info.dwMinorVersion = 2; break;
default: jassertfalse; break;
}
}
else
{
info.dwMajorVersion = 5;
info.dwMinorVersion = target >= SystemStats::WinXP ? 1 : 0;
}
DWORDLONG mask = 0;
VER_SET_CONDITION (mask, VER_MAJORVERSION, VER_GREATER_EQUAL);
VER_SET_CONDITION (mask, VER_MINORVERSION, VER_GREATER_EQUAL);
VER_SET_CONDITION (mask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
VER_SET_CONDITION (mask, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL);
return VerifyVersionInfo (&info,
VER_MAJORVERSION | VER_MINORVERSION
| VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR,
mask) != FALSE;
}
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
{
const SystemStats::OperatingSystemType types[]
= { Windows8, Windows7, WinVista, WinXP, Win2000 };
for (int i = 0; i < numElementsInArray (types); ++i)
if (isWindowsVersionOrLater (types[i]))
return types[i];
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 JUCE_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 juce_millisecondsSinceStartup() noexcept
{
return (uint32) timeGetTime();
}
//==============================================================================
class HiResCounterHandler
{
public:
HiResCounterHandler()
: hiResTicksOffset (0)
{
const MMRESULT res = timeBeginPeriod (1);
(void) res;
jassert (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 = (juce_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 juce_getClockCycleCounter() noexcept
{
#if JUCE_USE_INTRINSICS
// MS intrinsics version...
return (int64) __rdtsc();
#elif JUCE_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 = juce_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 = juce_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");
JUCE_LOAD_WINAPI_FUNCTION (dll, GetUserDefaultUILanguage, getUserDefaultUILanguage, LANGID, (void))
if (getUserDefaultUILanguage != nullptr)
return getLocaleValue (MAKELCID (getUserDefaultUILanguage(), SORT_DEFAULT), LOCALE_SISO639LANGNAME, "en");
return "en";
}

+ 639
- 0
source/modules/juce_core/native/juce_win32_Threads.cpp View File

@@ -0,0 +1,639 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
HWND juce_messageWindowHandle = 0; // (this is used by other parts of the codebase)
//==============================================================================
#if ! JUCE_USE_INTRINSICS
// In newer compilers, the inline versions of these are used (in juce_Atomic.h), but in
// older ones we have to actually call the ops as win32 functions..
long juce_InterlockedExchange (volatile long* a, long b) noexcept { return InterlockedExchange (a, b); }
long juce_InterlockedIncrement (volatile long* a) noexcept { return InterlockedIncrement (a); }
long juce_InterlockedDecrement (volatile long* a) noexcept { return InterlockedDecrement (a); }
long juce_InterlockedExchangeAdd (volatile long* a, long b) noexcept { return InterlockedExchangeAdd (a, b); }
long juce_InterlockedCompareExchange (volatile long* a, long b, long c) noexcept { return InterlockedCompareExchange (a, b, c); }
__int64 juce_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 JUCE_VC7_OR_EARLIER
static_jassert (sizeof (CRITICAL_SECTION) <= 24);
#else
static_jassert (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 JUCE_API juce_threadEntryPoint (void*);
static unsigned int __stdcall threadEntryProc (void* userData)
{
if (juce_messageWindowHandle != 0)
AttachThreadInput (GetWindowThreadProcessId (juce_messageWindowHandle, 0),
GetCurrentThreadId(), TRUE);
juce_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 JUCE_DEBUG
OutputDebugStringA ("** Warning - Forced thread termination **\n");
#endif
TerminateThread (threadHandle, 0);
}
}
void Thread::setCurrentThreadName (const String& name)
{
#if JUCE_DEBUG && JUCE_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 JUCE_DEBUG
_T("JUCE Sleep Event")))
#else
nullptr))
#endif
{}
~SleepEvent() noexcept
{
CloseHandle (handle);
handle = 0;
}
HANDLE handle;
};
static SleepEvent sleepEvent;
void JUCE_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 juce_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;
juce_repeatLastProcessPriority();
}
}
JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger()
{
return IsDebuggerPresent() != FALSE;
}
bool JUCE_CALLTYPE Process::isRunningUnderDebugger()
{
return juce_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 JUCE_MSVC && JUCE_CHECK_MEMORY_LEAKS
_CrtDumpMemoryLeaks();
#endif
// bullet in the head in case there's a problem shutting down..
ExitProcess (1);
}
bool juce_isRunningInWine()
{
HMODULE ntdll = GetModuleHandleA ("ntdll");
return ntdll != 0 && GetProcAddress (ntdll, "wine_get_version") != nullptr;
}
//==============================================================================
bool DynamicLibrary::open (const String& name)
{
close();
JUCE_TRY
{
handle = LoadLibrary (name.toWideCharPointer());
}
JUCE_CATCH_ALL
return handle != nullptr;
}
void DynamicLibrary::close()
{
JUCE_TRY
{
if (handle != nullptr)
{
FreeLibrary ((HMODULE) handle);
handle = nullptr;
}
}
JUCE_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!
jassert (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 = jmin ((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;
JUCE_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()
{
jassert (periodMs == 0);
}
void start (int newPeriod)
{
if (newPeriod != periodMs)
{
stop();
periodMs = newPeriod;
TIMECAPS tc;
if (timeGetDevCaps (&tc, sizeof (tc)) == TIMERR_NOERROR)
{
const int actualPeriod = jlimit ((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();
}
JUCE_DECLARE_NON_COPYABLE (Pimpl)
};

+ 149
- 0
source/modules/juce_core/network/juce_IPAddress.cpp View File

@@ -0,0 +1,149 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
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 ! JUCE_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 JUCE_MAC || JUCE_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

+ 82
- 0
source/modules/juce_core/network/juce_IPAddress.h View File

@@ -0,0 +1,82 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_IPADDRESS_H_INCLUDED
#define JUCE_IPADDRESS_H_INCLUDED
//==============================================================================
/**
An IPV4 address.
*/
class JUCE_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 // JUCE_IPADDRESS_H_INCLUDED

+ 78
- 0
source/modules/juce_core/network/juce_MACAddress.cpp View File

@@ -0,0 +1,78 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
MACAddress::MACAddress()
{
zeromem (address, sizeof (address));
}
MACAddress::MACAddress (const MACAddress& other)
{
memcpy (address, other.address, sizeof (address));
}
MACAddress& MACAddress::operator= (const MACAddress& other)
{
memcpy (address, other.address, sizeof (address));
return *this;
}
MACAddress::MACAddress (const uint8 bytes[6])
{
memcpy (address, bytes, sizeof (address));
}
String MACAddress::toString() const
{
String s;
for (size_t i = 0; i < sizeof (address); ++i)
{
s << String::toHexString ((int) address[i]).paddedLeft ('0', 2);
if (i < sizeof (address) - 1)
s << '-';
}
return s;
}
int64 MACAddress::toInt64() const noexcept
{
int64 n = 0;
for (int i = (int) sizeof (address); --i >= 0;)
n = (n << 8) | address[i];
return n;
}
bool MACAddress::isNull() const noexcept { return toInt64() == 0; }
bool MACAddress::operator== (const MACAddress& other) const noexcept { return memcmp (address, other.address, sizeof (address)) == 0; }
bool MACAddress::operator!= (const MACAddress& other) const noexcept { return ! operator== (other); }

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save