OpenShot Audio Library | OpenShotAudio  0.3.2
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 
23 namespace juce
24 {
25 
26 #if JUCE_DEBUG
27 
28 //==============================================================================
29 struct DanglingStreamChecker
30 {
31  DanglingStreamChecker() = default;
32 
33  ~DanglingStreamChecker()
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 
48  Array<void*, CriticalSection> activeStreams;
49 
50  static bool hasBeenDestroyed;
51 };
52 
53 bool DanglingStreamChecker::hasBeenDestroyed = false;
54 static DanglingStreamChecker danglingStreamChecker;
55 
56 #endif
57 
58 //==============================================================================
59 OutputStream::OutputStream()
60  : newLineString (NewLine::getDefault())
61 {
62  #if JUCE_DEBUG
63  if (! DanglingStreamChecker::hasBeenDestroyed)
64  danglingStreamChecker.activeStreams.add (this);
65  #endif
66 }
67 
68 OutputStream::~OutputStream()
69 {
70  #if JUCE_DEBUG
71  if (! DanglingStreamChecker::hasBeenDestroyed)
72  danglingStreamChecker.activeStreams.removeFirstMatchingValue (this);
73  #endif
74 }
75 
76 //==============================================================================
77 bool OutputStream::writeBool (bool b)
78 {
79  return writeByte (b ? (char) 1
80  : (char) 0);
81 }
82 
83 bool OutputStream::writeByte (char byte)
84 {
85  return write (&byte, 1);
86 }
87 
88 bool 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 
97 bool OutputStream::writeShort (short value)
98 {
99  auto v = ByteOrder::swapIfBigEndian ((uint16) value);
100  return write (&v, 2);
101 }
102 
103 bool OutputStream::writeShortBigEndian (short value)
104 {
105  auto v = ByteOrder::swapIfLittleEndian ((uint16) value);
106  return write (&v, 2);
107 }
108 
109 bool OutputStream::writeInt (int value)
110 {
111  auto v = ByteOrder::swapIfBigEndian ((uint32) value);
112  return write (&v, 4);
113 }
114 
115 bool OutputStream::writeIntBigEndian (int value)
116 {
117  auto v = ByteOrder::swapIfLittleEndian ((uint32) value);
118  return write (&v, 4);
119 }
120 
121 bool 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 
143 bool OutputStream::writeInt64 (int64 value)
144 {
145  auto v = ByteOrder::swapIfBigEndian ((uint64) value);
146  return write (&v, 8);
147 }
148 
149 bool OutputStream::writeInt64BigEndian (int64 value)
150 {
151  auto v = ByteOrder::swapIfLittleEndian ((uint64) value);
152  return write (&v, 8);
153 }
154 
155 bool OutputStream::writeFloat (float value)
156 {
157  union { int asInt; float asFloat; } n;
158  n.asFloat = value;
159  return writeInt (n.asInt);
160 }
161 
162 bool OutputStream::writeFloatBigEndian (float value)
163 {
164  union { int asInt; float asFloat; } n;
165  n.asFloat = value;
166  return writeIntBigEndian (n.asInt);
167 }
168 
169 bool OutputStream::writeDouble (double value)
170 {
171  union { int64 asInt; double asDouble; } n;
172  n.asDouble = value;
173  return writeInt64 (n.asInt);
174 }
175 
176 bool OutputStream::writeDoubleBigEndian (double value)
177 {
178  union { int64 asInt; double asDouble; } n;
179  n.asDouble = value;
180  return writeInt64BigEndian (n.asInt);
181 }
182 
183 bool 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 
198 bool 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  {
208  if (writeUTF16ByteOrderMark)
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 
221  if (replaceLineFeedWithWindows)
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 
241  if (replaceLineFeedWithWindows)
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  }
273  else if (replaceLineFeedWithUnix)
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 
296 int64 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 
313  numBytesToWrite -= num;
314  numWritten += num;
315  }
316 
317  return numWritten;
318 }
319 
320 //==============================================================================
321 void OutputStream::setNewLineString (const String& newLineStringToUse)
322 {
323  newLineString = newLineStringToUse;
324 }
325 
326 //==============================================================================
327 template <typename IntegerType>
328 static 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 
336 JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const int number)
337 {
338  writeIntToStream (stream, number);
339  return stream;
340 }
341 
342 JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const int64 number)
343 {
344  writeIntToStream (stream, number);
345  return stream;
346 }
347 
348 JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const double number)
349 {
350  return stream << String (number);
351 }
352 
353 JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const char character)
354 {
355  stream.writeByte (character);
356  return stream;
357 }
358 
359 JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const char* const text)
360 {
361  stream.write (text, strlen (text));
362  return stream;
363 }
364 
365 JUCE_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 
373 JUCE_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 
383 JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, InputStream& streamToRead)
384 {
385  stream.writeFromInputStream (streamToRead, -1);
386  return stream;
387 }
388 
389 JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const NewLine&)
390 {
391  return stream << stream.getNewLineString();
392 }
393 
394 } // namespace juce
virtual int read(void *destBuffer, int maxBytesToRead)=0
virtual bool write(const void *dataToWrite, size_t numberOfBytes)=0
CharPointerType getCharPointer() const noexcept
Definition: juce_String.h:1198
const char * toRawUTF8() const
size_t getNumBytesAsUTF8() const noexcept
size_t copyToUTF8(CharPointer_UTF8::CharType *destBuffer, size_t maxBufferSizeBytes) const noexcept