diff --git a/modules/juce_core/files/juce_File.cpp b/modules/juce_core/files/juce_File.cpp index 358edd2749..72b17bfeaa 100644 --- a/modules/juce_core/files/juce_File.cpp +++ b/modules/juce_core/files/juce_File.cpp @@ -750,24 +750,20 @@ bool File::replaceWithData (const void* const dataToWrite, return tempFile.overwriteTargetFileWithTemporary(); } -bool File::appendText (const String& text, - const bool asUnicode, - const bool writeUnicodeHeaderBytes) const +bool File::appendText (const String& text, bool asUnicode, bool writeHeaderBytes, const char* lineFeed) const { FileOutputStream out (*this); if (out.failedToOpen()) return false; - return out.writeText (text, asUnicode, writeUnicodeHeaderBytes); + return out.writeText (text, asUnicode, writeHeaderBytes, lineFeed); } -bool File::replaceWithText (const String& textToWrite, - const bool asUnicode, - const bool writeUnicodeHeaderBytes) const +bool File::replaceWithText (const String& textToWrite, bool asUnicode, bool writeHeaderBytes, const char* lineFeed) const { TemporaryFile tempFile (*this, TemporaryFile::useHiddenFile); - tempFile.getFile().appendText (textToWrite, asUnicode, writeUnicodeHeaderBytes); + tempFile.getFile().appendText (textToWrite, asUnicode, writeHeaderBytes, lineFeed); return tempFile.overwriteTargetFileWithTemporary(); } diff --git a/modules/juce_core/files/juce_File.h b/modules/juce_core/files/juce_File.h index 5f7d2d1b29..7b55ca442c 100644 --- a/modules/juce_core/files/juce_File.h +++ b/modules/juce_core/files/juce_File.h @@ -681,13 +681,15 @@ public: It can also write the 'ff fe' unicode header bytes before the text to indicate the endianness of the file. - Any single \\n characters in the string are replaced with \\r\\n before it is written. + If lineEndings is nullptr, then line endings in the text won't be modified. If you + pass "\\n" or "\\r\\n" then this function will replace any existing line feeds. @see replaceWithText */ bool appendText (const String& textToAppend, bool asUnicode = false, - bool writeUnicodeHeaderBytes = false) const; + bool writeUnicodeHeaderBytes = false, + const char* lineEndings = "\r\n") const; /** Replaces this file's contents with a given text string. @@ -707,7 +709,8 @@ public: */ bool replaceWithText (const String& textToWrite, bool asUnicode = false, - bool writeUnicodeHeaderBytes = false) const; + bool writeUnicodeHeaderBytes = false, + const char* lineEndings = "\r\n") const; /** Attempts to scan the contents of this file and compare it to another file, returning true if this is possible and they match byte-for-byte. diff --git a/modules/juce_core/streams/juce_OutputStream.cpp b/modules/juce_core/streams/juce_OutputStream.cpp index 6a24702179..e3ab6a7e69 100644 --- a/modules/juce_core/streams/juce_OutputStream.cpp +++ b/modules/juce_core/streams/juce_OutputStream.cpp @@ -171,20 +171,27 @@ bool OutputStream::writeDoubleBigEndian (double value) bool OutputStream::writeString (const String& text) { + auto numBytes = text.getNumBytesAsUTF8() + 1; + #if (JUCE_STRING_UTF_TYPE == 8) - return write (text.toRawUTF8(), text.getNumBytesAsUTF8() + 1); + 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). - const size_t numBytes = text.getNumBytesAsUTF8() + 1; HeapBlock temp (numBytes); text.copyToUTF8 (temp, numBytes); return write (temp, numBytes); #endif } -bool OutputStream::writeText (const String& text, bool asUTF16, bool writeUTF16ByteOrderMark) +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) @@ -200,10 +207,17 @@ bool OutputStream::writeText (const String& text, bool asUTF16, bool writeUTF16B if (c == 0) break; - if (c == '\n' && ! lastCharWasReturn) - writeShort ((short) '\r'); + if (replaceLineFeedWithWindows) + { + if (c == '\n' && ! lastCharWasReturn) + writeShort ((short) '\r'); - lastCharWasReturn = (c == L'\r'); + lastCharWasReturn = (c == L'\r'); + } + else if (replaceLineFeedWithUnix && c == '\r') + { + continue; + } if (! writeShort ((short) c)) return false; @@ -211,37 +225,57 @@ bool OutputStream::writeText (const String& text, bool asUTF16, bool writeUTF16B } else { - const char* src = text.toUTF8(); - auto* t = src; + const char* src = text.toRawUTF8(); - for (;;) + if (replaceLineFeedWithWindows) { - if (*t == '\n') + for (auto t = src;;) { - if (t > src) - if (! write (src, (size_t) (t - src))) - return false; + if (*t == '\n') + { + if (t > src) + if (! write (src, (size_t) (t - src))) + return false; - if (! write ("\r\n", 2)) - return false; + if (! write ("\r\n", 2)) + return false; - src = t + 1; + 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 (*t == '\r') - { - if (t[1] == '\n') - ++t; - } - else if (*t == 0) + } + else if (replaceLineFeedWithUnix) + { + for (;;) { - if (t > src) - if (! write (src, (size_t) (t - src))) - return false; + auto c = *src++; - break; - } + if (c == 0) + break; - ++t; + if (c != '\r') + if (! writeByte (c)) + return false; + } + } + else + { + return write (src, text.getNumBytesAsUTF8()); } } @@ -273,9 +307,9 @@ int64 OutputStream::writeFromInputStream (InputStream& source, int64 numBytesToW } //============================================================================== -void OutputStream::setNewLineString (const String& newLineString_) +void OutputStream::setNewLineString (const String& newLineStringToUse) { - newLineString = newLineString_; + newLineString = newLineStringToUse; } //============================================================================== diff --git a/modules/juce_core/streams/juce_OutputStream.h b/modules/juce_core/streams/juce_OutputStream.h index 11f3d16a81..f41cbc1259 100644 --- a/modules/juce_core/streams/juce_OutputStream.h +++ b/modules/juce_core/streams/juce_OutputStream.h @@ -201,12 +201,15 @@ public: bytes (0xff, 0xfe) to indicate the endianness (these should only be used at the start of a file). - The method also replaces '\\n' characters in the text with '\\r\\n'. + If lineEndings is nullptr, then line endings in the text won't be modified. If you + pass "\\n" or "\\r\\n" then this function will replace any existing line feeds. + @returns false if the write operation fails for some reason */ virtual bool writeText (const String& text, bool asUTF16, - bool writeUTF16ByteOrderMark); + bool writeUTF16ByteOrderMark, + const char* lineEndings); /** Reads data from an input stream and writes it to this stream.