/* ============================================================================== This file is part of the JUCE library - "Jules' Utility Class Extensions" Copyright 2004-9 by Raw Material Software Ltd. ------------------------------------------------------------------------------ JUCE can be redistributed and/or modified under the terms of the GNU General Public License (Version 2), as published by the Free Software Foundation. A copy of the license is included in the JUCE distribution, or can be found online at www.gnu.org/licenses. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ------------------------------------------------------------------------------ To release a closed-source product which uses JUCE, commercial licenses are available: visit www.rawmaterialsoftware.com/juce for more information. ============================================================================== */ #include "../../core/juce_StandardHeader.h" BEGIN_JUCE_NAMESPACE #include "juce_OutputStream.h" #include "../../threads/juce_CriticalSection.h" #include "../../containers/juce_VoidArray.h" //============================================================================== #if JUCE_DEBUG static CriticalSection activeStreamLock; static VoidArray activeStreams; void juce_CheckForDanglingStreams() { /* 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); }; #endif //============================================================================== OutputStream::OutputStream() throw() { #if JUCE_DEBUG activeStreamLock.enter(); activeStreams.add (this); activeStreamLock.exit(); #endif } OutputStream::~OutputStream() { #if JUCE_DEBUG activeStreamLock.enter(); activeStreams.removeValue (this); activeStreamLock.exit(); #endif } //============================================================================== void OutputStream::writeBool (bool b) { writeByte ((b) ? (char) 1 : (char) 0); } void OutputStream::writeByte (char byte) { write (&byte, 1); } void OutputStream::writeShort (short value) { const unsigned short v = ByteOrder::swapIfBigEndian ((unsigned short) value); write (&v, 2); } void OutputStream::writeShortBigEndian (short value) { const unsigned short v = ByteOrder::swapIfLittleEndian ((unsigned short) value); write (&v, 2); } void OutputStream::writeInt (int value) { const unsigned int v = ByteOrder::swapIfBigEndian ((unsigned int) value); write (&v, 4); } void OutputStream::writeIntBigEndian (int value) { const unsigned int v = ByteOrder::swapIfLittleEndian ((unsigned int) value); write (&v, 4); } void OutputStream::writeCompressedInt (int value) { unsigned int 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; write (data, num + 1); } void OutputStream::writeInt64 (int64 value) { const uint64 v = ByteOrder::swapIfBigEndian ((uint64) value); write (&v, 8); } void OutputStream::writeInt64BigEndian (int64 value) { const uint64 v = ByteOrder::swapIfLittleEndian ((uint64) value); write (&v, 8); } void OutputStream::writeFloat (float value) { union { int asInt; float asFloat; } n; n.asFloat = value; writeInt (n.asInt); } void OutputStream::writeFloatBigEndian (float value) { union { int asInt; float asFloat; } n; n.asFloat = value; writeIntBigEndian (n.asInt); } void OutputStream::writeDouble (double value) { union { int64 asInt; double asDouble; } n; n.asDouble = value; writeInt64 (n.asInt); } void OutputStream::writeDoubleBigEndian (double value) { union { int64 asInt; double asDouble; } n; n.asDouble = value; writeInt64BigEndian (n.asInt); } void OutputStream::writeString (const String& text) { const int numBytes = text.copyToUTF8 (0); HeapBlock temp (numBytes); text.copyToUTF8 (temp); write (temp, numBytes); // (numBytes includes the terminating null). } void OutputStream::printf (const char* pf, ...) { unsigned int bufSize = 256; HeapBlock buf (bufSize); for (;;) { va_list list; va_start (list, pf); const int num = CharacterFunctions::vprintf (buf, bufSize, pf, list); va_end (list); if (num > 0) { write (buf, num); break; } else if (num == 0) { break; } bufSize += 256; buf.malloc (bufSize); } } OutputStream& OutputStream::operator<< (const int number) { const String s (number); write ((const char*) s, s.length()); return *this; } OutputStream& OutputStream::operator<< (const double number) { const String s (number); write ((const char*) s, s.length()); return *this; } OutputStream& OutputStream::operator<< (const char character) { writeByte (character); return *this; } OutputStream& OutputStream::operator<< (const char* const text) { write (text, (int) strlen (text)); return *this; } OutputStream& OutputStream::operator<< (const juce_wchar* const text) { const String s (text); write ((const char*) s, s.length()); return *this; } OutputStream& OutputStream::operator<< (const String& text) { write ((const char*) text, text.length()); return *this; } void OutputStream::writeText (const String& text, const bool asUnicode, const bool writeUnicodeHeaderBytes) { if (asUnicode) { if (writeUnicodeHeaderBytes) write ("\x0ff\x0fe", 2); const juce_wchar* src = (const juce_wchar*) text; bool lastCharWasReturn = false; while (*src != 0) { if (*src == L'\n' && ! lastCharWasReturn) writeShort ((short) L'\r'); lastCharWasReturn = (*src == L'\r'); writeShort ((short) *src++); } } else { const char* src = (const char*) text; const char* t = src; for (;;) { if (*t == '\n') { if (t > src) write (src, (int) (t - src)); write ("\r\n", 2); src = t + 1; } else if (*t == '\r') { if (t[1] == '\n') ++t; } else if (*t == 0) { if (t > src) write (src, (int) (t - src)); break; } ++t; } } } int OutputStream::writeFromInputStream (InputStream& source, int numBytesToWrite) { if (numBytesToWrite < 0) numBytesToWrite = 0x7fffffff; int numWritten = 0; while (numBytesToWrite > 0 && ! source.isExhausted()) { char buffer [8192]; const int num = source.read (buffer, jmin (numBytesToWrite, sizeof (buffer))); if (num == 0) break; write (buffer, num); numBytesToWrite -= num; numWritten += num; } return numWritten; } END_JUCE_NAMESPACE