From 9f97ff341bdc98bb02da2d7453972f709ceea58d Mon Sep 17 00:00:00 2001 From: jules Date: Mon, 22 Jul 2013 11:29:15 +0100 Subject: [PATCH] Added a MemoryOutputStream constructor to write into a fixed block of memory. --- modules/juce_core/streams/juce_InputStream.h | 35 +------ .../streams/juce_MemoryOutputStream.cpp | 92 ++++++++++++++----- .../streams/juce_MemoryOutputStream.h | 15 ++- 3 files changed, 81 insertions(+), 61 deletions(-) diff --git a/modules/juce_core/streams/juce_InputStream.h b/modules/juce_core/streams/juce_InputStream.h index 26cae01ab2..d29df065ad 100644 --- a/modules/juce_core/streams/juce_InputStream.h +++ b/modules/juce_core/streams/juce_InputStream.h @@ -86,41 +86,28 @@ public: virtual int read (void* destBuffer, int maxBytesToRead) = 0; /** Reads a byte from the stream. - If the stream is exhausted, this will return zero. - @see OutputStream::writeByte */ virtual char readByte(); /** 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. - @see OutputStream::writeBool */ virtual bool readBool(); /** 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. - @see OutputStream::writeShort, readShortBigEndian */ virtual short readShort(); /** 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. - @see OutputStream::writeShortBigEndian, readShort */ virtual short readShortBigEndian(); @@ -170,51 +157,36 @@ public: virtual int64 readInt64BigEndian(); /** 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. - If the stream is exhausted partway through reading the bytes, this will return zero. - @see OutputStream::writeFloat, readDouble */ virtual float readFloat(); /** 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. - If the stream is exhausted partway through reading the bytes, this will return zero. - @see OutputStream::writeFloatBigEndian, readDoubleBigEndian */ virtual float readFloatBigEndian(); /** 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. - If the stream is exhausted partway through reading the bytes, this will return zero. - @see OutputStream::writeDouble, readFloat */ virtual double readDouble(); /** 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. - If the stream is exhausted partway through reading the bytes, this will return zero. - @see OutputStream::writeDoubleBigEndian, readFloatBigEndian */ virtual double readDoubleBigEndian(); /** 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() - The format used is: number of significant bytes + up to 4 bytes in little-endian order. - @see OutputStream::writeCompressedInt() */ virtual int readCompressedInt(); @@ -259,7 +231,6 @@ public: //============================================================================== /** Returns the offset of the next byte that will be read from the stream. - @see setPosition */ virtual int64 getPosition() = 0; diff --git a/modules/juce_core/streams/juce_MemoryOutputStream.cpp b/modules/juce_core/streams/juce_MemoryOutputStream.cpp index b4f08ab153..7d07ce627b 100644 --- a/modules/juce_core/streams/juce_MemoryOutputStream.cpp +++ b/modules/juce_core/streams/juce_MemoryOutputStream.cpp @@ -27,23 +27,28 @@ */ 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); } MemoryOutputStream::MemoryOutputStream (MemoryBlock& memoryBlockToWriteTo, const bool appendToExistingBlockContent) - : data (memoryBlockToWriteTo), - position (0), - size (0) + : blockToUse (&memoryBlockToWriteTo), externalData (nullptr), + position (0), size (0), availableSize (0) { if (appendToExistingBlockContent) 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() { trimExternalBlockSize(); @@ -56,13 +61,14 @@ void MemoryOutputStream::flush() 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) { - data.ensureSize (bytesToPreallocate + 1); + if (blockToUse != nullptr) + blockToUse->ensureSize (bytesToPreallocate + 1); } void MemoryOutputStream::reset() noexcept @@ -76,10 +82,24 @@ char* MemoryOutputStream::prepareToWrite (size_t numBytes) jassert ((ssize_t) numBytes >= 0); size_t storageNeeded = position + numBytes; - if (storageNeeded >= data.getSize()) - data.ensureSize ((storageNeeded + jmin (storageNeeded / 2, (size_t) (1024 * 1024)) + 32) & ~31u); + char* data; - char* const writePointer = static_cast (data.getData()) + position; + if (blockToUse != nullptr) + { + if (storageNeeded >= blockToUse->getSize()) + blockToUse->ensureSize ((storageNeeded + jmin (storageNeeded / 2, (size_t) (1024 * 1024)) + 32) & ~31u); + + data = static_cast (blockToUse->getData()); + } + else + { + if (storageNeeded > availableSize) + return nullptr; + + data = static_cast (externalData); + } + + char* const writePointer = data + position; position += numBytes; size = jmax (size, position); return writePointer; @@ -87,25 +107,43 @@ char* MemoryOutputStream::prepareToWrite (size_t numBytes) 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; - return true; + if (char* dest = prepareToWrite (howMany)) + { + memcpy (dest, buffer, howMany); + return true; + } + + return false; } bool MemoryOutputStream::writeRepeatedByte (uint8 byte, size_t howMany) { - if (howMany > 0) - memset (prepareToWrite (howMany), byte, howMany); + if (howMany == 0) + return true; - return true; + if (char* dest = prepareToWrite (howMany)) + { + memset (dest, byte, howMany); + 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 @@ -115,10 +153,13 @@ MemoryBlock MemoryOutputStream::getMemoryBlock() const const void* MemoryOutputStream::getData() const noexcept { - if (data.getSize() > size) - static_cast (data.getData()) [size] = 0; + if (blockToUse == nullptr) + return externalData; - return data.getData(); + if (blockToUse->getSize() > size) + static_cast (blockToUse->getData()) [size] = 0; + + return blockToUse->getData(); } bool MemoryOutputStream::setPosition (int64 newPosition) @@ -144,7 +185,8 @@ int MemoryOutputStream::writeFromInputStream (InputStream& source, int64 maxNumB if (maxNumBytesToWrite > availableData) maxNumBytesToWrite = availableData; - preallocate (data.getSize() + (size_t) maxNumBytesToWrite); + if (blockToUse != nullptr) + preallocate (blockToUse->getSize() + (size_t) maxNumBytesToWrite); } return OutputStream::writeFromInputStream (source, maxNumBytesToWrite); diff --git a/modules/juce_core/streams/juce_MemoryOutputStream.h b/modules/juce_core/streams/juce_MemoryOutputStream.h index 56f732e23c..06c08d6066 100644 --- a/modules/juce_core/streams/juce_MemoryOutputStream.h +++ b/modules/juce_core/streams/juce_MemoryOutputStream.h @@ -46,7 +46,6 @@ class JUCE_API MemoryOutputStream : public OutputStream public: //============================================================================== /** Creates an empty memory stream, ready to be written into. - @param initialSize the intial amount of capacity to allocate for writing into */ MemoryOutputStream (size_t initialSize = 256); @@ -66,6 +65,13 @@ public: MemoryOutputStream (MemoryBlock& memoryBlockToWriteTo, 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. This will free any data that was written to it. */ @@ -91,7 +97,7 @@ public: void preallocate (size_t bytesToPreallocate); /** 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. */ String toUTF8() const; @@ -119,9 +125,10 @@ public: private: //============================================================================== - MemoryBlock& data; + MemoryBlock* const blockToUse; MemoryBlock internalBlock; - size_t position, size; + void* externalData; + size_t position, size, availableSize; void trimExternalBlockSize(); char* prepareToWrite (size_t);