OpenShot Audio Library | OpenShotAudio 0.3.2
Loading...
Searching...
No Matches
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
28//==============================================================================
29struct DanglingStreamChecker
30{
31 DanglingStreamChecker() = default;
32
34 {
35 /*
36 It's always a bad idea to leak any object, but if you're leaking output
37 streams, then there's a good chance that you're failing to flush a file
38 to disk properly, which could result in corrupted data and other similar
39 nastiness..
40 */
41 jassert (activeStreams.size() == 0);
42
43 // We need to flag when this helper struct has been destroyed to prevent some
44 // nasty order-of-static-destruction issues
45 hasBeenDestroyed = true;
46 }
47
49
50 static bool hasBeenDestroyed;
51};
52
53bool DanglingStreamChecker::hasBeenDestroyed = false;
54static DanglingStreamChecker danglingStreamChecker;
55
56#endif
57
58//==============================================================================
59OutputStream::OutputStream()
60 : newLineString (NewLine::getDefault())
61{
62 #if JUCE_DEBUG
63 if (! DanglingStreamChecker::hasBeenDestroyed)
64 danglingStreamChecker.activeStreams.add (this);
65 #endif
66}
67
68OutputStream::~OutputStream()
69{
70 #if JUCE_DEBUG
71 if (! DanglingStreamChecker::hasBeenDestroyed)
73 #endif
74}
75
76//==============================================================================
77bool OutputStream::writeBool (bool b)
78{
79 return writeByte (b ? (char) 1
80 : (char) 0);
81}
82
83bool OutputStream::writeByte (char byte)
84{
85 return write (&byte, 1);
86}
87
88bool OutputStream::writeRepeatedByte (uint8 byte, size_t numTimesToRepeat)
89{
90 for (size_t i = 0; i < numTimesToRepeat; ++i)
91 if (! writeByte ((char) byte))
92 return false;
93
94 return true;
95}
96
97bool OutputStream::writeShort (short value)
98{
99 auto v = ByteOrder::swapIfBigEndian ((uint16) value);
100 return write (&v, 2);
101}
102
103bool OutputStream::writeShortBigEndian (short value)
104{
105 auto v = ByteOrder::swapIfLittleEndian ((uint16) value);
106 return write (&v, 2);
107}
108
109bool OutputStream::writeInt (int value)
110{
111 auto v = ByteOrder::swapIfBigEndian ((uint32) value);
112 return write (&v, 4);
113}
114
115bool OutputStream::writeIntBigEndian (int value)
116{
117 auto v = ByteOrder::swapIfLittleEndian ((uint32) value);
118 return write (&v, 4);
119}
120
121bool OutputStream::writeCompressedInt (int value)
122{
123 auto un = (value < 0) ? (unsigned int) -value
124 : (unsigned int) value;
125
126 uint8 data[5];
127 int num = 0;
128
129 while (un > 0)
130 {
131 data[++num] = (uint8) un;
132 un >>= 8;
133 }
134
135 data[0] = (uint8) num;
136
137 if (value < 0)
138 data[0] |= 0x80;
139
140 return write (data, (size_t) num + 1);
141}
142
143bool OutputStream::writeInt64 (int64 value)
144{
145 auto v = ByteOrder::swapIfBigEndian ((uint64) value);
146 return write (&v, 8);
147}
148
149bool OutputStream::writeInt64BigEndian (int64 value)
150{
151 auto v = ByteOrder::swapIfLittleEndian ((uint64) value);
152 return write (&v, 8);
153}
154
155bool OutputStream::writeFloat (float value)
156{
157 union { int asInt; float asFloat; } n;
158 n.asFloat = value;
159 return writeInt (n.asInt);
160}
161
162bool OutputStream::writeFloatBigEndian (float value)
163{
164 union { int asInt; float asFloat; } n;
165 n.asFloat = value;
166 return writeIntBigEndian (n.asInt);
167}
168
169bool OutputStream::writeDouble (double value)
170{
171 union { int64 asInt; double asDouble; } n;
172 n.asDouble = value;
173 return writeInt64 (n.asInt);
174}
175
176bool OutputStream::writeDoubleBigEndian (double value)
177{
178 union { int64 asInt; double asDouble; } n;
179 n.asDouble = value;
180 return writeInt64BigEndian (n.asInt);
181}
182
183bool OutputStream::writeString (const String& text)
184{
185 auto numBytes = text.getNumBytesAsUTF8() + 1;
186
187 #if (JUCE_STRING_UTF_TYPE == 8)
188 return write (text.toRawUTF8(), numBytes);
189 #else
190 // (This avoids using toUTF8() to prevent the memory bloat that it would leave behind
191 // if lots of large, persistent strings were to be written to streams).
192 HeapBlock<char> temp (numBytes);
193 text.copyToUTF8 (temp, numBytes);
194 return write (temp, numBytes);
195 #endif
196}
197
198bool OutputStream::writeText (const String& text, bool asUTF16, bool writeUTF16ByteOrderMark, const char* lf)
199{
200 bool replaceLineFeedWithUnix = lf != nullptr && lf[0] == '\n' && lf[1] == 0;
201 bool replaceLineFeedWithWindows = lf != nullptr && lf[0] == '\r' && lf[1] == '\n' && lf[2] == 0;
202
203 // The line-feed passed in must be either nullptr, or "\n" or "\r\n"
204 jassert (lf == nullptr || replaceLineFeedWithWindows || replaceLineFeedWithUnix);
205
206 if (asUTF16)
207 {
209 write ("\x0ff\x0fe", 2);
210
211 auto src = text.getCharPointer();
212 bool lastCharWasReturn = false;
213
214 for (;;)
215 {
216 auto c = src.getAndAdvance();
217
218 if (c == 0)
219 break;
220
222 {
223 if (c == '\n' && ! lastCharWasReturn)
224 writeShort ((short) '\r');
225
226 lastCharWasReturn = (c == L'\r');
227 }
228 else if (replaceLineFeedWithUnix && c == '\r')
229 {
230 continue;
231 }
232
233 if (! writeShort ((short) c))
234 return false;
235 }
236 }
237 else
238 {
239 const char* src = text.toRawUTF8();
240
242 {
243 for (auto t = src;;)
244 {
245 if (*t == '\n')
246 {
247 if (t > src)
248 if (! write (src, (size_t) (t - src)))
249 return false;
250
251 if (! write ("\r\n", 2))
252 return false;
253
254 src = t + 1;
255 }
256 else if (*t == '\r')
257 {
258 if (t[1] == '\n')
259 ++t;
260 }
261 else if (*t == 0)
262 {
263 if (t > src)
264 if (! write (src, (size_t) (t - src)))
265 return false;
266
267 break;
268 }
269
270 ++t;
271 }
272 }
274 {
275 for (;;)
276 {
277 auto c = *src++;
278
279 if (c == 0)
280 break;
281
282 if (c != '\r')
283 if (! writeByte (c))
284 return false;
285 }
286 }
287 else
288 {
289 return write (src, text.getNumBytesAsUTF8());
290 }
291 }
292
293 return true;
294}
295
296int64 OutputStream::writeFromInputStream (InputStream& source, int64 numBytesToWrite)
297{
298 if (numBytesToWrite < 0)
299 numBytesToWrite = std::numeric_limits<int64>::max();
300
301 int64 numWritten = 0;
302
303 while (numBytesToWrite > 0)
304 {
305 char buffer[8192];
306 auto num = source.read (buffer, (int) jmin (numBytesToWrite, (int64) sizeof (buffer)));
307
308 if (num <= 0)
309 break;
310
311 write (buffer, (size_t) num);
312
314 numWritten += num;
315 }
316
317 return numWritten;
318}
319
320//==============================================================================
321void OutputStream::setNewLineString (const String& newLineStringToUse)
322{
323 newLineString = newLineStringToUse;
324}
325
326//==============================================================================
327template <typename IntegerType>
328static void writeIntToStream (OutputStream& stream, IntegerType number)
329{
330 char buffer[NumberToStringConverters::charsNeededForInt];
331 char* end = buffer + numElementsInArray (buffer);
332 const char* start = NumberToStringConverters::numberToString (end, number);
333 stream.write (start, (size_t) (end - start - 1));
334}
335
336JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const int number)
337{
338 writeIntToStream (stream, number);
339 return stream;
340}
341
342JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const int64 number)
343{
344 writeIntToStream (stream, number);
345 return stream;
346}
347
348JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const double number)
349{
350 return stream << String (number);
351}
352
353JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const char character)
354{
355 stream.writeByte (character);
356 return stream;
357}
358
359JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const char* const text)
360{
361 stream.write (text, strlen (text));
362 return stream;
363}
364
365JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const MemoryBlock& data)
366{
367 if (data.getSize() > 0)
368 stream.write (data.getData(), data.getSize());
369
370 return stream;
371}
372
373JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const File& fileToRead)
374{
375 FileInputStream in (fileToRead);
376
377 if (in.openedOk())
378 return stream << in;
379
380 return stream;
381}
382
383JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, InputStream& streamToRead)
384{
385 stream.writeFromInputStream (streamToRead, -1);
386 return stream;
387}
388
389JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const NewLine&)
390{
391 return stream << stream.getNewLineString();
392}
393
394} // namespace juce
void removeFirstMatchingValue(ParameterType valueToRemove)
Definition juce_Array.h:834
Array()=default
virtual int read(void *destBuffer, int maxBytesToRead)=0
virtual bool write(const void *dataToWrite, size_t numberOfBytes)=0
CharPointerType getCharPointer() const noexcept
const char * toRawUTF8() const
size_t getNumBytesAsUTF8() const noexcept
size_t copyToUTF8(CharPointer_UTF8::CharType *destBuffer, size_t maxBufferSizeBytes) const noexcept