| @@ -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; | |||
| @@ -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; | |||
| 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; | |||
| 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; | |||
| if (char* dest = prepareToWrite (howMany)) | |||
| { | |||
| memcpy (dest, buffer, howMany); | |||
| return true; | |||
| } | |||
| 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; | |||
| 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 | |||
| @@ -115,10 +153,13 @@ MemoryBlock MemoryOutputStream::getMemoryBlock() const | |||
| 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) | |||
| @@ -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); | |||
| @@ -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); | |||