Browse Source

Correction to String::copyToUTF8. Millisecond timer rollover fix. Added channel count to BufferingAudioSource. Hashmap speed-up. Added Identifier::isValidIdentifier.

tags/2021-05-28
Julian Storer 14 years ago
parent
commit
b820ec4567
21 changed files with 262 additions and 268 deletions
  1. +99
    -92
      juce_amalgamated.cpp
  2. +79
    -128
      juce_amalgamated.h
  3. +1
    -1
      src/audio/audio_sources/juce_AudioTransportSource.cpp
  4. +7
    -5
      src/audio/audio_sources/juce_BufferingAudioSource.cpp
  5. +4
    -2
      src/audio/audio_sources/juce_BufferingAudioSource.h
  6. +3
    -0
      src/audio/devices/juce_AudioDeviceManager.h
  7. +14
    -17
      src/containers/juce_HashMap.h
  8. +1
    -1
      src/core/juce_StandardHeader.h
  9. +3
    -1
      src/core/juce_Time.cpp
  10. +4
    -0
      src/core/juce_Time.h
  11. +4
    -3
      src/events/juce_Timer.cpp
  12. +7
    -5
      src/gui/components/menus/juce_PopupMenu.cpp
  13. +7
    -0
      src/memory/juce_Memory.h
  14. +1
    -1
      src/native/android/juce_android_SystemStats.cpp
  15. +1
    -1
      src/native/linux/juce_linux_SystemStats.cpp
  16. +0
    -2
      src/native/mac/juce_mac_MiscUtilities.mm
  17. +8
    -3
      src/native/mac/juce_mac_SystemStats.mm
  18. +3
    -3
      src/text/juce_CharacterFunctions.h
  19. +8
    -2
      src/text/juce_Identifier.cpp
  20. +7
    -0
      src/text/juce_Identifier.h
  21. +1
    -1
      src/text/juce_String.cpp

+ 99
- 92
juce_amalgamated.cpp View File

@@ -646,6 +646,10 @@
#include <dwrite.h>
#endif

#ifndef WM_APPCOMMAND
#define WM_APPCOMMAND 0x0319
#endif

/** A simple COM smart pointer.
Avoids having to include ATL just to get one of these.
*/
@@ -1716,20 +1720,6 @@ const String SystemStats::getJUCEVersion()
static JuceVersionPrinter juceVersionPrinter;
#endif

#ifdef JUCE_DLL
void* juce_Malloc (int size) { return malloc (size); }
void* juce_Calloc (int size) { return calloc (1, size); }
void* juce_Realloc (void* block, int size) { return realloc (block, size); }
void juce_Free (void* block) { free (block); }

#if JUCE_MSVC && JUCE_CHECK_MEMORY_LEAKS
void* juce_DebugMalloc (int size, const char* file, int line) { return _malloc_dbg (size, _NORMAL_BLOCK, file, line); }
void* juce_DebugCalloc (int size, const char* file, int line) { return _calloc_dbg (1, size, _NORMAL_BLOCK, file, line); }
void* juce_DebugRealloc (void* block, int size, const char* file, int line) { return _realloc_dbg (block, size, _NORMAL_BLOCK, file, line); }
void juce_DebugFree (void* block) { _free_dbg (block, _NORMAL_BLOCK); }
#endif
#endif

END_JUCE_NAMESPACE

/*** End of inlined file: juce_SystemStats.cpp ***/
@@ -2032,7 +2022,9 @@ uint32 Time::getMillisecondCounter() noexcept

uint32 Time::getApproximateMillisecondCounter() noexcept
{
jassert (TimeHelpers::lastMSCounterValue != 0);
if (TimeHelpers::lastMSCounterValue == 0)
getMillisecondCounter();

return TimeHelpers::lastMSCounterValue;
}

