The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

297 lines
7.7KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-10 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #include "../../core/juce_StandardHeader.h"
  19. BEGIN_JUCE_NAMESPACE
  20. #include "juce_OutputStream.h"
  21. #include "../../threads/juce_ScopedLock.h"
  22. #include "../../containers/juce_Array.h"
  23. #include "../../containers/juce_ScopedPointer.h"
  24. #include "../files/juce_FileInputStream.h"
  25. //==============================================================================
  26. #if JUCE_DEBUG
  27. static CriticalSection activeStreamLock;
  28. static Array<void*> activeStreams;
  29. void juce_CheckForDanglingStreams()
  30. {
  31. /*
  32. It's always a bad idea to leak any object, but if you're leaking output
  33. streams, then there's a good chance that you're failing to flush a file
  34. to disk properly, which could result in corrupted data and other similar
  35. nastiness..
  36. */
  37. jassert (activeStreams.size() == 0);
  38. };
  39. #endif
  40. //==============================================================================
  41. OutputStream::OutputStream()
  42. {
  43. #if JUCE_DEBUG
  44. const ScopedLock sl (activeStreamLock);
  45. activeStreams.add (this);
  46. #endif
  47. }
  48. OutputStream::~OutputStream()
  49. {
  50. #if JUCE_DEBUG
  51. const ScopedLock sl (activeStreamLock);
  52. activeStreams.removeValue (this);
  53. #endif
  54. }
  55. //==============================================================================
  56. void OutputStream::writeBool (const bool b)
  57. {
  58. writeByte (b ? (char) 1
  59. : (char) 0);
  60. }
  61. void OutputStream::writeByte (char byte)
  62. {
  63. write (&byte, 1);
  64. }
  65. void OutputStream::writeShort (short value)
  66. {
  67. const unsigned short v = ByteOrder::swapIfBigEndian ((unsigned short) value);
  68. write (&v, 2);
  69. }
  70. void OutputStream::writeShortBigEndian (short value)
  71. {
  72. const unsigned short v = ByteOrder::swapIfLittleEndian ((unsigned short) value);
  73. write (&v, 2);
  74. }
  75. void OutputStream::writeInt (int value)
  76. {
  77. const unsigned int v = ByteOrder::swapIfBigEndian ((unsigned int) value);
  78. write (&v, 4);
  79. }
  80. void OutputStream::writeIntBigEndian (int value)
  81. {
  82. const unsigned int v = ByteOrder::swapIfLittleEndian ((unsigned int) value);
  83. write (&v, 4);
  84. }
  85. void OutputStream::writeCompressedInt (int value)
  86. {
  87. unsigned int un = (value < 0) ? (unsigned int) -value
  88. : (unsigned int) value;
  89. uint8 data[5];
  90. int num = 0;
  91. while (un > 0)
  92. {
  93. data[++num] = (uint8) un;
  94. un >>= 8;
  95. }
  96. data[0] = (uint8) num;
  97. if (value < 0)
  98. data[0] |= 0x80;
  99. write (data, num + 1);
  100. }
  101. void OutputStream::writeInt64 (int64 value)
  102. {
  103. const uint64 v = ByteOrder::swapIfBigEndian ((uint64) value);
  104. write (&v, 8);
  105. }
  106. void OutputStream::writeInt64BigEndian (int64 value)
  107. {
  108. const uint64 v = ByteOrder::swapIfLittleEndian ((uint64) value);
  109. write (&v, 8);
  110. }
  111. void OutputStream::writeFloat (float value)
  112. {
  113. union { int asInt; float asFloat; } n;
  114. n.asFloat = value;
  115. writeInt (n.asInt);
  116. }
  117. void OutputStream::writeFloatBigEndian (float value)
  118. {
  119. union { int asInt; float asFloat; } n;
  120. n.asFloat = value;
  121. writeIntBigEndian (n.asInt);
  122. }
  123. void OutputStream::writeDouble (double value)
  124. {
  125. union { int64 asInt; double asDouble; } n;
  126. n.asDouble = value;
  127. writeInt64 (n.asInt);
  128. }
  129. void OutputStream::writeDoubleBigEndian (double value)
  130. {
  131. union { int64 asInt; double asDouble; } n;
  132. n.asDouble = value;
  133. writeInt64BigEndian (n.asInt);
  134. }
  135. void OutputStream::writeString (const String& text)
  136. {
  137. // (This avoids using toUTF8() to prevent the memory bloat that it would leave behind
  138. // if lots of large, persistent strings were to be written to streams).
  139. const int numBytes = text.getNumBytesAsUTF8() + 1;
  140. HeapBlock<char> temp (numBytes);
  141. text.copyToUTF8 (temp, numBytes);
  142. write (temp, numBytes);
  143. }
  144. void OutputStream::writeText (const String& text, const bool asUnicode,
  145. const bool writeUnicodeHeaderBytes)
  146. {
  147. if (asUnicode)
  148. {
  149. if (writeUnicodeHeaderBytes)
  150. write ("\x0ff\x0fe", 2);
  151. const juce_wchar* src = text;
  152. bool lastCharWasReturn = false;
  153. while (*src != 0)
  154. {
  155. if (*src == L'\n' && ! lastCharWasReturn)
  156. writeShort ((short) L'\r');
  157. lastCharWasReturn = (*src == L'\r');
  158. writeShort ((short) *src++);
  159. }
  160. }
  161. else
  162. {
  163. const char* src = text.toUTF8();
  164. const char* t = src;
  165. for (;;)
  166. {
  167. if (*t == '\n')
  168. {
  169. if (t > src)
  170. write (src, (int) (t - src));
  171. write ("\r\n", 2);
  172. src = t + 1;
  173. }
  174. else if (*t == '\r')
  175. {
  176. if (t[1] == '\n')
  177. ++t;
  178. }
  179. else if (*t == 0)
  180. {
  181. if (t > src)
  182. write (src, (int) (t - src));
  183. break;
  184. }
  185. ++t;
  186. }
  187. }
  188. }
  189. int OutputStream::writeFromInputStream (InputStream& source, int64 numBytesToWrite)
  190. {
  191. if (numBytesToWrite < 0)
  192. numBytesToWrite = std::numeric_limits<int64>::max();
  193. int numWritten = 0;
  194. while (numBytesToWrite > 0 && ! source.isExhausted())
  195. {
  196. char buffer [8192];
  197. const int num = source.read (buffer, (int) jmin (numBytesToWrite, (int64) sizeof (buffer)));
  198. if (num <= 0)
  199. break;
  200. write (buffer, num);
  201. numBytesToWrite -= num;
  202. numWritten += num;
  203. }
  204. return numWritten;
  205. }
  206. //==============================================================================
  207. OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const int number)
  208. {
  209. return stream << String (number);
  210. }
  211. OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const double number)
  212. {
  213. return stream << String (number);
  214. }
  215. OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const char character)
  216. {
  217. stream.writeByte (character);
  218. return stream;
  219. }
  220. OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const char* const text)
  221. {
  222. stream.write (text, (int) strlen (text));
  223. return stream;
  224. }
  225. OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const MemoryBlock& data)
  226. {
  227. stream.write (data.getData(), (int) data.getSize());
  228. return stream;
  229. }
  230. OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const File& fileToRead)
  231. {
  232. const ScopedPointer<FileInputStream> in (fileToRead.createInputStream());
  233. if (in != 0)
  234. stream.writeFromInputStream (*in, -1);
  235. return stream;
  236. }
  237. END_JUCE_NAMESPACE