2 ==============================================================================
4 This file is part of the Water library.
5 Copyright (c) 2016 ROLI Ltd.
6 Copyright (C) 2017 Filipe Coelho <falktx@falktx.com>
8 Permission is granted to use this software under the terms of the ISC license
9 http://www.isc.org/downloads/software-support-policy/isc-license/
11 Permission to use, copy, modify, and/or distribute this software for any
12 purpose with or without fee is hereby granted, provided that the above
13 copyright notice and this permission notice appear in all copies.
15 THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
16 TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
18 OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
19 USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
23 ==============================================================================
26 #include "MemoryOutputStream.h"
27 #include "InputStream.h"
31 MemoryOutputStream::MemoryOutputStream (const size_t initialSize
)
32 : internalBlock(), blockToUse (internalBlock
),
33 position (0), size (0),
34 usingInternalBlock (true)
36 internalBlock
.setSize (initialSize
, false);
39 MemoryOutputStream::MemoryOutputStream (MemoryBlock
& memoryBlockToWriteTo
,
40 const bool appendToExistingBlockContent
)
41 : internalBlock(), blockToUse (memoryBlockToWriteTo
),
42 position (0), size (0),
43 usingInternalBlock (false)
45 if (appendToExistingBlockContent
)
46 position
= size
= memoryBlockToWriteTo
.getSize();
49 MemoryOutputStream::~MemoryOutputStream()
51 trimExternalBlockSize();
54 void MemoryOutputStream::flush()
56 trimExternalBlockSize();
59 void MemoryOutputStream::trimExternalBlockSize()
61 if (! usingInternalBlock
)
62 blockToUse
.setSize (size
, false);
65 void MemoryOutputStream::preallocate (const size_t bytesToPreallocate
)
67 blockToUse
.ensureSize (bytesToPreallocate
+ 1);
70 void MemoryOutputStream::reset() noexcept
76 char* MemoryOutputStream::prepareToWrite (size_t numBytes
)
78 CARLA_SAFE_ASSERT_RETURN ((ssize_t
) numBytes
>= 0, nullptr);
80 const size_t storageNeeded
= position
+ numBytes
;
82 if (storageNeeded
>= blockToUse
.getSize())
83 blockToUse
.ensureSize ((storageNeeded
+ jmin (storageNeeded
/ 2, (size_t) (1024 * 1024)) + 32) & ~31u);
85 char* const data
= static_cast<char*> (blockToUse
.getData());
86 char* const writePointer
= data
+ position
;
88 size
= jmax (size
, position
);
92 bool MemoryOutputStream::write (const void* const buffer
, size_t howMany
)
94 CARLA_SAFE_ASSERT_RETURN (buffer
!= nullptr, false);
99 if (char* const dest
= prepareToWrite (howMany
))
101 std::memcpy (dest
, buffer
, howMany
);
108 bool MemoryOutputStream::writeRepeatedByte (uint8 byte
, size_t howMany
)
113 if (char* dest
= prepareToWrite (howMany
))
115 memset (dest
, byte
, howMany
);
122 bool MemoryOutputStream::appendUTF8Char (water_uchar c
)
124 if (char* dest
= prepareToWrite (CharPointer_UTF8::getBytesRequiredFor (c
)))
126 CharPointer_UTF8 (dest
).write (c
);
133 MemoryBlock
MemoryOutputStream::getMemoryBlock() const
135 return MemoryBlock (getData(), getDataSize());
138 const void* MemoryOutputStream::getData() const noexcept
140 if (blockToUse
.getSize() > size
)
141 static_cast<char*> (blockToUse
.getData()) [size
] = 0;
143 return blockToUse
.getData();
146 void* MemoryOutputStream::getDataAndRelease() noexcept
148 if (blockToUse
.getSize() > size
)
149 static_cast<char*> (blockToUse
.getData()) [size
] = 0;
151 return blockToUse
.release();
154 bool MemoryOutputStream::setPosition (int64 newPosition
)
156 if (newPosition
<= (int64
) size
)
158 // ok to seek backwards
159 position
= jlimit ((size_t) 0, size
, (size_t) newPosition
);
163 // can't move beyond the end of the stream..
167 int64
MemoryOutputStream::writeFromInputStream (InputStream
& source
, int64 maxNumBytesToWrite
)
169 // before writing from an input, see if we can preallocate to make it more efficient..
170 int64 availableData
= source
.getTotalLength() - source
.getPosition();
172 if (availableData
> 0)
174 if (maxNumBytesToWrite
> availableData
|| maxNumBytesToWrite
< 0)
175 maxNumBytesToWrite
= availableData
;
177 preallocate (blockToUse
.getSize() + (size_t) maxNumBytesToWrite
);
180 return OutputStream::writeFromInputStream (source
, maxNumBytesToWrite
);
183 String
MemoryOutputStream::toUTF8() const
185 const char* const d
= static_cast<const char*> (getData());
186 return String (CharPointer_UTF8 (d
), CharPointer_UTF8 (d
+ getDataSize()));
189 String
MemoryOutputStream::toString() const
191 return String::createStringFromData (getData(), (int) getDataSize());
194 OutputStream
& operator<< (OutputStream
& stream
, const MemoryOutputStream
& streamToRead
)
196 const size_t dataSize
= streamToRead
.getDataSize();
199 stream
.write (streamToRead
.getData(), dataSize
);