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 
23 namespace juce
24 {
25 
26 #if JUCE_DEBUG
27 
28 struct 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 
46 static DanglingStreamChecker danglingStreamChecker;
47 #endif
48 
49 //==============================================================================
50 OutputStream::OutputStream()
51  : newLineString (NewLine::getDefault())
52 {
53  #if JUCE_DEBUG
54  danglingStreamChecker.activeStreams.add (this);
55  #endif
56 }
57 
58 OutputStream::~OutputStream()
59 {
60  #if JUCE_DEBUG
61  danglingStreamChecker.activeStreams.removeFirstMatchingValue (this);
62  #endif
63 }
64 
65 //==============================================================================
66 bool OutputStream::writeBool (bool b)
67 {
68  return writeByte (b ? (char) 1
69  : (char) 0);
70 }
71 
72 bool OutputStream::writeByte (char byte)
73 {
74  return write (&byte, 1);
75 }
76 
77 bool 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 
86 bool OutputStream::writeShort (short value)
87 {
88  auto v = ByteOrder::swapIfBigEndian ((uint16) value);
89  return write (&v, 2);
90 }
91 
92 bool OutputStream::writeShortBigEndian (short value)
93 {
94  auto v = ByteOrder::swapIfLittleEndian ((uint16) value);
95  return write (&v, 2);
96 }
97 
98 bool OutputStream::writeInt (int value)
99 {
100  auto v = ByteOrder::swapIfBigEndian ((uint32) value);
101  return write (&v, 4);
102 }
103 
104 bool OutputStream::writeIntBigEndian (int value)
105 {
106  auto v = ByteOrder::swapIfLittleEndian ((uint32) value);
107  return write (&v, 4);
108 }
109 
110 bool 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 
132 bool OutputStream::writeInt64 (int64 value)
133 {
134  auto v = ByteOrder::swapIfBigEndian ((uint64) value);
135  return write (&v, 8);
136 }
137 
138 bool OutputStream::writeInt64BigEndian (int64 value)
139 {
140  auto v = ByteOrder::swapIfLittleEndian ((uint64) value);
141  return write (&v, 8);
142 }
143 
144 bool OutputStream::writeFloat (float value)
145 {
146  union { int asInt; float asFloat; } n;
147  n.asFloat = value;
148  return writeInt (n.asInt);
149 }
150 
151 bool OutputStream::writeFloatBigEndian (float value)
152 {
153  union { int asInt; float asFloat; } n;
154  n.asFloat = value;
155  return writeIntBigEndian (n.asInt);
156 }
157 
158 bool OutputStream::writeDouble (double value)
159 {
160  union { int64 asInt; double asDouble; } n;
161  n.asDouble = value;
162  return writeInt64 (n.asInt);
163 }
164 
165 bool OutputStream::writeDoubleBigEndian (double value)
166 {
167  union { int64 asInt; double asDouble; } n;
168  n.asDouble = value;
169  return writeInt64BigEndian (n.asInt);
170 }
171 
172 bool 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 
187 bool 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 
285 int64 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 //==============================================================================
310 void OutputStream::setNewLineString (const String& newLineStringToUse)
311 {
312  newLineString = newLineStringToUse;
313 }
314 
315 //==============================================================================
316 template <typename IntegerType>
317 static 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 
325 JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const int number)
326 {
327  writeIntToStream (stream, number);
328  return stream;
329 }
330 
331 JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const int64 number)
332 {
333  writeIntToStream (stream, number);
334  return stream;
335 }
336 
337 JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const double number)
338 {
339  return stream << String (number);
340 }
341 
342 JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const char character)
343 {
344  stream.writeByte (character);
345  return stream;
346 }
347 
348 JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const char* const text)
349 {
350  stream.write (text, strlen (text));
351  return stream;
352 }
353 
354 JUCE_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 
362 JUCE_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 
372 JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, InputStream& streamToRead)
373 {
374  stream.writeFromInputStream (streamToRead, -1);
375  return stream;
376 }
377 
378 JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const NewLine&)
379 {
380  return stream << stream.getNewLineString();
381 }
382 
383 } // namespace juce
juce::String::toRawUTF8
const char * toRawUTF8() const
Returns a pointer to a UTF-8 version of this string.
Definition: juce_String.cpp:2072
juce::HeapBlock< char >
juce::InputStream
The base class for streams that read data.
Definition: juce_InputStream.h:40
juce::InputStream::read
virtual int read(void *destBuffer, int maxBytesToRead)=0
Reads some data from the stream into a memory buffer.
juce::String::getCharPointer
CharPointerType getCharPointer() const noexcept
Returns the character pointer currently being used to store this string.
Definition: juce_String.h:1200
juce::String::getNumBytesAsUTF8
size_t getNumBytesAsUTF8() const noexcept
Returns the number of bytes required to represent this string as UTF8.
Definition: juce_String.cpp:2118
JUCE_API
#define JUCE_API
This macro is added to all JUCE public class declarations.
Definition: juce_StandardHeader.h:143
juce::OutputStream::write
virtual bool write(const void *dataToWrite, size_t numberOfBytes)=0
Writes a block of data to the stream.
juce::OutputStream
The base class for streams that write data to some kind of destination.
Definition: juce_OutputStream.h:41
juce::String::copyToUTF8
size_t copyToUTF8(CharPointer_UTF8::CharType *destBuffer, size_t maxBufferSizeBytes) const noexcept
Copies the string to a buffer as UTF-8 characters.
Definition: juce_String.cpp:2102
juce::String
The JUCE String class!
Definition: juce_String.h:42
juce::CharPointer_UTF8::getAndAdvance
juce_wchar getAndAdvance() noexcept
Returns the character that this pointer is currently pointing to, and then advances the pointer to po...
Definition: juce_CharPointer_UTF8.h:151