|
- /*
- ==============================================================================
-
- This file is part of the JUCE library.
- Copyright (c) 2020 - Raw Material Software Limited
-
- JUCE is an open source library subject to commercial or open-source
- licensing.
-
- The code included in this file is provided under the terms of the ISC license
- http://www.isc.org/downloads/software-support-policy/isc-license. Permission
- To use, copy, modify, and/or distribute this software for any purpose with or
- without fee is hereby granted provided that the above copyright notice and
- this permission notice appear in all copies.
-
- JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
- EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
- DISCLAIMED.
-
- ==============================================================================
- */
-
- namespace juce
- {
-
- #if JUCE_DEBUG
-
- //==============================================================================
- struct DanglingStreamChecker
- {
- DanglingStreamChecker() = default;
-
- ~DanglingStreamChecker()
- {
- /*
- It's always a bad idea to leak any object, but if you're leaking output
- streams, then there's a good chance that you're failing to flush a file
- to disk properly, which could result in corrupted data and other similar
- nastiness..
- */
- jassert (activeStreams.size() == 0);
-
- // We need to flag when this helper struct has been destroyed to prevent some
- // nasty order-of-static-destruction issues
- hasBeenDestroyed = true;
- }
-
- Array<void*, CriticalSection> activeStreams;
-
- static bool hasBeenDestroyed;
- };
-
- bool DanglingStreamChecker::hasBeenDestroyed = false;
- static DanglingStreamChecker danglingStreamChecker;
-
- #endif
-
- //==============================================================================
- OutputStream::OutputStream()
- : newLineString (NewLine::getDefault())
- {
- #if JUCE_DEBUG
- if (! DanglingStreamChecker::hasBeenDestroyed)
- danglingStreamChecker.activeStreams.add (this);
- #endif
- }
-
- OutputStream::~OutputStream()
- {
- #if JUCE_DEBUG
- if (! DanglingStreamChecker::hasBeenDestroyed)
- danglingStreamChecker.activeStreams.removeFirstMatchingValue (this);
- #endif
- }
-
- //==============================================================================
- bool OutputStream::writeBool (bool b)
- {
- return writeByte (b ? (char) 1
- : (char) 0);
- }
-
- bool OutputStream::writeByte (char byte)
- {
- return write (&byte, 1);
- }
-
- bool OutputStream::writeRepeatedByte (uint8 byte, size_t numTimesToRepeat)
- {
- for (size_t i = 0; i < numTimesToRepeat; ++i)
- if (! writeByte ((char) byte))
- return false;
-
- return true;
- }
-
- bool OutputStream::writeShort (short value)
- {
- auto v = ByteOrder::swapIfBigEndian ((uint16) value);
- return write (&v, 2);
- }
-
- bool OutputStream::writeShortBigEndian (short value)
- {
- auto v = ByteOrder::swapIfLittleEndian ((uint16) value);
- return write (&v, 2);
- }
-
- bool OutputStream::writeInt (int value)
- {
- auto v = ByteOrder::swapIfBigEndian ((uint32) value);
- return write (&v, 4);
- }
-
- bool OutputStream::writeIntBigEndian (int value)
- {
- auto v = ByteOrder::swapIfLittleEndian ((uint32) value);
- return write (&v, 4);
- }
-
- bool OutputStream::writeCompressedInt (int value)
- {
- auto un = (value < 0) ? (unsigned int) -value
- : (unsigned int) value;
-
- uint8 data[5];
- int num = 0;
-
- while (un > 0)
- {
- data[++num] = (uint8) un;
- un >>= 8;
- }
-
- data[0] = (uint8) num;
-
- if (value < 0)
- data[0] |= 0x80;
-
- return write (data, (size_t) num + 1);
- }
-
- bool OutputStream::writeInt64 (int64 value)
- {
- auto v = ByteOrder::swapIfBigEndian ((uint64) value);
- return write (&v, 8);
- }
-
- bool OutputStream::writeInt64BigEndian (int64 value)
- {
- auto v = ByteOrder::swapIfLittleEndian ((uint64) value);
- return write (&v, 8);
- }
-
- bool OutputStream::writeFloat (float value)
- {
- union { int asInt; float asFloat; } n;
- n.asFloat = value;
- return writeInt (n.asInt);
- }
-
- bool OutputStream::writeFloatBigEndian (float value)
- {
- union { int asInt; float asFloat; } n;
- n.asFloat = value;
- return writeIntBigEndian (n.asInt);
- }
-
- bool OutputStream::writeDouble (double value)
- {
- union { int64 asInt; double asDouble; } n;
- n.asDouble = value;
- return writeInt64 (n.asInt);
- }
-
- bool OutputStream::writeDoubleBigEndian (double value)
- {
- union { int64 asInt; double asDouble; } n;
- n.asDouble = value;
- return writeInt64BigEndian (n.asInt);
- }
-
- bool OutputStream::writeString (const String& text)
- {
- auto numBytes = text.getNumBytesAsUTF8() + 1;
-
- #if (JUCE_STRING_UTF_TYPE == 8)
- return write (text.toRawUTF8(), numBytes);
- #else
- // (This avoids using toUTF8() to prevent the memory bloat that it would leave behind
- // if lots of large, persistent strings were to be written to streams).
- HeapBlock<char> temp (numBytes);
- text.copyToUTF8 (temp, numBytes);
- return write (temp, numBytes);
- #endif
- }
-
- bool OutputStream::writeText (const String& text, bool asUTF16, bool writeUTF16ByteOrderMark, const char* lf)
- {
- bool replaceLineFeedWithUnix = lf != nullptr && lf[0] == '\n' && lf[1] == 0;
- bool replaceLineFeedWithWindows = lf != nullptr && lf[0] == '\r' && lf[1] == '\n' && lf[2] == 0;
-
- // The line-feed passed in must be either nullptr, or "\n" or "\r\n"
- jassert (lf == nullptr || replaceLineFeedWithWindows || replaceLineFeedWithUnix);
-
- if (asUTF16)
- {
- if (writeUTF16ByteOrderMark)
- write ("\x0ff\x0fe", 2);
-
- auto src = text.getCharPointer();
- bool lastCharWasReturn = false;
-
- for (;;)
- {
- auto c = src.getAndAdvance();
-
- if (c == 0)
- break;
-
- if (replaceLineFeedWithWindows)
- {
- if (c == '\n' && ! lastCharWasReturn)
- writeShort ((short) '\r');
-
- lastCharWasReturn = (c == L'\r');
- }
- else if (replaceLineFeedWithUnix && c == '\r')
- {
- continue;
- }
-
- if (! writeShort ((short) c))
- return false;
- }
- }
- else
- {
- const char* src = text.toRawUTF8();
-
- if (replaceLineFeedWithWindows)
- {
- for (auto t = src;;)
- {
- if (*t == '\n')
- {
- if (t > src)
- if (! write (src, (size_t) (t - src)))
- return false;
-
- if (! write ("\r\n", 2))
- return false;
-
- src = t + 1;
- }
- else if (*t == '\r')
- {
- if (t[1] == '\n')
- ++t;
- }
- else if (*t == 0)
- {
- if (t > src)
- if (! write (src, (size_t) (t - src)))
- return false;
-
- break;
- }
-
- ++t;
- }
- }
- else if (replaceLineFeedWithUnix)
- {
- for (;;)
- {
- auto c = *src++;
-
- if (c == 0)
- break;
-
- if (c != '\r')
- if (! writeByte (c))
- return false;
- }
- }
- else
- {
- return write (src, text.getNumBytesAsUTF8());
- }
- }
-
- return true;
- }
-
- int64 OutputStream::writeFromInputStream (InputStream& source, int64 numBytesToWrite)
- {
- if (numBytesToWrite < 0)
- numBytesToWrite = std::numeric_limits<int64>::max();
-
- int64 numWritten = 0;
-
- while (numBytesToWrite > 0)
- {
- char buffer[8192];
- auto num = source.read (buffer, (int) jmin (numBytesToWrite, (int64) sizeof (buffer)));
-
- if (num <= 0)
- break;
-
- write (buffer, (size_t) num);
-
- numBytesToWrite -= num;
- numWritten += num;
- }
-
- return numWritten;
- }
-
- //==============================================================================
- void OutputStream::setNewLineString (const String& newLineStringToUse)
- {
- newLineString = newLineStringToUse;
- }
-
- //==============================================================================
- template <typename IntegerType>
- static void writeIntToStream (OutputStream& stream, IntegerType number)
- {
- char buffer[NumberToStringConverters::charsNeededForInt];
- char* end = buffer + numElementsInArray (buffer);
- const char* start = NumberToStringConverters::numberToString (end, number);
- stream.write (start, (size_t) (end - start - 1));
- }
-
- JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const int number)
- {
- writeIntToStream (stream, number);
- return stream;
- }
-
- JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const int64 number)
- {
- writeIntToStream (stream, number);
- return stream;
- }
-
- JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const double number)
- {
- return stream << String (number);
- }
-
- JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const char character)
- {
- stream.writeByte (character);
- return stream;
- }
-
- JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const char* const text)
- {
- stream.write (text, strlen (text));
- return stream;
- }
-
- JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const MemoryBlock& data)
- {
- if (! data.isEmpty())
- stream.write (data.getData(), data.getSize());
-
- return stream;
- }
-
- JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const File& fileToRead)
- {
- FileInputStream in (fileToRead);
-
- if (in.openedOk())
- return stream << in;
-
- return stream;
- }
-
- JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, InputStream& streamToRead)
- {
- stream.writeFromInputStream (streamToRead, -1);
- return stream;
- }
-
- JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const NewLine&)
- {
- return stream << stream.getNewLineString();
- }
-
- } // namespace juce
|