@@ -4164,7 +4156,7 @@ Identifier::Identifier (const String& name_)
{
/* An Identifier string must be suitable for use as a script variable or XML
attribute, so it can only contain this limited set of characters.. */
jassert (name_.containsOnly ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_") && name_.isNotEmpty());
jassert (isValidIdentifier (name_));
}

Identifier::Identifier (const char* const name_)
@@ -4172,13 +4164,19 @@ Identifier::Identifier (const char* const name_)
{
/* An Identifier string must be suitable for use as a script variable or XML
attribute, so it can only contain this limited set of characters.. */
jassert (toString().containsOnly ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_") && toString().isNotEmpty());
jassert (isValidIdentifier (toString()));
}

Identifier::~Identifier()
{
}

bool Identifier::isValidIdentifier (const String& possibleIdentifier) noexcept
{
return possibleIdentifier.isNotEmpty()
&& possibleIdentifier.containsOnly ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_");
}

END_JUCE_NAMESPACE

/*** End of inlined file: juce_Identifier.cpp ***/
@@ -4740,7 +4738,7 @@ const var NamedValueSet::getWithDefault (const Identifier& name, const var& defa
return v != nullptr ? *v : defaultReturnValue;
}

var* NamedValueSet::getVarPointer (const Identifier& name) const
var* NamedValueSet::getVarPointer (const Identifier& name) const noexcept
{
for (NamedValue* i = values; i != nullptr; i = i->nextListItem)
if (i->name == name)
@@ -13550,7 +13548,7 @@ struct StringCopier
jassert (maxBufferSizeBytes >= 0); // keep this value positive, or no characters will be copied!

if (buffer == nullptr)
return (int) CharPointerType_Dest::getBytesRequiredFor (source);
return (int) (CharPointerType_Dest::getBytesRequiredFor (source) + sizeof (typename CharPointerType_Dest::CharType));

return CharPointerType_Dest (buffer).writeWithDestByteLimit (source, maxBufferSizeBytes);
}
@@ -24596,7 +24594,7 @@ void AudioTransportSource::setSource (PositionableAudioSource* const newSource,

if (readAheadBufferSize_ > 0)
newPositionableSource = newBufferingSource
= new BufferingAudioSource (newPositionableSource, false, readAheadBufferSize_);
= new BufferingAudioSource (newPositionableSource, false, readAheadBufferSize_, maxNumChannels);

newPositionableSource->setNextReadPosition (0);

@@ -24897,11 +24895,13 @@ juce_ImplementSingleton (SharedBufferingAudioSourceThread)

BufferingAudioSource::BufferingAudioSource (PositionableAudioSource* source_,
const bool deleteSourceWhenDeleted_,
int numberOfSamplesToBuffer_)
const int numberOfSamplesToBuffer_,
const int numberOfChannels_)
: source (source_),
deleteSourceWhenDeleted (deleteSourceWhenDeleted_),
numberOfSamplesToBuffer (jmax (1024, numberOfSamplesToBuffer_)),
buffer (2, 0),
numberOfChannels (numberOfChannels_),
buffer (numberOfChannels_, 0),
bufferValidStart (0),
bufferValidEnd (0),
nextPlayPos (0),
@@ -24930,7 +24930,7 @@ void BufferingAudioSource::prepareToPlay (int samplesPerBlockExpected, double sa

sampleRate = sampleRate_;

buffer.setSize (2, jmax (samplesPerBlockExpected * 2, numberOfSamplesToBuffer));
buffer.setSize (numberOfChannels, jmax (samplesPerBlockExpected * 2, numberOfSamplesToBuffer));
buffer.clear();

bufferValidStart = 0;
@@ -24953,7 +24953,7 @@ void BufferingAudioSource::releaseResources()
if (thread != nullptr)
thread->removeSource (this);

buffer.setSize (2, 0);
buffer.setSize (numberOfChannels, 0);
source->releaseResources();
}

@@ -24980,7 +24980,7 @@ void BufferingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info

if (validStart < validEnd)
{
for (int chan = jmin (2, info.buffer->getNumChannels()); --chan >= 0;)
for (int chan = jmin (numberOfChannels, info.buffer->getNumChannels()); --chan >= 0;)
{
const int startBufferIndex = (validStart + nextPlayPos) % buffer.getNumSamples();
const int endBufferIndex = (validEnd + nextPlayPos) % buffer.getNumSamples();
@@ -40070,13 +40070,14 @@ public:
{
const uint32 now = Time::getMillisecondCounter();

if (now <= lastTime)
if (now == lastTime)
{
wait (2);
wait (1);
continue;
}

const int elapsed = now - lastTime;
const int elapsed = now >= lastTime ? (now - lastTime)
: (std::numeric_limits<uint32>::max() - (lastTime - now));
lastTime = now;

const int timeUntilFirstTimer = getTimeUntilFirstTimer (elapsed);
@@ -70513,20 +70514,22 @@ public:
{
if (isVisible())
{
WeakReference<Component> deletionChecker (this);

activeSubMenu = nullptr;
currentChild = nullptr;

exitModalState (item != nullptr ? item->itemId : 0);

if (makeInvisible)
setVisible (false);

if (item != nullptr
&& item->commandManager != nullptr
&& item->itemId != 0)
{
*managerOfChosenCommand = item->commandManager;
}

exitModalState (item != nullptr ? item->itemId : 0);

if (makeInvisible && (deletionChecker != nullptr))
setVisible (false);
}
}

@@ -79046,9 +79049,7 @@ void ComponentPeer::addMaskedRegion (int x, int y, int w, int h)

const StringArray ComponentPeer::getAvailableRenderingEngines()
{
StringArray s;
s.add ("Software Renderer");
return s;
return StringArray ("Software Renderer");
}

int ComponentPeer::getCurrentRenderingEngine() const
@@ -79701,12 +79702,12 @@ void ResizableWindow::resized()
{
if (resizableBorder != nullptr)
{
#if JUCE_WINDOWS || JUCE_LINUX
#if JUCE_WINDOWS || JUCE_LINUX
// hide the resizable border if the OS already provides one..
resizableBorder->setVisible (! (isFullScreen() || isUsingNativeTitleBar()));
#else
#else
resizableBorder->setVisible (! isFullScreen());
#endif
#endif

resizableBorder->setBorderThickness (getBorderThickness());
resizableBorder->setSize (getWidth(), getHeight());
@@ -79715,12 +79716,12 @@ void ResizableWindow::resized()

if (resizableCorner != nullptr)
{
#if JUCE_MAC
#if JUCE_MAC
// hide the resizable border if the OS already provides one..
resizableCorner->setVisible (! (isFullScreen() || isUsingNativeTitleBar()));
#else
#else
resizableCorner->setVisible (! isFullScreen());
#endif
#endif

const int resizerSize = 18;
resizableCorner->setBounds (getWidth() - resizerSize,
@@ -79733,9 +79734,9 @@ void ResizableWindow::resized()

updateLastPos();

#if JUCE_DEBUG
#if JUCE_DEBUG
hasBeenResized = true;
#endif
#endif
}

void ResizableWindow::childBoundsChanged (Component* child)
@@ -79862,7 +79863,7 @@ void ResizableWindow::paint (Graphics& g)
getBorderThickness(), *this);
}

#if JUCE_DEBUG
#if JUCE_DEBUG
/* If this fails, then you've probably written a subclass with a resized()
callback but forgotten to make it call its parent class's resized() method.

@@ -79875,7 +79876,7 @@ void ResizableWindow::paint (Graphics& g)
layout.
*/
jassert (hasBeenResized || (getWidth() == 0 && getHeight() == 0));
#endif
#endif
}

void ResizableWindow::lookAndFeelChanged()
@@ -243769,6 +243770,11 @@ void Logger::outputDebugString (const String& text)
OutputDebugString ((text + "\n").toWideCharPointer());
}

#ifdef JUCE_DLL
JUCE_API void* juceDLL_malloc (size_t sz) { return ::malloc (sz); }
JUCE_API void juceDLL_free (void* block) { ::free (block); }
#endif

#if JUCE_USE_INTRINSICS || JUCE_64BIT

// CPU info functions using intrinsics...
@@ -244191,10 +244197,10 @@ void JUCE_API juce_threadEntryPoint (void*);

static unsigned int __stdcall threadEntryProc (void* userData)
{
#if ! JUCE_ONLY_BUILD_CORE_LIBRARY
#if ! JUCE_ONLY_BUILD_CORE_LIBRARY
AttachThreadInput (GetWindowThreadProcessId (juce_messageWindowHandle, 0),
GetCurrentThreadId(), TRUE);
#endif
#endif

juce_threadEntryPoint (userData);

@@ -244220,16 +244226,16 @@ void Thread::killThread()
{
if (threadHandle_ != 0)
{
#if JUCE_DEBUG
#if JUCE_DEBUG
OutputDebugString (_T("** Warning - Forced thread termination **\n"));
#endif
#endif
TerminateThread (threadHandle_, 0);
}
}

void Thread::setCurrentThreadName (const String& name)
{
#if JUCE_DEBUG && JUCE_MSVC
#if JUCE_DEBUG && JUCE_MSVC
struct
{
DWORD dwType;
@@ -244249,9 +244255,9 @@ void Thread::setCurrentThreadName (const String& name)
}
__except (EXCEPTION_CONTINUE_EXECUTION)
{}
#else
#else
(void) name;
#endif
#endif
}

Thread::ThreadID Thread::getCurrentThreadId()
@@ -244397,7 +244403,7 @@ void PlatformUtilities::freeDynamicLibrary (void* h)
{
JUCE_TRY
{
if (h != 0)
if (h != nullptr)
FreeLibrary ((HMODULE) h);
}
JUCE_CATCH_ALL
@@ -244405,7 +244411,7 @@ void PlatformUtilities::freeDynamicLibrary (void* h)

void* PlatformUtilities::getProcedureEntryPoint (void* h, const String& name)
{
return (h != 0) ? (void*) GetProcAddress ((HMODULE) h, name.toUTF8()) : nullptr; // (void* cast is required for mingw)
return (h != nullptr) ? (void*) GetProcAddress ((HMODULE) h, name.toUTF8()) : nullptr; // (void* cast is required for mingw)
}

class InterProcessLock::Pimpl
@@ -245366,11 +245372,11 @@ void NamedPipe::cancelPendingReads()
#if JUCE_INCLUDED_FILE

#ifndef INTERNET_FLAG_NEED_FILE
#define INTERNET_FLAG_NEED_FILE 0x00000010
#define INTERNET_FLAG_NEED_FILE 0x00000010
#endif

#ifndef INTERNET_OPTION_DISABLE_AUTODIAL
#define INTERNET_OPTION_DISABLE_AUTODIAL 70
#define INTERNET_OPTION_DISABLE_AUTODIAL 70
#endif

#ifndef WORKAROUND_TIMEOUT_BUG
@@ -246040,10 +246046,6 @@ HWND juce_messageWindowHandle = 0;

extern long improbableWindowNumber; // defined in windowing.cpp

#ifndef WM_APPCOMMAND
#define WM_APPCOMMAND 0x0319
#endif

static LRESULT CALLBACK juce_MessageWndProc (HWND h,
const UINT message,
const WPARAM wParam,
@@ -247570,7 +247572,6 @@ private:
#define APPCOMMAND_MEDIA_PREVIOUSTRACK 12
#define APPCOMMAND_MEDIA_STOP 13
#define APPCOMMAND_MEDIA_PLAY_PAUSE 14
#define WM_APPCOMMAND 0x0319
#endif

extern void juce_repeatLastProcessPriority(); // in juce_win32_Threads.cpp
@@ -252279,29 +252280,32 @@ typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int* piAt
typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval);
typedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC) (void);

#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
#define WGL_DRAW_TO_WINDOW_ARB 0x2001
#define WGL_ACCELERATION_ARB 0x2003
#define WGL_SWAP_METHOD_ARB 0x2007
#define WGL_SUPPORT_OPENGL_ARB 0x2010
#define WGL_PIXEL_TYPE_ARB 0x2013
#define WGL_DOUBLE_BUFFER_ARB 0x2011
#define WGL_COLOR_BITS_ARB 0x2014
#define WGL_RED_BITS_ARB 0x2015
#define WGL_GREEN_BITS_ARB 0x2017
#define WGL_BLUE_BITS_ARB 0x2019
#define WGL_ALPHA_BITS_ARB 0x201B
#define WGL_DEPTH_BITS_ARB 0x2022
#define WGL_STENCIL_BITS_ARB 0x2023
#define WGL_FULL_ACCELERATION_ARB 0x2027
#define WGL_ACCUM_RED_BITS_ARB 0x201E
#define WGL_ACCUM_GREEN_BITS_ARB 0x201F
#define WGL_ACCUM_BLUE_BITS_ARB 0x2020
#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
#define WGL_STEREO_ARB 0x2012
#define WGL_SAMPLE_BUFFERS_ARB 0x2041
#define WGL_SAMPLES_ARB 0x2042
#define WGL_TYPE_RGBA_ARB 0x202B
enum
{
WGL_NUMBER_PIXEL_FORMATS_ARB = 0x2000,
WGL_DRAW_TO_WINDOW_ARB = 0x2001,
WGL_ACCELERATION_ARB = 0x2003,
WGL_SWAP_METHOD_ARB = 0x2007,
WGL_SUPPORT_OPENGL_ARB = 0x2010,
WGL_PIXEL_TYPE_ARB = 0x2013,
WGL_DOUBLE_BUFFER_ARB = 0x2011,
WGL_COLOR_BITS_ARB = 0x2014,
WGL_RED_BITS_ARB = 0x2015,
WGL_GREEN_BITS_ARB = 0x2017,
WGL_BLUE_BITS_ARB = 0x2019,
WGL_ALPHA_BITS_ARB = 0x201B,
WGL_DEPTH_BITS_ARB = 0x2022,
WGL_STENCIL_BITS_ARB = 0x2023,
WGL_FULL_ACCELERATION_ARB = 0x2027,
WGL_ACCUM_RED_BITS_ARB = 0x201E,
WGL_ACCUM_GREEN_BITS_ARB = 0x201F,
WGL_ACCUM_BLUE_BITS_ARB = 0x2020,
WGL_ACCUM_ALPHA_BITS_ARB = 0x2021,
WGL_STEREO_ARB = 0x2012,
WGL_SAMPLE_BUFFERS_ARB = 0x2041,
WGL_SAMPLES_ARB = 0x2042,
WGL_TYPE_RGBA_ARB = 0x202B
};

static void getWglExtensions (HDC dc, StringArray& result) noexcept
{
@@ -261987,7 +261991,7 @@ int64 Time::getHighResolutionTicks() noexcept
timespec t;
clock_gettime (CLOCK_MONOTONIC, &t);

return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / (int64) 1000);
return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000);
}

int64 Time::getHighResolutionTicksPerSecond() noexcept
@@ -269340,13 +269344,15 @@ public:
{
mach_timebase_info_data_t timebase;
(void) mach_timebase_info (&timebase);
highResTimerFrequency = (int64) (1.0e9 * timebase.denom / timebase.numer);
highResTimerToMillisecRatio = timebase.numer / (1.0e6 * timebase.denom);
highResTimerFrequency = (timebase.denom * (int64) 1000000000) / timebase.numer;
numerator = timebase.numer;
denominator = timebase.denom * (int64) 1000000;
highResTimerToMillisecRatio = numerator / (double) denominator;
}

inline uint32 millisecondsSinceStartup() const noexcept
{
return (uint32) (mach_absolute_time() * highResTimerToMillisecRatio);
return (uint32) ((mach_absolute_time() * numerator) / denominator);
}

inline double getMillisecondCounterHiRes() const noexcept
@@ -269355,6 +269361,9 @@ public:
}

int64 highResTimerFrequency;

private:
int64 numerator, denominator;
double highResTimerToMillisecRatio;
};

@@ -271813,8 +271822,6 @@ public:
timerCallback();
}

