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.

324 lines
8.4KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 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 "../../containers/juce_Array.h"
  22. #include "../../memory/juce_ScopedPointer.h"
  23. #include "../files/juce_FileInputStream.h"
  24. //==============================================================================
  25. #if JUCE_DEBUG
  26. struct DanglingStreamChecker
  27. {
  28. DanglingStreamChecker() {}
  29. ~DanglingStreamChecker()
  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. Array<void*, CriticalSection> activeStreams;
  40. };
  41. static DanglingStreamChecker danglingStreamChecker;
  42. #endif
  43. //==============================================================================
  44. OutputStream::OutputStream()
  45. : newLineString (NewLine::getDefault())
  46. {
  47. #if JUCE_DEBUG
  48. danglingStreamChecker.activeStreams.add (this);
  49. #endif
  50. }
  51. OutputStream::~OutputStream()
  52. {
  53. #if JUCE_DEBUG
  54. danglingStreamChecker.activeStreams.removeValue (this);
  55. #endif
  56. }
  57. //==============================================================================
  58. void OutputStream::writeBool (const bool b)
  59. {
  60. writeByte (b ? (char) 1
  61. : (char) 0);
  62. }
  63. void OutputStream::writeByte (char byte)
  64. {
  65. write (&byte, 1);
  66. }
  67. void OutputStream::writeRepeatedByte (uint8 byte, int numTimesToRepeat)
  68. {
  69. while (--numTimesToRepeat >= 0)
  70. writeByte (byte);
  71. }
  72. void OutputStream::writeShort (short value)
  73. {
  74. const unsigned short v = ByteOrder::swapIfBigEndian ((unsigned short) value);
  75. write (&v, 2);
  76. }
  77. void OutputStream::writeShortBigEndian (short value)
  78. {
  79. const unsigned short v = ByteOrder::swapIfLittleEndian ((unsigned short) value);
  80. write (&v, 2);
  81. }
  82. void OutputStream::writeInt (int value)
  83. {
  84. const unsigned int v = ByteOrder::swapIfBigEndian ((unsigned int) value);
  85. write (&v, 4);
  86. }
  87. void OutputStream::writeIntBigEndian (int value)
  88. {
  89. const unsigned int v = ByteOrder::swapIfLittleEndian ((unsigned int) value);
  90. write (&v, 4);
  91. }
  92. void OutputStream::writeCompressedInt (int value)
  93. {
  94. unsigned int un = (value < 0) ? (unsigned int) -value
  95. : (unsigned int) value;
  96. uint8 data[5];
  97. int num = 0;
  98. while (un > 0)
  99. {
  100. data[++num] = (uint8) un;
  101. un >>= 8;
  102. }
  103. data[0] = (uint8) num;
  104. if (value < 0)
  105. data[0] |= 0x80;
  106. write (data, num + 1);
  107. }
  108. void OutputStream::writeInt64 (int64 value)
  109. {
  110. const uint64 v = ByteOrder::swapIfBigEndian ((uint64) value);
  111. write (&v, 8);
  112. }
  113. void OutputStream::writeInt64BigEndian (int64 value)
  114. {
  115. const uint64 v = ByteOrder::swapIfLittleEndian ((uint64) value);
  116. write (&v, 8);
  117. }
  118. void OutputStream::writeFloat (float value)
  119. {
  120. union { int asInt; float asFloat; } n;
  121. n.asFloat = value;
  122. writeInt (n.asInt);
  123. }
  124. void OutputStream::writeFloatBigEndian (float value)
  125. {
  126. union { int asInt; float asFloat; } n;
  127. n.asFloat = value;
  128. writeIntBigEndian (n.asInt);
  129. }
  130. void OutputStream::writeDouble (double value)
  131. {
  132. union { int64 asInt; double asDouble; } n;
  133. n.asDouble = value;
  134. writeInt64 (n.asInt);
  135. }
  136. void OutputStream::writeDoubleBigEndian (double value)
  137. {
  138. union { int64 asInt; double asDouble; } n;
  139. n.asDouble = value;
  140. writeInt64BigEndian (n.asInt);
  141. }
  142. void OutputStream::writeString (const String& text)
  143. {
  144. // (This avoids using toUTF8() to prevent the memory bloat that it would leave behind
  145. // if lots of large, persistent strings were to be written to streams).
  146. const int numBytes = text.getNumBytesAsUTF8() + 1;
  147. HeapBlock<char> temp (numBytes);
  148. text.copyToUTF8 (temp, numBytes);
  149. write (temp, numBytes);
  150. }
  151. void OutputStream::writeText (const String& text, const bool asUTF16,
  152. const bool writeUTF16ByteOrderMark)
  153. {
  154. if (asUTF16)
  155. {
  156. if (writeUTF16ByteOrderMark)
  157. write ("\x0ff\x0fe", 2);
  158. String::CharPointerType src (text.getCharPointer());
  159. bool lastCharWasReturn = false;
  160. for (;;)
  161. {
  162. const juce_wchar c = src.getAndAdvance();
  163. if (c == 0)
  164. break;
  165. if (c == '\n' && ! lastCharWasReturn)
  166. writeShort ((short) '\r');
  167. lastCharWasReturn = (c == L'\r');
  168. writeShort ((short) c);
  169. }
  170. }
  171. else
  172. {
  173. const char* src = text.toUTF8();
  174. const char* t = src;
  175. for (;;)
  176. {
  177. if (*t == '\n')
  178. {
  179. if (t > src)
  180. write (src, (int) (t - src));
  181. write ("\r\n", 2);
  182. src = t + 1;
  183. }
  184. else if (*t == '\r')
  185. {
  186. if (t[1] == '\n')
  187. ++t;
  188. }
  189. else if (*t == 0)
  190. {
  191. if (t > src)
  192. write (src, (int) (t - src));
  193. break;
  194. }
  195. ++t;
  196. }
  197. }
  198. }
  199. int OutputStream::writeFromInputStream (InputStream& source, int64 numBytesToWrite)
  200. {
  201. if (numBytesToWrite < 0)
  202. numBytesToWrite = std::numeric_limits<int64>::max();
  203. int numWritten = 0;
  204. while (numBytesToWrite > 0 && ! source.isExhausted())
  205. {
  206. char buffer [8192];
  207. const int num = source.read (buffer, (int) jmin (numBytesToWrite, (int64) sizeof (buffer)));
  208. if (num <= 0)
  209. break;
  210. write (buffer, num);
  211. numBytesToWrite -= num;
  212. numWritten += num;
  213. }
  214. return numWritten;
  215. }
  216. //==============================================================================
  217. void OutputStream::setNewLineString (const String& newLineString_)
  218. {
  219. newLineString = newLineString_;
  220. }
  221. //==============================================================================
  222. OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const int number)
  223. {
  224. return stream << String (number);
  225. }
  226. OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const double number)
  227. {
  228. return stream << String (number);
  229. }
  230. OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const char character)
  231. {
  232. stream.writeByte (character);
  233. return stream;
  234. }
  235. OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const char* const text)
  236. {
  237. stream.write (text, (int) strlen (text));
  238. return stream;
  239. }
  240. OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const MemoryBlock& data)
  241. {
  242. stream.write (data.getData(), (int) data.getSize());
  243. return stream;
  244. }
  245. OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const File& fileToRead)
  246. {
  247. const ScopedPointer<FileInputStream> in (fileToRead.createInputStream());
  248. if (in != nullptr)
  249. stream.writeFromInputStream (*in, -1);
  250. return stream;
  251. }
  252. OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const NewLine&)
  253. {
  254. return stream << stream.getNewLineString();
  255. }
  256. END_JUCE_NAMESPACE