| @@ -62,9 +62,7 @@ public: | |||
| if (JUCEApplication::getInstance() != 0) | |||
| { | |||
| JUCEApplication::getInstance()->systemRequestedQuit(); | |||
| if (! MessageManager::getInstance()->hasStopMessageBeenSent()) | |||
| return NSTerminateCancel; | |||
| return NSTerminateCancel; | |||
| } | |||
| return NSTerminateNow; | |||
| @@ -1,10 +1,11 @@ | |||
| <?xml version="1.0" encoding="Windows-1252"?> | |||
| <VisualStudioProject | |||
| ProjectType="Visual C++" | |||
| Version="8.00" | |||
| Version="9.00" | |||
| Name="JUCE" | |||
| ProjectGUID="{AE232C11-D91C-4CA1-B24E-8B11A52EFF26}" | |||
| RootNamespace="JUCE" | |||
| TargetFrameworkVersion="131072" | |||
| > | |||
| <Platforms> | |||
| <Platform | |||
| @@ -207,6 +208,8 @@ | |||
| AdditionalOptions="/IMPLIB:".\..\..\..\bin\JUCE_debug.lib"
" | |||
| OutputFile="$(OutDir)\$(ProjectName)_debug.dll" | |||
| IgnoreDefaultLibraryNames="libcmt.lib" | |||
| RandomizedBaseAddress="1" | |||
| DataExecutionPrevention="0" | |||
| /> | |||
| <Tool | |||
| Name="VCALinkTool" | |||
| @@ -228,9 +231,6 @@ | |||
| <Tool | |||
| Name="VCAppVerifierTool" | |||
| /> | |||
| <Tool | |||
| Name="VCWebDeploymentTool" | |||
| /> | |||
| <Tool | |||
| Name="VCPostBuildEventTool" | |||
| /> | |||
| @@ -289,6 +289,8 @@ | |||
| <Tool | |||
| Name="VCLinkerTool" | |||
| IgnoreDefaultLibraryNames="libcmtd.lib" | |||
| RandomizedBaseAddress="1" | |||
| DataExecutionPrevention="0" | |||
| /> | |||
| <Tool | |||
| Name="VCALinkTool" | |||
| @@ -310,9 +312,6 @@ | |||
| <Tool | |||
| Name="VCAppVerifierTool" | |||
| /> | |||
| <Tool | |||
| Name="VCWebDeploymentTool" | |||
| /> | |||
| <Tool | |||
| Name="VCPostBuildEventTool" | |||
| /> | |||
| @@ -39,6 +39,7 @@ | |||
| #define JUCE_PLUGINHOST_VST 1 | |||
| #define JUCE_PLUGINHOST_AU 1 | |||
| #define JUCE_SUPPORT_CARBON 1 | |||
| //#define JUCE_ONLY_BUILD_CORE_LIBRARY 1 | |||
| //#define JUCE_FORCE_DEBUG 1 | |||
| //#define JUCE_LOG_ASSERTIONS 1 | |||
| @@ -2,6 +2,9 @@ | |||
| Microsoft Visual Studio Solution File, Format Version 9.00 | |||
| # Visual Studio 2005 | |||
| Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jucedemo", "jucedemo.vcproj", "{050D65C2-17C4-4EE1-ABCE-BEA9DA83D77A}" | |||
| ProjectSection(ProjectDependencies) = postProject | |||
| {AE232C11-D91C-4CA1-B24E-8B11A52EFF26} = {AE232C11-D91C-4CA1-B24E-8B11A52EFF26} | |||
| EndProjectSection | |||
| EndProject | |||
| Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JUCE", "..\..\..\..\build\win32\vc8\JUCE.vcproj", "{AE232C11-D91C-4CA1-B24E-8B11A52EFF26}" | |||
| EndProject | |||
| @@ -185,6 +185,16 @@ | |||
| #define JUCE_WEB_BROWSER 1 | |||
| #endif | |||
| //============================================================================= | |||
| /** Setting this allows the build to use old Carbon libraries that will be | |||
| deprecated in newer versions of OSX. This is handy for some backwards-compatibility | |||
| reasons. | |||
| */ | |||
| #ifndef JUCE_SUPPORT_CARBON | |||
| #define JUCE_SUPPORT_CARBON 1 | |||
| #endif | |||
| //============================================================================= | |||
| /* These flags let you avoid the direct inclusion of some 3rd-party libs in the | |||
| codebase - you might need to use this if you're linking to some of these libraries | |||
| @@ -221,6 +221,14 @@ | |||
| #define JUCE_WEB_BROWSER 1 | |||
| #endif | |||
| /** Setting this allows the build to use old Carbon libraries that will be | |||
| deprecated in newer versions of OSX. This is handy for some backwards-compatibility | |||
| reasons. | |||
| */ | |||
| #ifndef JUCE_SUPPORT_CARBON | |||
| #define JUCE_SUPPORT_CARBON 1 | |||
| #endif | |||
| /* These flags let you avoid the direct inclusion of some 3rd-party libs in the | |||
| codebase - you might need to use this if you're linking to some of these libraries | |||
| yourself. | |||
| @@ -2347,8 +2355,13 @@ public: | |||
| @param destBuffer the place to copy it to; if this is a null pointer, | |||
| the method just returns the number of bytes required | |||
| (including the terminating null character). | |||
| @param maxBufferSizeBytes the size of the destination buffer, in bytes. If the | |||
| string won't fit, it'll put in as many as it can while | |||
| still allowing for a terminating null char at the end, | |||
| and will return the number of bytes that were actually | |||
| used. If this value is < 0, no limit is used. | |||
| */ | |||
| int copyToUTF8 (uint8* const destBuffer) const throw(); | |||
| int copyToUTF8 (uint8* const destBuffer, const int maxBufferSizeBytes = 0x7fffffff) const throw(); | |||
| /** Returns a pointer to a UTF-8 version of this string. | |||
| @@ -36083,11 +36096,13 @@ public: | |||
| This will take care of any floating-point conversion that's required to convert | |||
| between the two formats. It won't deal with sample-rate conversion, though. | |||
| If numSamplesToRead < 0, it will write the entire length of the reader. | |||
| @returns false if it can't read or write properly during the operation | |||
| */ | |||
| bool writeFromAudioReader (AudioFormatReader& reader, | |||
| int64 startSample, | |||
| int numSamplesToRead); | |||
| int64 numSamplesToRead); | |||
| /** Reads some samples from an AudioSource, and writes these to the output. | |||
| @@ -37229,6 +37244,13 @@ public: | |||
| const StringPairArray& metadataValues, | |||
| int qualityOptionIndex); | |||
| /** Utility function to replace the metadata in a wav file with a new set of values. | |||
| If possible, this cheats by overwriting just the metadata region of the file, rather | |||
| than by copying the whole file again. | |||
| */ | |||
| bool replaceMetadataInFile (const File& wavFile, const StringPairArray& newMetadata); | |||
| juce_UseDebuggingNewOperator | |||
| }; | |||
| @@ -43050,6 +43072,11 @@ public: | |||
| */ | |||
| virtual int getItemHeight() const { return 20; } | |||
| /** You can override this method to return false if you don't want to allow the | |||
| user to select this item. | |||
| */ | |||
| virtual bool canBeSelected() const { return true; } | |||
| /** Creates a component that will be used to represent this item. | |||
| You don't have to implement this method - if it returns 0 then no component | |||
| @@ -66,7 +66,7 @@ | |||
| #pragma warning (disable: 4309 4305) | |||
| #endif | |||
| #if JUCE_MAC && JUCE_SUPPORT_CARBON | |||
| #if JUCE_MAC && JUCE_32BIT && JUCE_SUPPORT_CARBON | |||
| BEGIN_JUCE_NAMESPACE | |||
| #include "../build/macosx/platform_specific_code/juce_mac_CarbonViewWrapperComponent.h" | |||
| END_JUCE_NAMESPACE | |||
| @@ -330,7 +330,7 @@ AudioFormatWriter::~AudioFormatWriter() | |||
| bool AudioFormatWriter::writeFromAudioReader (AudioFormatReader& reader, | |||
| int64 startSample, | |||
| int numSamplesToRead) | |||
| int64 numSamplesToRead) | |||
| { | |||
| const int bufferSize = 16384; | |||
| const int maxChans = 128; | |||
| @@ -340,9 +340,12 @@ bool AudioFormatWriter::writeFromAudioReader (AudioFormatReader& reader, | |||
| for (int i = maxChans; --i >= 0;) | |||
| buffers[i] = 0; | |||
| if (numSamplesToRead < 0) | |||
| numSamplesToRead = reader.lengthInSamples; | |||
| while (numSamplesToRead > 0) | |||
| { | |||
| const int numToDo = jmin (numSamplesToRead, bufferSize); | |||
| const int numToDo = (int) jmin (numSamplesToRead, (int64) bufferSize); | |||
| for (int i = tempBuffer.getNumChannels(); --i >= 0;) | |||
| buffers[i] = (int*) tempBuffer.getSampleData (i, 0); | |||
| @@ -112,11 +112,13 @@ public: | |||
| This will take care of any floating-point conversion that's required to convert | |||
| between the two formats. It won't deal with sample-rate conversion, though. | |||
| If numSamplesToRead < 0, it will write the entire length of the reader. | |||
| @returns false if it can't read or write properly during the operation | |||
| */ | |||
| bool writeFromAudioReader (AudioFormatReader& reader, | |||
| int64 startSample, | |||
| int numSamplesToRead); | |||
| int64 numSamplesToRead); | |||
| /** Reads some samples from an AudioSource, and writes these to the output. | |||
| @@ -36,6 +36,8 @@ BEGIN_JUCE_NAMESPACE | |||
| #include "juce_WavAudioFormat.h" | |||
| #include "../../../juce_core/io/streams/juce_BufferedInputStream.h" | |||
| #include "../../../juce_core/text/juce_LocalisedStrings.h" | |||
| #include "../../../juce_core/io/files/juce_FileInputStream.h" | |||
| #include "../../../juce_core/io/files/juce_FileOutputStream.h" | |||
| //============================================================================== | |||
| @@ -85,55 +87,55 @@ const StringPairArray WavAudioFormat::createBWAVMetadata (const String& descript | |||
| struct BWAVChunk | |||
| { | |||
| char description [256]; | |||
| char originator [32]; | |||
| char originatorRef [32]; | |||
| char originationDate [10]; | |||
| char originationTime [8]; | |||
| uint8 description [256]; | |||
| uint8 originator [32]; | |||
| uint8 originatorRef [32]; | |||
| uint8 originationDate [10]; | |||
| uint8 originationTime [8]; | |||
| uint32 timeRefLow; | |||
| uint32 timeRefHigh; | |||
| uint16 version; | |||
| uint8 umid[64]; | |||
| uint8 reserved[190]; | |||
| char codingHistory[1]; | |||
| uint8 codingHistory[1]; | |||
| void copyTo (StringPairArray& values) const | |||
| { | |||
| values.set (WavAudioFormat::bwavDescription, String (description, 256)); | |||
| values.set (WavAudioFormat::bwavOriginator, String (originator, 32)); | |||
| values.set (WavAudioFormat::bwavOriginatorRef, String (originatorRef, 32)); | |||
| values.set (WavAudioFormat::bwavOriginationDate, String (originationDate, 10)); | |||
| values.set (WavAudioFormat::bwavOriginationTime, String (originationTime, 8)); | |||
| values.set (WavAudioFormat::bwavDescription, String::fromUTF8 (description, 256)); | |||
| values.set (WavAudioFormat::bwavOriginator, String::fromUTF8 (originator, 32)); | |||
| values.set (WavAudioFormat::bwavOriginatorRef, String::fromUTF8 (originatorRef, 32)); | |||
| values.set (WavAudioFormat::bwavOriginationDate, String::fromUTF8 (originationDate, 10)); | |||
| values.set (WavAudioFormat::bwavOriginationTime, String::fromUTF8 (originationTime, 8)); | |||
| const uint32 timeLow = swapIfBigEndian (timeRefLow); | |||
| const uint32 timeHigh = swapIfBigEndian (timeRefHigh); | |||
| const int64 time = (((int64)timeHigh) << 32) + timeLow; | |||
| values.set (WavAudioFormat::bwavTimeReference, String (time)); | |||
| values.set (WavAudioFormat::bwavCodingHistory, String (codingHistory)); | |||
| values.set (WavAudioFormat::bwavCodingHistory, String::fromUTF8 (codingHistory)); | |||
| } | |||
| static MemoryBlock createFrom (const StringPairArray& values) | |||
| { | |||
| const int sizeNeeded = sizeof (BWAVChunk) + values [WavAudioFormat::bwavCodingHistory].length(); | |||
| const int sizeNeeded = sizeof (BWAVChunk) + values [WavAudioFormat::bwavCodingHistory].copyToUTF8 (0) - 1; | |||
| MemoryBlock data ((sizeNeeded + 3) & ~3); | |||
| data.fillWith (0); | |||
| BWAVChunk* b = (BWAVChunk*) data.getData(); | |||
| // although copyToBuffer may overrun by one byte, that's ok as long as these | |||
| // operations get done in the right order | |||
| values [WavAudioFormat::bwavDescription].copyToBuffer (b->description, 256); | |||
| values [WavAudioFormat::bwavOriginator].copyToBuffer (b->originator, 32); | |||
| values [WavAudioFormat::bwavOriginatorRef].copyToBuffer (b->originatorRef, 32); | |||
| values [WavAudioFormat::bwavOriginationDate].copyToBuffer (b->originationDate, 10); | |||
| values [WavAudioFormat::bwavOriginationTime].copyToBuffer (b->originationTime, 8); | |||
| // Allow these calls to overwrite an extra byte at the end, which is fine as long | |||
| // as they get called in the right order.. | |||
| values [WavAudioFormat::bwavDescription].copyToUTF8 (b->description, 257); | |||
| values [WavAudioFormat::bwavOriginator].copyToUTF8 (b->originator, 33); | |||
| values [WavAudioFormat::bwavOriginatorRef].copyToUTF8 (b->originatorRef, 33); | |||
| values [WavAudioFormat::bwavOriginationDate].copyToUTF8 (b->originationDate, 11); | |||
| values [WavAudioFormat::bwavOriginationTime].copyToUTF8 (b->originationTime, 9); | |||
| const int64 time = values [WavAudioFormat::bwavTimeReference].getLargeIntValue(); | |||
| b->timeRefLow = swapIfBigEndian ((uint32) (time & 0xffffffff)); | |||
| b->timeRefHigh = swapIfBigEndian ((uint32) (time >> 32)); | |||
| values [WavAudioFormat::bwavCodingHistory].copyToBuffer (b->codingHistory, 256 * 1024); | |||
| values [WavAudioFormat::bwavCodingHistory].copyToUTF8 (b->codingHistory); | |||
| if (b->description[0] != 0 | |||
| || b->originator[0] != 0 | |||
| @@ -169,10 +171,14 @@ class WavAudioFormatReader : public AudioFormatReader | |||
| const WavAudioFormatReader& operator= (const WavAudioFormatReader&); | |||
| public: | |||
| int64 bwavChunkStart, bwavSize; | |||
| //============================================================================== | |||
| WavAudioFormatReader (InputStream* const in) | |||
| : AudioFormatReader (in, wavFormatName), | |||
| dataLength (0) | |||
| dataLength (0), | |||
| bwavChunkStart (0), | |||
| bwavSize (0) | |||
| { | |||
| if (input->readInt() == chunkName ("RIFF")) | |||
| { | |||
| @@ -220,6 +226,9 @@ public: | |||
| } | |||
| else if (chunkType == chunkName ("bext")) | |||
| { | |||
| bwavChunkStart = input->getPosition(); | |||
| bwavSize = length; | |||
| // Broadcast-wav extension chunk.. | |||
| BWAVChunk* const bwav = (BWAVChunk*) juce_calloc (jmax (length + 1, (int) sizeof (BWAVChunk))); | |||
| @@ -752,4 +761,82 @@ AudioFormatWriter* WavAudioFormat::createWriterFor (OutputStream* out, | |||
| return 0; | |||
| } | |||
| static bool juce_slowCopyOfWavFileWithNewMetadata (const File& file, const StringPairArray& metadata) | |||
| { | |||
| bool ok = false; | |||
| WavAudioFormat wav; | |||
| const File dest (file.getNonexistentSibling()); | |||
| OutputStream* outStream = dest.createOutputStream(); | |||
| if (outStream != 0) | |||
| { | |||
| AudioFormatReader* reader = wav.createReaderFor (file.createInputStream(), true); | |||
| if (reader != 0) | |||
| { | |||
| AudioFormatWriter* writer = wav.createWriterFor (outStream, reader->sampleRate, | |||
| reader->numChannels, reader->bitsPerSample, | |||
| metadata, 0); | |||
| if (writer != 0) | |||
| { | |||
| ok = writer->writeFromAudioReader (*reader, 0, -1); | |||
| outStream = 0; | |||
| delete writer; | |||
| } | |||
| delete reader; | |||
| } | |||
| delete outStream; | |||
| } | |||
| if (ok) | |||
| ok = dest.moveFileTo (file); | |||
| if (! ok) | |||
| dest.deleteFile(); | |||
| return ok; | |||
| } | |||
| bool WavAudioFormat::replaceMetadataInFile (const File& wavFile, const StringPairArray& newMetadata) | |||
| { | |||
| WavAudioFormatReader* reader = (WavAudioFormatReader*) createReaderFor (wavFile.createInputStream(), true); | |||
| if (reader != 0) | |||
| { | |||
| const int64 bwavPos = reader->bwavChunkStart; | |||
| const int64 bwavSize = reader->bwavSize; | |||
| delete reader; | |||
| if (bwavSize > 0) | |||
| { | |||
| MemoryBlock chunk = BWAVChunk::createFrom (newMetadata); | |||
| if (chunk.getSize() <= bwavSize) | |||
| { | |||
| // the new one will fit in the space available, so write it directly.. | |||
| const int64 oldSize = wavFile.getSize(); | |||
| FileOutputStream* out = wavFile.createOutputStream(); | |||
| out->setPosition (bwavPos); | |||
| out->write (chunk.getData(), chunk.getSize()); | |||
| out->setPosition (oldSize); | |||
| delete out; | |||
| jassert (wavFile.getSize() == oldSize); | |||
| return true; | |||
| } | |||
| } | |||
| } | |||
| return juce_slowCopyOfWavFileWithNewMetadata (wavFile, newMetadata); | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -141,6 +141,13 @@ public: | |||
| const StringPairArray& metadataValues, | |||
| int qualityOptionIndex); | |||
| //============================================================================== | |||
| /** Utility function to replace the metadata in a wav file with a new set of values. | |||
| If possible, this cheats by overwriting just the metadata region of the file, rather | |||
| than by copying the whole file again. | |||
| */ | |||
| bool replaceMetadataInFile (const File& wavFile, const StringPairArray& newMetadata); | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| @@ -37,10 +37,6 @@ | |||
| #include <AudioUnit/AUCocoaUIView.h> | |||
| #include <CoreAudioKit/AUGenericView.h> | |||
| #if JUCE_MAC && JUCE_32BIT | |||
| #define JUCE_SUPPORT_CARBON 1 | |||
| #endif | |||
| #if JUCE_SUPPORT_CARBON | |||
| #include <AudioToolbox/AudioUnitUtilities.h> | |||
| #include <AudioUnit/AudioUnitCarbonView.h> | |||
| @@ -57,6 +53,9 @@ BEGIN_JUCE_NAMESPACE | |||
| #include "../../../../juce_core/misc/juce_PlatformUtilities.h" | |||
| #include "../../../../juce_appframework/gui/components/layout/juce_ComponentMovementWatcher.h" | |||
| #include "../../../../juce_appframework/gui/components/special/juce_NSViewComponent.h" | |||
| #if JUCE_MAC && JUCE_SUPPORT_CARBON | |||
| #include "../../../../../build/macosx/platform_specific_code/juce_mac_CarbonViewWrapperComponent.h" | |||
| #endif | |||
| #if JUCE_MAC | |||
| @@ -79,8 +79,10 @@ BEGIN_JUCE_NAMESPACE | |||
| #include "../../../gui/components/layout/juce_ComponentMovementWatcher.h" | |||
| #include "../../../application/juce_Application.h" | |||
| #include "../../../../juce_core/misc/juce_PlatformUtilities.h" | |||
| #include "../../../../../build/macosx/platform_specific_code/juce_mac_CarbonViewWrapperComponent.h" | |||
| #if JUCE_MAC && JUCE_SUPPORT_CARBON | |||
| #include "../../../../../build/macosx/platform_specific_code/juce_mac_CarbonViewWrapperComponent.h" | |||
| #endif | |||
| //============================================================================== | |||
| #undef PRAGMA_ALIGN_SUPPORTED | |||
| @@ -572,6 +572,9 @@ void TreeView::resized() | |||
| void TreeView::moveSelectedRow (int delta) | |||
| { | |||
| if (delta == 0) | |||
| return; | |||
| int rowSelected = 0; | |||
| TreeViewItem* const firstSelected = getSelectedItem (0); | |||
| @@ -580,13 +583,36 @@ void TreeView::moveSelectedRow (int delta) | |||
| rowSelected = jlimit (0, getNumRowsInTree() - 1, rowSelected + delta); | |||
| TreeViewItem* item = getItemOnRow (rowSelected); | |||
| if (item != 0) | |||
| for (;;) | |||
| { | |||
| item->setSelected (true, true); | |||
| TreeViewItem* item = getItemOnRow (rowSelected); | |||
| if (item != 0) | |||
| { | |||
| if (! item->canBeSelected()) | |||
| { | |||
| // if the row we want to highlight doesn't allow it, try skipping | |||
| // to the next item.. | |||
| const int nextRowToTry = jlimit (0, getNumRowsInTree() - 1, | |||
| rowSelected + (delta < 0 ? -1 : 1)); | |||
| scrollToKeepItemVisible (item); | |||
| if (rowSelected != nextRowToTry) | |||
| { | |||
| rowSelected = nextRowToTry; | |||
| continue; | |||
| } | |||
| else | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| item->setSelected (true, true); | |||
| scrollToKeepItemVisible (item); | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| @@ -906,6 +932,9 @@ void TreeViewItem::deselectAllRecursively() | |||
| void TreeViewItem::setSelected (const bool shouldBeSelected, | |||
| const bool deselectOtherItemsFirst) | |||
| { | |||
| if (shouldBeSelected && ! canBeSelected()) | |||
| return; | |||
| if (deselectOtherItemsFirst) | |||
| getTopLevelItem()->deselectAllRecursively(); | |||
| @@ -238,6 +238,11 @@ public: | |||
| */ | |||
| virtual int getItemHeight() const { return 20; } | |||
| /** You can override this method to return false if you don't want to allow the | |||
| user to select this item. | |||
| */ | |||
| virtual bool canBeSelected() const { return true; } | |||
| /** Creates a component that will be used to represent this item. | |||
| You don't have to implement this method - if it returns 0 then no component | |||
| @@ -150,7 +150,7 @@ PixelARGB* ColourGradient::createLookupTable (int& numEntries) const throw() | |||
| for (int j = 2; j < colours.size(); j += 2) | |||
| { | |||
| const int numToDo = ((colours.getUnchecked (j) * numEntries) >> 16) - index; | |||
| const int numToDo = ((colours.getUnchecked (j) * (numEntries - 1)) >> 16) - index; | |||
| const PixelARGB pix2 (colours.getUnchecked (j + 1)); | |||
| for (int i = 0; i < numToDo; ++i) | |||
| @@ -2086,8 +2086,10 @@ const char* String::toUTF8() const throw() | |||
| } | |||
| } | |||
| int String::copyToUTF8 (uint8* const buffer) const throw() | |||
| int String::copyToUTF8 (uint8* const buffer, const int maxBufferSizeBytes) const throw() | |||
| { | |||
| jassert (maxBufferSizeBytes >= 0); // keep this value positive, or no characters will be copied! | |||
| #if JUCE_STRINGS_ARE_UNICODE | |||
| int num = 0, index = 0; | |||
| @@ -2119,10 +2121,18 @@ int String::copyToUTF8 (uint8* const buffer) const throw() | |||
| if (buffer != 0) | |||
| { | |||
| buffer [num++] = (uint8) ((0xff << (7 - numExtraBytes)) | (c >> (numExtraBytes * 6))); | |||
| if (num + numExtraBytes >= maxBufferSizeBytes) | |||
| { | |||
| buffer [num++] = 0; | |||
| break; | |||
| } | |||
| else | |||
| { | |||
| buffer [num++] = (uint8) ((0xff << (7 - numExtraBytes)) | (c >> (numExtraBytes * 6))); | |||
| while (--numExtraBytes >= 0) | |||
| buffer [num++] = (uint8) (0x80 | (0x3f & (c >> (numExtraBytes * 6)))); | |||
| while (--numExtraBytes >= 0) | |||
| buffer [num++] = (uint8) (0x80 | (0x3f & (c >> (numExtraBytes * 6)))); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| @@ -2132,7 +2142,15 @@ int String::copyToUTF8 (uint8* const buffer) const throw() | |||
| else | |||
| { | |||
| if (buffer != 0) | |||
| { | |||
| if (num + 1 >= maxBufferSizeBytes) | |||
| { | |||
| buffer [num++] = 0; | |||
| break; | |||
| } | |||
| buffer [num] = (uint8) c; | |||
| } | |||
| ++num; | |||
| } | |||
| @@ -2144,10 +2162,10 @@ int String::copyToUTF8 (uint8* const buffer) const throw() | |||
| return num; | |||
| #else | |||
| const int numBytes = length() + 1; | |||
| const int numBytes = jmin (maxBufferSizeBytes, length() + 1); | |||
| if (buffer != 0) | |||
| copyToBuffer ((char*) buffer, numBytes); | |||
| copyToBuffer ((char*) buffer, maxBufferSizeBytes); | |||
| return numBytes; | |||
| #endif | |||
| @@ -1003,8 +1003,13 @@ public: | |||
| @param destBuffer the place to copy it to; if this is a null pointer, | |||
| the method just returns the number of bytes required | |||
| (including the terminating null character). | |||
| @param maxBufferSizeBytes the size of the destination buffer, in bytes. If the | |||
| string won't fit, it'll put in as many as it can while | |||
| still allowing for a terminating null char at the end, | |||
| and will return the number of bytes that were actually | |||
| used. If this value is < 0, no limit is used. | |||
| */ | |||
| int copyToUTF8 (uint8* const destBuffer) const throw(); | |||
| int copyToUTF8 (uint8* const destBuffer, const int maxBufferSizeBytes = 0x7fffffff) const throw(); | |||
| /** Returns a pointer to a UTF-8 version of this string. | |||