~ScreenSaverDefeater() {}

void timerCallback()
{
if (Process::isForegroundProcess())
@@ -286929,7 +286936,7 @@ int64 Time::getHighResolutionTicks() noexcept
timespec t;
clock_gettime (CLOCK_MONOTONIC, &t);

return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / (int64) 1000);
return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000);
}

int64 Time::getHighResolutionTicksPerSecond() noexcept


+ 79
- 128
juce_amalgamated.h View File

@@ -73,7 +73,7 @@ namespace JuceDummyNamespace {}
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 53
#define JUCE_BUILDNUMBER 85
#define JUCE_BUILDNUMBER 86

/** Current Juce version number.

@@ -895,102 +895,6 @@ extern JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger();
#ifndef __JUCE_MEMORY_JUCEHEADER__
#define __JUCE_MEMORY_JUCEHEADER__

/*
This file defines the various juce_malloc(), juce_free() macros that can be used in
preference to the standard calls.

None of this stuff is actually used in the library itself, and will probably be
deprecated at some point in the future, to force everyone to use HeapBlock and other
safer allocation methods.
*/

#if JUCE_MSVC && JUCE_CHECK_MEMORY_LEAKS && ! DOXYGEN
#ifndef JUCE_DLL

// Win32 debug non-DLL versions..

