OpenShot Library | libopenshot-audio 0.2.0
juce_OutputStream.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2017 - ROLI Ltd.
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
26#if JUCE_DEBUG
27
28struct DanglingStreamChecker
29{
30 DanglingStreamChecker() {}
31
32 ~DanglingStreamChecker()
33 {
34 /*
35 It's always a bad idea to leak any object, but if you're leaking output
36 streams, then there's a good chance that you're failing to flush a file
37 to disk properly, which could result in corrupted data and other similar
38 nastiness..
39 */
40 jassert (activeStreams.size() == 0);
41 }
42
43 Array<void*, CriticalSection> activeStreams;
44};
45
46static DanglingStreamChecker danglingStreamChecker;
47#endif
48
49//==============================================================================
50OutputStream::OutputStream()
51 : newLineString (NewLine::getDefault())
52{
53 #if JUCE_DEBUG
54 danglingStreamChecker.activeStreams.add (this);
55 #endif
56}
57
58OutputStream::~OutputStream()
59{
60 #if JUCE_DEBUG
61 danglingStreamChecker.activeStreams.removeFirstMatchingValue (this);
62 #endif
63}
64
65//==============================================================================
66bool OutputStream::writeBool (bool b)
67{
68 return writeByte (b ? (char) 1
69 : (char) 0);
70}
71
72bool OutputStream::writeByte (char byte)
73{
74 return write (&byte, 1);
75}
76
77bool OutputStream::writeRepeatedByte (uint8 byte, size_t numTimesToRepeat)
78{
79 for (size_t i = 0; i < numTimesToRepeat; ++i)
80 if (! writeByte ((char) byte))
81 return false;
82
83 return true;
84}
85
86bool OutputStream::writeShort (short value)
87{
88 auto v = ByteOrder::swapIfBigEndian ((uint16) value);
89 return write (&v, 2);
90}
91
92bool OutputStream::writeShortBigEndian (short value)
93{
94 auto v = ByteOrder::swapIfLittleEndian ((uint16) value);
95 return write (&v, 2);
96}
97
98bool OutputStream::writeInt (int value)
99{
100 auto v = ByteOrder::swapIfBigEndian ((uint32) value);
101 return write (&v, 4);
102}
103
104bool OutputStream::writeIntBigEndian (int value)
105{
106 auto v = ByteOrder::swapIfLittleEndian ((uint32) value);
107 return write (&v, 4);
108}
109
110bool OutputStream::writeCompressedInt (int value)
111{
112 auto un = (value < 0) ? (unsigned int) -value
113 : (unsigned int) value;
114
115 uint8 data[5];
116 int num = 0;
117
118 while (un > 0)
119 {
120 data[++num] = (uint8) un;
121 un >>= 8;
122 }
123
124 data[0] = (uint8) num;
125
126 if (value < 0)
127 data[0] |= 0x80;
128
129 return write (data, (size_t) num + 1);
130}
131
132bool OutputStream::writeInt64 (int64 value)
133{
134 auto v = ByteOrder::swapIfBigEndian ((uint64) value);
135 return write (&v, 8);
136}
137
138bool OutputStream::writeInt64BigEndian (int64 value)
139{
140 auto v = ByteOrder::swapIfLittleEndian ((uint64) value);
141 return write (&v, 8);
142}
143
144bool OutputStream::writeFloat (float value)
145{
146 union { int asInt; float asFloat; } n;
147 n.asFloat = value;
148 return writeInt (n.asInt);
149}
150
151bool OutputStream::writeFloatBigEndian (float value)
152{
153 union { int asInt; float asFloat; } n;
154 n.asFloat = value;
155 return writeIntBigEndian (n.asInt);
156}
157
158bool OutputStream::writeDouble (double value)
159{
160 union { int64 asInt; double asDouble; } n;
161 n.asDouble = value;
162 return writeInt64 (n.asInt);
163}
164
165bool OutputStream::writeDoubleBigEndian (double value)
166{
167 union { int64 asInt; double asDouble; } n;
168 n.asDouble = value;
169 return writeInt64BigEndian (n.asInt);
170}
171
172bool OutputStream::writeString (const String& text)
173{
174 auto numBytes = text.getNumBytesAsUTF8() + 1;
175
176 #if (JUCE_STRING_UTF_TYPE == 8)
177 return write (text.toRawUTF8(), numBytes);
178 #else
179 // (This avoids using toUTF8() to prevent the memory bloat that it would leave behind
180 // if lots of large, persistent strings were to be written to streams).
181 HeapBlock<char> temp (numBytes);
182 text.copyToUTF8 (temp, numBytes);
183 return write (temp, numBytes);
184 #endif
185}
186
187bool OutputStream::writeText (const String& text, bool asUTF16, bool writeUTF16ByteOrderMark, const char* lf)
188{
189 bool replaceLineFeedWithUnix = lf != nullptr && lf[0] == '\n' && lf[1] == 0;
190 bool replaceLineFeedWithWindows = lf != nullptr && lf[0] == '\r' && lf[1] == '\n' && lf[2] == 0;
191
192 // The line-feed passed in must be either nullptr, or "\n" or "\r\n"
193 jassert (lf == nullptr || replaceLineFeedWithWindows || replaceLineFeedWithUnix);
194
195 if (asUTF16)
196 {
197 if (writeUTF16ByteOrderMark)
198 write ("\x0ff\x0fe", 2);
199
200 auto src = text.getCharPointer();
201 bool lastCharWasReturn = false;
202
203 for (;;)
204 {
205 auto c = src.getAndAdvance();
206
207 if (c == 0)
208 break;
209
210 if (replaceLineFeedWithWindows)
211 {
212 if (c == '\n' && ! lastCharWasReturn)
213 writeShort ((short) '\r');
214
215 lastCharWasReturn = (c == L'\r');
216 }
217 else if (replaceLineFeedWithUnix && c == '\r')
218 {
219 continue;
220 }
221
222 if (! writeShort ((short) c))
223 return false;
224 }
225 }
226 else
227 {
228 const char* src = text.toRawUTF8();
229
230 if (replaceLineFeedWithWindows)
231 {
232 for (auto t = src;;)
233 {
234 if (*t == '\n')
235 {
236 if (t > src)
237 if (! write (src, (size_t) (t - src)))
238 return false;
239
240 if (! write ("\r\n", 2))
241 return false;
242
243 src = t + 1;
244 }
245 else if (*t == '\r')
246 {
247 if (t[1] == '\n')
248 ++t;
249 }
250 else if (*t == 0)
251 {
252 if (t > src)
253 if (! write (src, (size_t) (t - src)))
254 return false;
255
256 break;
257 }
258
259 ++t;
260 }
261 }
262 else if (replaceLineFeedWithUnix)
263 {
264 for (;;)
265 {
266 auto c = *src++;
267
268 if (c == 0)
269 break;
270
271 if (c != '\r')
272 if (! writeByte (c))
273 return false;
274 }
275 }
276 else
277 {
278 return write (src, text.getNumBytesAsUTF8());
279 }
280 }
281
282 return true;
283}
284
285int64 OutputStream::writeFromInputStream (InputStream& source, int64 numBytesToWrite)
286{
287 if (numBytesToWrite < 0)
288 numBytesToWrite = std::numeric_limits<int64>::max();
289
290 int64 numWritten = 0;
291
292 while (numBytesToWrite > 0)
293 {
294 char buffer[8192];
295 auto num = source.read (buffer, (int) jmin (numBytesToWrite, (int64) sizeof (buffer)));
296
297 if (num <= 0)
298 break;
299
300 write (buffer, (size_t) num);
301
302 numBytesToWrite -= num;
303 numWritten += num;
304 }
305
306 return numWritten;
307}
308
309//==============================================================================
310void OutputStream::setNewLineString (const String& newLineStringToUse)
311{
312 newLineString = newLineStringToUse;
313}
314
315//==============================================================================
316template <typename IntegerType>
317static void writeIntToStream (OutputStream& stream, IntegerType number)
318{
319 char buffer[NumberToStringConverters::charsNeededForInt];
320 char* end = buffer + numElementsInArray (buffer);
321 const char* start = NumberToStringConverters::numberToString (end, number);
322 stream.write (start, (size_t) (end - start - 1));
323}
324
325JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const int number)
326{
327 writeIntToStream (stream, number);
328 return stream;
329}
330
331JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const int64 number)
332{
333 writeIntToStream (stream, number);
334 return stream;
335}
336
337JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const double number)
338{
339 return stream << String (number);
340}
341
342JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const char character)
343{
344 stream.writeByte (character);
345 return stream;
346}
347
348JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const char* const text)
349{
350 stream.write (text, strlen (text));
351 return stream;
352}
353
354JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const MemoryBlock& data)
355{
356 if (data.getSize() > 0)
357 stream.write (data.getData(), data.getSize());
358
359 return stream;
360}
361
362JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const File& fileToRead)
363{
364 FileInputStream in (fileToRead);
365
366 if (in.openedOk())
367 return stream << in;
368
369 return stream;
370}
371
372JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, InputStream& streamToRead)
373{
374 stream.writeFromInputStream (streamToRead, -1);
375 return stream;
376}
377
378JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const NewLine&)
379{
380 return stream << stream.getNewLineString();
381}
382
383} // namespace juce
juce_wchar getAndAdvance() noexcept
Returns the character that this pointer is currently pointing to, and then advances the pointer to po...
Very simple container class to hold a pointer to some data on the heap.
The base class for streams that read data.
virtual int read(void *destBuffer, int maxBytesToRead)=0
Reads some data from the stream into a memory buffer.
The base class for streams that write data to some kind of destination.
virtual bool write(const void *dataToWrite, size_t numberOfBytes)=0
Writes a block of data to the stream.
The JUCE String class!
Definition juce_String.h:43
CharPointerType getCharPointer() const noexcept
Returns the character pointer currently being used to store this string.
const char * toRawUTF8() const
Returns a pointer to a UTF-8 version of this string.
size_t getNumBytesAsUTF8() const noexcept
Returns the number of bytes required to represent this string as UTF8.
size_t copyToUTF8(CharPointer_UTF8::CharType *destBuffer, size_t maxBufferSizeBytes) const noexcept
Copies the string to a buffer as UTF-8 characters.
#define JUCE_API
This macro is added to all JUCE public class declarations.