| @@ -86,41 +86,28 @@ public: | |||||
| virtual int read (void* destBuffer, int maxBytesToRead) = 0; | virtual int read (void* destBuffer, int maxBytesToRead) = 0; | ||||
| /** Reads a byte from the stream. | /** Reads a byte from the stream. | ||||
| If the stream is exhausted, this will return zero. | If the stream is exhausted, this will return zero. | ||||
| @see OutputStream::writeByte | @see OutputStream::writeByte | ||||
| */ | */ | ||||
| virtual char readByte(); | virtual char readByte(); | ||||
| /** Reads a boolean from the stream. | /** Reads a boolean from the stream. | ||||
| The bool is encoded as a single byte - 1 for true, 0 for false. | |||||
| The bool is encoded as a single byte - non-zero for true, 0 for false. | |||||
| If the stream is exhausted, this will return false. | If the stream is exhausted, this will return false. | ||||
| @see OutputStream::writeBool | @see OutputStream::writeBool | ||||
| */ | */ | ||||
| virtual bool readBool(); | virtual bool readBool(); | ||||
| /** Reads two bytes from the stream as a little-endian 16-bit value. | /** Reads two bytes from the stream as a little-endian 16-bit value. | ||||
| If the next two bytes read are byte1 and byte2, this returns | |||||
| (byte1 | (byte2 << 8)). | |||||
| If the next two bytes read are byte1 and byte2, this returns (byte1 | (byte2 << 8)). | |||||
| If the stream is exhausted partway through reading the bytes, this will return zero. | If the stream is exhausted partway through reading the bytes, this will return zero. | ||||
| @see OutputStream::writeShort, readShortBigEndian | @see OutputStream::writeShort, readShortBigEndian | ||||
| */ | */ | ||||
| virtual short readShort(); | virtual short readShort(); | ||||
| /** Reads two bytes from the stream as a little-endian 16-bit value. | /** Reads two bytes from the stream as a little-endian 16-bit value. | ||||
| If the next two bytes read are byte1 and byte2, this returns | |||||
| (byte2 | (byte1 << 8)). | |||||
| If the next two bytes read are byte1 and byte2, this returns (byte2 | (byte1 << 8)). | |||||
| If the stream is exhausted partway through reading the bytes, this will return zero. | If the stream is exhausted partway through reading the bytes, this will return zero. | ||||
| @see OutputStream::writeShortBigEndian, readShort | @see OutputStream::writeShortBigEndian, readShort | ||||
| */ | */ | ||||
| virtual short readShortBigEndian(); | virtual short readShortBigEndian(); | ||||
| @@ -170,51 +157,36 @@ public: | |||||
| virtual int64 readInt64BigEndian(); | virtual int64 readInt64BigEndian(); | ||||
| /** Reads four bytes as a 32-bit floating point value. | /** Reads four bytes as a 32-bit floating point value. | ||||
| The raw 32-bit encoding of the float is read from the stream as a little-endian int. | The raw 32-bit encoding of the float is read from the stream as a little-endian int. | ||||
| If the stream is exhausted partway through reading the bytes, this will return zero. | If the stream is exhausted partway through reading the bytes, this will return zero. | ||||
| @see OutputStream::writeFloat, readDouble | @see OutputStream::writeFloat, readDouble | ||||
| */ | */ | ||||
| virtual float readFloat(); | virtual float readFloat(); | ||||
| /** Reads four bytes as a 32-bit floating point value. | /** Reads four bytes as a 32-bit floating point value. | ||||
| The raw 32-bit encoding of the float is read from the stream as a big-endian int. | The raw 32-bit encoding of the float is read from the stream as a big-endian int. | ||||
| If the stream is exhausted partway through reading the bytes, this will return zero. | If the stream is exhausted partway through reading the bytes, this will return zero. | ||||
| @see OutputStream::writeFloatBigEndian, readDoubleBigEndian | @see OutputStream::writeFloatBigEndian, readDoubleBigEndian | ||||
| */ | */ | ||||
| virtual float readFloatBigEndian(); | virtual float readFloatBigEndian(); | ||||
| /** Reads eight bytes as a 64-bit floating point value. | /** Reads eight bytes as a 64-bit floating point value. | ||||
| The raw 64-bit encoding of the double is read from the stream as a little-endian int64. | The raw 64-bit encoding of the double is read from the stream as a little-endian int64. | ||||
| If the stream is exhausted partway through reading the bytes, this will return zero. | If the stream is exhausted partway through reading the bytes, this will return zero. | ||||
| @see OutputStream::writeDouble, readFloat | @see OutputStream::writeDouble, readFloat | ||||
| */ | */ | ||||
| virtual double readDouble(); | virtual double readDouble(); | ||||
| /** Reads eight bytes as a 64-bit floating point value. | /** Reads eight bytes as a 64-bit floating point value. | ||||
| The raw 64-bit encoding of the double is read from the stream as a big-endian int64. | The raw 64-bit encoding of the double is read from the stream as a big-endian int64. | ||||
| If the stream is exhausted partway through reading the bytes, this will return zero. | If the stream is exhausted partway through reading the bytes, this will return zero. | ||||
| @see OutputStream::writeDoubleBigEndian, readFloatBigEndian | @see OutputStream::writeDoubleBigEndian, readFloatBigEndian | ||||
| */ | */ | ||||
| virtual double readDoubleBigEndian(); | virtual double readDoubleBigEndian(); | ||||
| /** Reads an encoded 32-bit number from the stream using a space-saving compressed format. | /** Reads an encoded 32-bit number from the stream using a space-saving compressed format. | ||||
| For small values, this is more space-efficient than using readInt() and OutputStream::writeInt() | For small values, this is more space-efficient than using readInt() and OutputStream::writeInt() | ||||
| The format used is: number of significant bytes + up to 4 bytes in little-endian order. | The format used is: number of significant bytes + up to 4 bytes in little-endian order. | ||||
| @see OutputStream::writeCompressedInt() | @see OutputStream::writeCompressedInt() | ||||
| */ | */ | ||||
| virtual int readCompressedInt(); | virtual int readCompressedInt(); | ||||
| @@ -259,7 +231,6 @@ public: | |||||
| //============================================================================== | //============================================================================== | ||||
| /** Returns the offset of the next byte that will be read from the stream. | /** Returns the offset of the next byte that will be read from the stream. | ||||
| @see setPosition | @see setPosition | ||||
| */ | */ | ||||
| virtual int64 getPosition() = 0; | virtual int64 getPosition() = 0; | ||||
| @@ -27,23 +27,28 @@ | |||||
| */ | */ | ||||
| MemoryOutputStream::MemoryOutputStream (const size_t initialSize) | MemoryOutputStream::MemoryOutputStream (const size_t initialSize) | ||||
| : data (internalBlock), | |||||
| position (0), | |||||
| size (0) | |||||
| : blockToUse (&internalBlock), externalData (nullptr), | |||||
| position (0), size (0), availableSize (0) | |||||
| { | { | ||||
| internalBlock.setSize (initialSize, false); | internalBlock.setSize (initialSize, false); | ||||
| } | } | ||||
| MemoryOutputStream::MemoryOutputStream (MemoryBlock& memoryBlockToWriteTo, | MemoryOutputStream::MemoryOutputStream (MemoryBlock& memoryBlockToWriteTo, | ||||
| const bool appendToExistingBlockContent) | const bool appendToExistingBlockContent) | ||||
| : data (memoryBlockToWriteTo), | |||||
| position (0), | |||||
| size (0) | |||||
| : blockToUse (&memoryBlockToWriteTo), externalData (nullptr), | |||||
| position (0), size (0), availableSize (0) | |||||
| { | { | ||||
| if (appendToExistingBlockContent) | if (appendToExistingBlockContent) | ||||
| position = size = memoryBlockToWriteTo.getSize(); | position = size = memoryBlockToWriteTo.getSize(); | ||||
| } | } | ||||
| MemoryOutputStream::MemoryOutputStream (void* destBuffer, size_t destBufferSize) | |||||
| : blockToUse (nullptr), externalData (destBuffer), | |||||
| position (0), size (0), availableSize (destBufferSize) | |||||
| { | |||||
| jassert (externalData != nullptr); // This must be a valid pointer. | |||||
| } | |||||
| MemoryOutputStream::~MemoryOutputStream() | MemoryOutputStream::~MemoryOutputStream() | ||||
| { | { | ||||
| trimExternalBlockSize(); | trimExternalBlockSize(); | ||||
| @@ -56,13 +61,14 @@ void MemoryOutputStream::flush() | |||||
| void MemoryOutputStream::trimExternalBlockSize() | void MemoryOutputStream::trimExternalBlockSize() | ||||
| { | { | ||||
| if (&data != &internalBlock) | |||||
| data.setSize (size, false); | |||||
| if (blockToUse != &internalBlock && blockToUse != nullptr) | |||||
| blockToUse->setSize (size, false); | |||||
| } | } | ||||
| void MemoryOutputStream::preallocate (const size_t bytesToPreallocate) | void MemoryOutputStream::preallocate (const size_t bytesToPreallocate) | ||||
| { | { | ||||
| data.ensureSize (bytesToPreallocate + 1); | |||||
| if (blockToUse != nullptr) | |||||
| blockToUse->ensureSize (bytesToPreallocate + 1); | |||||
| } | } | ||||
| void MemoryOutputStream::reset() noexcept | void MemoryOutputStream::reset() noexcept | ||||
| @@ -76,10 +82,24 @@ char* MemoryOutputStream::prepareToWrite (size_t numBytes) | |||||
| jassert ((ssize_t) numBytes >= 0); | jassert ((ssize_t) numBytes >= 0); | ||||
| size_t storageNeeded = position + numBytes; | size_t storageNeeded = position + numBytes; | ||||
| if (storageNeeded >= data.getSize()) | |||||
| data.ensureSize ((storageNeeded + jmin (storageNeeded / 2, (size_t) (1024 * 1024)) + 32) & ~31u); | |||||
| char* data; | |||||
| if (blockToUse != nullptr) | |||||
| { | |||||
| if (storageNeeded >= blockToUse->getSize()) | |||||
| blockToUse->ensureSize ((storageNeeded + jmin (storageNeeded / 2, (size_t) (1024 * 1024)) + 32) & ~31u); | |||||
| data = static_cast <char*> (blockToUse->getData()); | |||||
| } | |||||
| else | |||||
| { | |||||
| if (storageNeeded > availableSize) | |||||
| return nullptr; | |||||
| data = static_cast <char*> (externalData); | |||||
| } | |||||
| char* const writePointer = static_cast <char*> (data.getData()) + position; | |||||
| char* const writePointer = data + position; | |||||
| position += numBytes; | position += numBytes; | ||||
| size = jmax (size, position); | size = jmax (size, position); | ||||
| return writePointer; | return writePointer; | ||||
| @@ -87,25 +107,43 @@ char* MemoryOutputStream::prepareToWrite (size_t numBytes) | |||||
| bool MemoryOutputStream::write (const void* const buffer, size_t howMany) | bool MemoryOutputStream::write (const void* const buffer, size_t howMany) | ||||
| { | { | ||||
| jassert (buffer != nullptr && ((ssize_t) howMany) >= 0); | |||||
| jassert (buffer != nullptr); | |||||
| if (howMany > 0) | |||||
| memcpy (prepareToWrite (howMany), buffer, howMany); | |||||
| if (howMany == 0) | |||||
| return true; | |||||
| if (char* dest = prepareToWrite (howMany)) | |||||
| { | |||||
| memcpy (dest, buffer, howMany); | |||||
| return true; | |||||
| } | |||||
| return true; | |||||
| return false; | |||||
| } | } | ||||
| bool MemoryOutputStream::writeRepeatedByte (uint8 byte, size_t howMany) | bool MemoryOutputStream::writeRepeatedByte (uint8 byte, size_t howMany) | ||||
| { | { | ||||
| if (howMany > 0) | |||||
| memset (prepareToWrite (howMany), byte, howMany); | |||||
| if (howMany == 0) | |||||
| return true; | |||||
| if (char* dest = prepareToWrite (howMany)) | |||||
| { | |||||
| memset (dest, byte, howMany); | |||||
| return true; | |||||
| } | |||||
| return true; | |||||
| return false; | |||||
| } | } | ||||
| void MemoryOutputStream::appendUTF8Char (juce_wchar c) | |||||
| bool MemoryOutputStream::appendUTF8Char (juce_wchar c) | |||||
| { | { | ||||
| CharPointer_UTF8 (prepareToWrite (CharPointer_UTF8::getBytesRequiredFor (c))).write (c); | |||||
| if (char* dest = prepareToWrite (CharPointer_UTF8::getBytesRequiredFor (c))) | |||||
| { | |||||
| CharPointer_UTF8 (dest).write (c); | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | } | ||||
| MemoryBlock MemoryOutputStream::getMemoryBlock() const | MemoryBlock MemoryOutputStream::getMemoryBlock() const | ||||
| @@ -115,10 +153,13 @@ MemoryBlock MemoryOutputStream::getMemoryBlock() const | |||||
| const void* MemoryOutputStream::getData() const noexcept | const void* MemoryOutputStream::getData() const noexcept | ||||
| { | { | ||||
| if (data.getSize() > size) | |||||
| static_cast <char*> (data.getData()) [size] = 0; | |||||
| if (blockToUse == nullptr) | |||||
| return externalData; | |||||
| if (blockToUse->getSize() > size) | |||||
| static_cast <char*> (blockToUse->getData()) [size] = 0; | |||||
| return data.getData(); | |||||
| return blockToUse->getData(); | |||||
| } | } | ||||
| bool MemoryOutputStream::setPosition (int64 newPosition) | bool MemoryOutputStream::setPosition (int64 newPosition) | ||||
| @@ -144,7 +185,8 @@ int MemoryOutputStream::writeFromInputStream (InputStream& source, int64 maxNumB | |||||
| if (maxNumBytesToWrite > availableData) | if (maxNumBytesToWrite > availableData) | ||||
| maxNumBytesToWrite = availableData; | maxNumBytesToWrite = availableData; | ||||
| preallocate (data.getSize() + (size_t) maxNumBytesToWrite); | |||||
| if (blockToUse != nullptr) | |||||
| preallocate (blockToUse->getSize() + (size_t) maxNumBytesToWrite); | |||||
| } | } | ||||
| return OutputStream::writeFromInputStream (source, maxNumBytesToWrite); | return OutputStream::writeFromInputStream (source, maxNumBytesToWrite); | ||||
| @@ -46,7 +46,6 @@ class JUCE_API MemoryOutputStream : public OutputStream | |||||
| public: | public: | ||||
| //============================================================================== | //============================================================================== | ||||
| /** Creates an empty memory stream, ready to be written into. | /** Creates an empty memory stream, ready to be written into. | ||||
| @param initialSize the intial amount of capacity to allocate for writing into | @param initialSize the intial amount of capacity to allocate for writing into | ||||
| */ | */ | ||||
| MemoryOutputStream (size_t initialSize = 256); | MemoryOutputStream (size_t initialSize = 256); | ||||
| @@ -66,6 +65,13 @@ public: | |||||
| MemoryOutputStream (MemoryBlock& memoryBlockToWriteTo, | MemoryOutputStream (MemoryBlock& memoryBlockToWriteTo, | ||||
| bool appendToExistingBlockContent); | bool appendToExistingBlockContent); | ||||
| /** Creates a MemoryOutputStream that will write into a user-supplied, fixed-size | |||||
| block of memory. | |||||
| When using this mode, the stream will write directly into this memory area until | |||||
| it's full, at which point write operations will fail. | |||||
| */ | |||||
| MemoryOutputStream (void* destBuffer, size_t destBufferSize); | |||||
| /** Destructor. | /** Destructor. | ||||
| This will free any data that was written to it. | This will free any data that was written to it. | ||||
| */ | */ | ||||
| @@ -91,7 +97,7 @@ public: | |||||
| void preallocate (size_t bytesToPreallocate); | void preallocate (size_t bytesToPreallocate); | ||||
| /** Appends the utf-8 bytes for a unicode character */ | /** Appends the utf-8 bytes for a unicode character */ | ||||
| void appendUTF8Char (juce_wchar character); | |||||
| bool appendUTF8Char (juce_wchar character); | |||||
| /** Returns a String created from the (UTF8) data that has been written to the stream. */ | /** Returns a String created from the (UTF8) data that has been written to the stream. */ | ||||
| String toUTF8() const; | String toUTF8() const; | ||||
| @@ -119,9 +125,10 @@ public: | |||||
| private: | private: | ||||
| //============================================================================== | //============================================================================== | ||||
| MemoryBlock& data; | |||||
| MemoryBlock* const blockToUse; | |||||
| MemoryBlock internalBlock; | MemoryBlock internalBlock; | ||||
| size_t position, size; | |||||
| void* externalData; | |||||
| size_t position, size, availableSize; | |||||
| void trimExternalBlockSize(); | void trimExternalBlockSize(); | ||||
| char* prepareToWrite (size_t); | char* prepareToWrite (size_t); | ||||