#define juce_malloc(numBytes) _malloc_dbg (numBytes, _NORMAL_BLOCK, __FILE__, __LINE__)
#define juce_calloc(numBytes) _calloc_dbg (1, numBytes, _NORMAL_BLOCK, __FILE__, __LINE__)
#define juce_realloc(location, numBytes) _realloc_dbg (location, numBytes, _NORMAL_BLOCK, __FILE__, __LINE__)
#define juce_free(location) _free_dbg (location, _NORMAL_BLOCK)

#else

// Win32 debug DLL versions..

// For the DLL, we'll define some functions in the DLL that will be used for allocation - that
// way all juce calls in the DLL and in the host API will all use the same allocator.
extern JUCE_API void* juce_DebugMalloc (int size, const char* file, int line);
extern JUCE_API void* juce_DebugCalloc (int size, const char* file, int line);
extern JUCE_API void* juce_DebugRealloc (void* block, int size, const char* file, int line);
extern JUCE_API void juce_DebugFree (void* block);

#define juce_malloc(numBytes) JUCE_NAMESPACE::juce_DebugMalloc (numBytes, __FILE__, __LINE__)
#define juce_calloc(numBytes) JUCE_NAMESPACE::juce_DebugCalloc (numBytes, __FILE__, __LINE__)
#define juce_realloc(location, numBytes) JUCE_NAMESPACE::juce_DebugRealloc (location, numBytes, __FILE__, __LINE__)
#define juce_free(location) JUCE_NAMESPACE::juce_DebugFree (location)

#define JUCE_LEAK_DETECTOR(OwnerClass) public:\
static void* operator new (size_t sz) { void* const p = juce_malloc ((int) sz); return (p != 0) ? p : ::operator new (sz); } \
static void* operator new (size_t, void* p) { return p; } \
static void operator delete (void* p) { juce_free (p); } \
static void operator delete (void*, void*) {}
#endif

#elif defined (JUCE_DLL) && ! DOXYGEN

// Win32 DLL (release) versions..

// For the DLL, we'll define some functions in the DLL that will be used for allocation - that
// way all juce calls in the DLL and in the host API will all use the same allocator.
extern JUCE_API void* juce_Malloc (int size);
extern JUCE_API void* juce_Calloc (int size);
extern JUCE_API void* juce_Realloc (void* block, int size);
extern JUCE_API void juce_Free (void* block);

#define juce_malloc(numBytes) JUCE_NAMESPACE::juce_Malloc (numBytes)
#define juce_calloc(numBytes) JUCE_NAMESPACE::juce_Calloc (numBytes)
#define juce_realloc(location, numBytes) JUCE_NAMESPACE::juce_Realloc (location, numBytes)
#define juce_free(location) JUCE_NAMESPACE::juce_Free (location)

#define JUCE_LEAK_DETECTOR(OwnerClass) public:\
static void* operator new (size_t sz) { void* const p = juce_malloc ((int) sz); return (p != 0) ? p : ::operator new (sz); } \
static void* operator new (size_t, void* p) { return p; } \
static void operator delete (void* p) { juce_free (p); } \
static void operator delete (void*, void*) {}
#else

// Mac, Linux and Win32 (release) versions..

/** This can be used instead of calling malloc directly.
Only use direct memory allocation if there's really no way to use a HeapBlock object instead!
*/
#define juce_malloc(numBytes) malloc (numBytes)

/** This can be used instead of calling calloc directly.
Only use direct memory allocation if there's really no way to use a HeapBlock object instead!
*/
#define juce_calloc(numBytes) calloc (1, numBytes)

/** This can be used instead of calling realloc directly.
Only use direct memory allocation if there's really no way to use a HeapBlock object instead!
*/
#define juce_realloc(location, numBytes) realloc (location, numBytes)

/** This can be used instead of calling free directly.
Only use direct memory allocation if there's really no way to use a HeapBlock object instead!
*/
#define juce_free(location) free (location)

#endif

/** (Deprecated) This was a win32-specific way of checking for object leaks - now please
use the JUCE_LEAK_DETECTOR instead.
*/
#ifndef juce_UseDebuggingNewOperator
#define juce_UseDebuggingNewOperator
#endif

#if JUCE_MSVC || DOXYGEN
/** This is a compiler-independent way of declaring a variable as being thread-local.

@@ -1031,6 +935,35 @@ inline void deleteAndZero (Type& pointer) { delete pointer; pointer = nullp
template <typename Type>
inline Type* addBytesToPointer (Type* pointer, int 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); }

/* In a win32 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) && ! 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_NAMESPACE::juceDLL_malloc ((int) sz); } \
static void* operator new (size_t, void* p) { return p; } \
static void operator delete (void* p) { JUCE_NAMESPACE::juceDLL_free (p); } \
static void operator delete (void*, void*) {}
#endif

/** (Deprecated) This was a win32-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_JUCEHEADER__

/*** End of inlined file: juce_Memory.h ***/
@@ -1912,7 +1845,7 @@ public:
template <typename DestCharPointerType, typename SrcCharPointerType>
static int copyWithDestByteLimit (DestCharPointerType& dest, SrcCharPointerType src, int maxBytes) noexcept
{
int numBytesDone = 0;
typename DestCharPointerType::CharType const* const startAddress = dest.getAddress();
maxBytes -= sizeof (typename DestCharPointerType::CharType); // (allow for a terminating null)

for (;;)
@@ -1924,12 +1857,12 @@ public:
if (c == 0 || maxBytes < 0)
break;

numBytesDone += bytesNeeded;
dest.write (c);
}

dest.writeNull();
return numBytesDone;

return getAddressDifference (dest.getAddress(), startAddress);
}

template <typename DestCharPointerType, typename SrcCharPointerType>
@@ -8008,6 +7941,12 @@ public:
/** Returns this identifier's raw string pointer. */
operator const String::CharPointerType() const noexcept { return name; }

/** Checks a given string for characters that might not be valid in an Identifier.
Since Identifiers are used as a script variables and XML attributes, they should only contain
alphanumeric characters and underscores.
*/
static bool isValidIdentifier (const String& possibleIdentifier) noexcept;

private:

String::CharPointerType name;
@@ -8053,7 +7992,7 @@ public:
operator const String() const { return getDefault(); }
};

/** An predefined object representing a new-line, which can be written to a string or stream.
/** A predefined object representing a new-line, which can be written to a string or stream.

To write a new-line to a stream, you can use the predefined 'newLine' variable like this:
@code
@@ -9317,7 +9256,7 @@ public:
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;
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);
@@ -10791,7 +10730,7 @@ public:
{
const ScopedLockType sl (getLock());

for (const HashEntry* entry = slots [generateHashFor (keyToLookFor)]; entry != nullptr; entry = entry->nextEntry)
for (const HashEntry* entry = slots.getUnchecked (generateHashFor (keyToLookFor)); entry != nullptr; entry = entry->nextEntry)
if (entry->key == keyToLookFor)
return entry->value;

@@ -10803,7 +10742,7 @@ public:
{
const ScopedLockType sl (getLock());

for (const HashEntry* entry = slots [generateHashFor (keyToLookFor)]; entry != nullptr; entry = entry->nextEntry)
for (const HashEntry* entry = slots.getUnchecked (generateHashFor (keyToLookFor)); entry != nullptr; entry = entry->nextEntry)
if (entry->key == keyToLookFor)
return true;

@@ -10832,25 +10771,22 @@ public:
const ScopedLockType sl (getLock());
const int hashIndex = generateHashFor (newKey);

if (isPositiveAndBelow (hashIndex, getNumSlots()))
{
HashEntry* const firstEntry = slots.getUnchecked (hashIndex);
HashEntry* const firstEntry = slots.getUnchecked (hashIndex);

for (HashEntry* entry = firstEntry; entry != nullptr; entry = entry->nextEntry)
for (HashEntry* entry = firstEntry; entry != nullptr; entry = entry->nextEntry)
{
if (entry->key == newKey)
{
if (entry->key == newKey)
{
entry->value = newValue;
return;
}
entry->value = newValue;
return;
}
}

slots.set (hashIndex, new HashEntry (newKey, newValue, firstEntry));
++totalNumItems;
slots.set (hashIndex, new HashEntry (newKey, newValue, firstEntry));
++totalNumItems;

if (totalNumItems > (getNumSlots() * 3) / 2)
remapTable (getNumSlots() * 2);
}
if (totalNumItems > (getNumSlots() * 3) / 2)
remapTable (getNumSlots() * 2);
}

/** Removes an item with the given key. */
@@ -10858,7 +10794,7 @@ public:
{
const ScopedLockType sl (getLock());
const int hashIndex = generateHashFor (keyToRemove);
HashEntry* entry = slots [hashIndex];
HashEntry* entry = slots.getUnchecked (hashIndex);
HashEntry* previous = nullptr;

while (entry != nullptr)
@@ -11953,6 +11889,10 @@ public:
system clock. It should be accurate to within a few millisecs, depending on platform,
hardware, etc.

Being a 32-bit return value, it will of course wrap back to 0 after 2^32 seconds of
uptime, so be careful to take that into account. If you need a 64-bit time, you can
use currentTimeMillis() instead.

@see getApproximateMillisecondCounter
*/
static uint32 getMillisecondCounter() noexcept;
@@ -38449,10 +38389,12 @@ public:
@param deleteSourceWhenDeleted if true, then the input source object will
be deleted when this object is deleted
@param numberOfSamplesToBuffer the size of buffer to use for reading ahead
@param numberOfChannels the number of channels that will be played
*/
BufferingAudioSource (PositionableAudioSource* source,
bool deleteSourceWhenDeleted,
int numberOfSamplesToBuffer);
int numberOfSamplesToBuffer,
int numberOfChannels = 2);

/** Destructor.

@@ -38486,7 +38428,7 @@ private:

PositionableAudioSource* source;
bool deleteSourceWhenDeleted;
int numberOfSamplesToBuffer;
int numberOfSamplesToBuffer, numberOfChannels;
AudioSampleBuffer buffer;
CriticalSection bufferStartPosLock;
int64 volatile bufferValidStart, bufferValidEnd, nextPlayPos;
@@ -43908,6 +43850,9 @@ public:

This stores the current device, its samplerate, block size, etc, and
can be restored later with initialise().

Note that this can return a null pointer if no settings have been explicitly changed
(i.e. if the device manager has just been left in its default state).
*/
XmlElement* createStateXml() const;

@@ -47730,7 +47675,7 @@ private:

ReferenceCountedArray <Node> nodes;
OwnedArray <Connection> connections;
int lastNodeId;
uint32 lastNodeId;
AudioSampleBuffer renderingBuffers;
OwnedArray <MidiBuffer> midiBuffers;

@@ -57819,22 +57764,24 @@ private:

@code
{
WildcardFileFilter wildcardFilter ("*.foo", "Foo files");
WildcardFileFilter wildcardFilter ("*.foo", String::empty, "Foo files");

FileBrowserComponent browser (FileBrowserComponent::loadFileMode,
FileBrowserComponent browser (FileBrowserComponent::canSelectFiles,
File::nonexistent,
&wildcardFilter,
0);
nullptr);

FileChooserDialogBox dialogBox ("Open some kind of file",
"Please choose some kind of file that you want to open...",
browser,
getLookAndFeel().alertWindowBackground);
false,
Colours::lightgrey);

if (dialogBox.show())
{
File selectedFile = browser.getCurrentFile();
...
File selectedFile = browser.getSelectedFile (0);

...etc..
}
}
@endcode
@@ -58447,6 +58394,10 @@ public:
patterns, e.g. "*.wav;*.aiff" would look for files ending in either .wav
or .aiff.

Passing an empty string as a pattern will fail to match anything, so by leaving
either the file or directory pattern parameter empty means you can control
whether files or directories are found.

The description is a name to show the user in a list of possible patterns, so
for the wav/aiff example, your description might be "audio files".
*/


+ 1
- 1
src/audio/audio_sources/juce_AudioTransportSource.cpp View File

@@ -89,7 +89,7 @@ void AudioTransportSource::setSource (PositionableAudioSource* const newSource,
if (readAheadBufferSize_ > 0)
newPositionableSource = newBufferingSource
= new BufferingAudioSource (newPositionableSource, false, readAheadBufferSize_);
= new BufferingAudioSource (newPositionableSource, false, readAheadBufferSize_, maxNumChannels);
newPositionableSource->setNextReadPosition (0);


+ 7
- 5
src/audio/audio_sources/juce_BufferingAudioSource.cpp View File

@@ -121,11 +121,13 @@ juce_ImplementSingleton (SharedBufferingAudioSourceThread)
//==============================================================================
BufferingAudioSource::BufferingAudioSource (PositionableAudioSource* source_,
const bool deleteSourceWhenDeleted_,
int numberOfSamplesToBuffer_)
const int numberOfSamplesToBuffer_,
const int numberOfChannels_)
: source (source_),
deleteSourceWhenDeleted (deleteSourceWhenDeleted_),
numberOfSamplesToBuffer (jmax (1024, numberOfSamplesToBuffer_)),
buffer (2, 0),
numberOfChannels (numberOfChannels_),
buffer (numberOfChannels_, 0),
bufferValidStart (0),
bufferValidEnd (0),
nextPlayPos (0),
@@ -155,7 +157,7 @@ void BufferingAudioSource::prepareToPlay (int samplesPerBlockExpected, double sa
sampleRate = sampleRate_;
buffer.setSize (2, jmax (samplesPerBlockExpected * 2, numberOfSamplesToBuffer));
buffer.setSize (numberOfChannels, jmax (samplesPerBlockExpected * 2, numberOfSamplesToBuffer));
buffer.clear();
bufferValidStart = 0;
@@ -178,7 +180,7 @@ void BufferingAudioSource::releaseResources()
if (thread != nullptr)
thread->removeSource (this);
buffer.setSize (2, 0);
buffer.setSize (numberOfChannels, 0);
source->releaseResources();
}
@@ -205,7 +207,7 @@ void BufferingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info
if (validStart < validEnd)
{
for (int chan = jmin (2, info.buffer->getNumChannels()); --chan >= 0;)
for (int chan = jmin (numberOfChannels, info.buffer->getNumChannels()); --chan >= 0;)
{
const int startBufferIndex = (validStart + nextPlayPos) % buffer.getNumSamples();
const int endBufferIndex = (validEnd + nextPlayPos) % buffer.getNumSamples();


+ 4
- 2
src/audio/audio_sources/juce_BufferingAudioSource.h View File

@@ -51,10 +51,12 @@ public:
@param deleteSourceWhenDeleted if true, then the input source object will
be deleted when this object is deleted
@param numberOfSamplesToBuffer the size of buffer to use for reading ahead
@param numberOfChannels the number of channels that will be played
*/
BufferingAudioSource (PositionableAudioSource* source,
bool deleteSourceWhenDeleted,
int numberOfSamplesToBuffer);
int numberOfSamplesToBuffer,
int numberOfChannels = 2);
/** Destructor.
@@ -90,7 +92,7 @@ private:
//==============================================================================
PositionableAudioSource* source;
bool deleteSourceWhenDeleted;
int numberOfSamplesToBuffer;
int numberOfSamplesToBuffer, numberOfChannels;
AudioSampleBuffer buffer;
CriticalSection bufferStartPosLock;
int64 volatile bufferValidStart, bufferValidEnd, nextPlayPos;


+ 3
- 0
src/audio/devices/juce_AudioDeviceManager.h View File

@@ -201,6 +201,9 @@ public:
This stores the current device, its samplerate, block size, etc, and
can be restored later with initialise().
Note that this can return a null pointer if no settings have been explicitly changed
(i.e. if the device manager has just been left in its default state).
*/
XmlElement* createStateXml() const;


+ 14
- 17
src/containers/juce_HashMap.h View File

@@ -160,7 +160,7 @@ public:
{
const ScopedLockType sl (getLock());
for (const HashEntry* entry = slots [generateHashFor (keyToLookFor)]; entry != nullptr; entry = entry->nextEntry)
for (const HashEntry* entry = slots.getUnchecked (generateHashFor (keyToLookFor)); entry != nullptr; entry = entry->nextEntry)
if (entry->key == keyToLookFor)
return entry->value;
@@ -173,7 +173,7 @@ public:
{
const ScopedLockType sl (getLock());
for (const HashEntry* entry = slots [generateHashFor (keyToLookFor)]; entry != nullptr; entry = entry->nextEntry)
for (const HashEntry* entry = slots.getUnchecked (generateHashFor (keyToLookFor)); entry != nullptr; entry = entry->nextEntry)
if (entry->key == keyToLookFor)
return true;
@@ -203,25 +203,22 @@ public:
const ScopedLockType sl (getLock());
const int hashIndex = generateHashFor (newKey);
if (isPositiveAndBelow (hashIndex, getNumSlots()))
{
HashEntry* const firstEntry = slots.getUnchecked (hashIndex);
HashEntry* const firstEntry = slots.getUnchecked (hashIndex);
for (HashEntry* entry = firstEntry; entry != nullptr; entry = entry->nextEntry)
for (HashEntry* entry = firstEntry; entry != nullptr; entry = entry->nextEntry)
{
if (entry->key == newKey)
{
if (entry->key == newKey)
{
entry->value = newValue;
return;
}
entry->value = newValue;
return;
}
}
slots.set (hashIndex, new HashEntry (newKey, newValue, firstEntry));
++totalNumItems;
slots.set (hashIndex, new HashEntry (newKey, newValue, firstEntry));
++totalNumItems;
if (totalNumItems > (getNumSlots() * 3) / 2)
remapTable (getNumSlots() * 2);
}
if (totalNumItems > (getNumSlots() * 3) / 2)
remapTable (getNumSlots() * 2);
}
/** Removes an item with the given key. */
@@ -229,7 +226,7 @@ public:
{
const ScopedLockType sl (getLock());
const int hashIndex = generateHashFor (keyToRemove);
HashEntry* entry = slots [hashIndex];
HashEntry* entry = slots.getUnchecked (hashIndex);
HashEntry* previous = nullptr;
while (entry != nullptr)


+ 1
- 1
src/core/juce_StandardHeader.h View File

@@ -33,7 +33,7 @@
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 53
#define JUCE_BUILDNUMBER 85
#define JUCE_BUILDNUMBER 86
/** Current Juce version number.


+ 3
- 1
src/core/juce_Time.cpp View File

@@ -276,7 +276,9 @@ uint32 Time::getMillisecondCounter() noexcept
uint32 Time::getApproximateMillisecondCounter() noexcept
{
jassert (TimeHelpers::lastMSCounterValue != 0);
if (TimeHelpers::lastMSCounterValue == 0)
getMillisecondCounter();
return TimeHelpers::lastMSCounterValue;
}


+ 4
- 0
src/core/juce_Time.h View File

@@ -298,6 +298,10 @@ public:
system clock. It should be accurate to within a few millisecs, depending on platform,
hardware, etc.
Being a 32-bit return value, it will of course wrap back to 0 after 2^32 seconds of
uptime, so be careful to take that into account. If you need a 64-bit time, you can
use currentTimeMillis() instead.
@see getApproximateMillisecondCounter
*/
static uint32 getMillisecondCounter() noexcept;


+ 4
- 3
src/events/juce_Timer.cpp View File

@@ -72,13 +72,14 @@ public:
{
const uint32 now = Time::getMillisecondCounter();
if (now <= lastTime)
if (now == lastTime)
{
wait (2);
wait (1);
continue;
}
const int elapsed = now - lastTime;
const int elapsed = now >= lastTime ? (now - lastTime)
: (std::numeric_limits<uint32>::max() - (lastTime - now));
lastTime = now;
const int timeUntilFirstTimer = getTimeUntilFirstTimer (elapsed);


+ 7
- 5
src/gui/components/menus/juce_PopupMenu.cpp View File

@@ -373,20 +373,22 @@ public:
{
if (isVisible())
{
WeakReference<Component> deletionChecker (this);
activeSubMenu = nullptr;
currentChild = nullptr;
exitModalState (item != nullptr ? item->itemId : 0);
if (makeInvisible)
setVisible (false);
if (item != nullptr
&& item->commandManager != nullptr
&& item->itemId != 0)
{
*managerOfChosenCommand = item->commandManager;
}
exitModalState (item != nullptr ? item->itemId : 0);
if (makeInvisible && (deletionChecker != nullptr))
setVisible (false);
}
}


+ 7
- 0
src/memory/juce_Memory.h View File

@@ -69,6 +69,13 @@ inline void deleteAndZero (Type& pointer) { delete poi
template <typename Type>
inline Type* addBytesToPointer (Type* pointer, int 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); }
//==============================================================================
/* In a win32 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,


+ 1
- 1
src/native/android/juce_android_SystemStats.cpp View File

@@ -142,7 +142,7 @@ int64 Time::getHighResolutionTicks() noexcept
timespec t;
clock_gettime (CLOCK_MONOTONIC, &t);
return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / (int64) 1000);
return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000);
}
int64 Time::getHighResolutionTicksPerSecond() noexcept


+ 1
- 1
src/native/linux/juce_linux_SystemStats.cpp View File

@@ -155,7 +155,7 @@ int64 Time::getHighResolutionTicks() noexcept
timespec t;
clock_gettime (CLOCK_MONOTONIC, &t);
return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / (int64) 1000);
return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000);
}
int64 Time::getHighResolutionTicksPerSecond() noexcept


+ 0
- 2
src/native/mac/juce_mac_MiscUtilities.mm View File

@@ -274,8 +274,6 @@ public:
timerCallback();
}
~ScreenSaverDefeater() {}
void timerCallback()
{
if (Process::isForegroundProcess())


+ 8
- 3
src/native/mac/juce_mac_SystemStats.mm View File

@@ -190,13 +190,15 @@ public:
{
mach_timebase_info_data_t timebase;
(void) mach_timebase_info (&timebase);
highResTimerFrequency = (int64) (1.0e9 * timebase.denom / timebase.numer);
highResTimerToMillisecRatio = timebase.numer / (1.0e6 * timebase.denom);
highResTimerFrequency = (timebase.denom * (int64) 1000000000) / timebase.numer;
numerator = timebase.numer;
denominator = timebase.denom * (int64) 1000000;
highResTimerToMillisecRatio = numerator / (double) denominator;
}
inline uint32 millisecondsSinceStartup() const noexcept
{
return (uint32) (mach_absolute_time() * highResTimerToMillisecRatio);
return (uint32) ((mach_absolute_time() * numerator) / denominator);
}
inline double getMillisecondCounterHiRes() const noexcept
@@ -205,6 +207,9 @@ public:
}
int64 highResTimerFrequency;
private:
int64 numerator, denominator;
double highResTimerToMillisecRatio;
};


+ 3
- 3
src/text/juce_CharacterFunctions.h View File

@@ -308,7 +308,7 @@ public:
template <typename DestCharPointerType, typename SrcCharPointerType>
static int copyWithDestByteLimit (DestCharPointerType& dest, SrcCharPointerType src, int maxBytes) noexcept
{
int numBytesDone = 0;
typename DestCharPointerType::CharType const* const startAddress = dest.getAddress();
maxBytes -= sizeof (typename DestCharPointerType::CharType); // (allow for a terminating null)
for (;;)
@@ -320,12 +320,12 @@ public:
if (c == 0 || maxBytes < 0)
break;
numBytesDone += bytesNeeded;
dest.write (c);
}
dest.writeNull();
return numBytesDone;
return getAddressDifference (dest.getAddress(), startAddress);
}
template <typename DestCharPointerType, typename SrcCharPointerType>


+ 8
- 2
src/text/juce_Identifier.cpp View File

@@ -58,7 +58,7 @@ Identifier::Identifier (const String& name_)
{
/* An Identifier string must be suitable for use as a script variable or XML
attribute, so it can only contain this limited set of characters.. */
jassert (name_.containsOnly ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_") && name_.isNotEmpty());
jassert (isValidIdentifier (name_));
}
Identifier::Identifier (const char* const name_)
@@ -66,11 +66,17 @@ Identifier::Identifier (const char* const name_)
{
/* An Identifier string must be suitable for use as a script variable or XML
attribute, so it can only contain this limited set of characters.. */
jassert (toString().containsOnly ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_") && toString().isNotEmpty());
jassert (isValidIdentifier (toString()));
}
Identifier::~Identifier()
{
}
bool Identifier::isValidIdentifier (const String& possibleIdentifier) noexcept
{
return possibleIdentifier.isNotEmpty()
&& possibleIdentifier.containsOnly ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_");
}
END_JUCE_NAMESPACE

+ 7
- 0
src/text/juce_Identifier.h View File

@@ -78,6 +78,13 @@ public:
/** Returns this identifier's raw string pointer. */
operator const String::CharPointerType() const noexcept { return name; }
/** Checks a given string for characters that might not be valid in an Identifier.
Since Identifiers are used as a script variables and XML attributes, they should only contain
alphanumeric characters and underscores.
*/
static bool isValidIdentifier (const String& possibleIdentifier) noexcept;
private:
//==============================================================================
String::CharPointerType name;


+ 1
- 1
src/text/juce_String.cpp View File

@@ -2052,7 +2052,7 @@ struct StringCopier
jassert (maxBufferSizeBytes >= 0); // keep this value positive, or no characters will be copied!
if (buffer == nullptr)
return (int) CharPointerType_Dest::getBytesRequiredFor (source);
return (int) (CharPointerType_Dest::getBytesRequiredFor (source) + sizeof (typename CharPointerType_Dest::CharType));
return CharPointerType_Dest (buffer).writeWithDestByteLimit (source, maxBufferSizeBytes);
}


Loading…
Cancel
Save