1/* 2 * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved. 3 * Copyright (C) 2010 Google Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include "config.h" 33#include "LineEnding.h" 34 35#include "PlatformString.h" 36#include <wtf/text/CString.h> 37 38namespace { 39 40class OutputBuffer { 41public: 42 virtual char* allocate(size_t size) = 0; 43 virtual void copy(const CString&) = 0; 44 virtual ~OutputBuffer() { } 45}; 46 47class CStringBuffer : public OutputBuffer { 48public: 49 CStringBuffer(CString& buffer) 50 : m_buffer(buffer) 51 { 52 } 53 virtual ~CStringBuffer() { } 54 55 virtual char* allocate(size_t size) 56 { 57 char* ptr; 58 m_buffer = CString::newUninitialized(size, ptr); 59 return ptr; 60 } 61 62 virtual void copy(const CString& source) 63 { 64 m_buffer = source; 65 } 66 67 const CString& buffer() const { return m_buffer; } 68 69private: 70 CString m_buffer; 71}; 72 73class VectorCharAppendBuffer : public OutputBuffer { 74public: 75 VectorCharAppendBuffer(Vector<char>& buffer) 76 : m_buffer(buffer) 77 { 78 } 79 virtual ~VectorCharAppendBuffer() { } 80 81 virtual char* allocate(size_t size) 82 { 83 size_t oldSize = m_buffer.size(); 84 m_buffer.grow(oldSize + size); 85 return m_buffer.data() + oldSize; 86 } 87 88 virtual void copy(const CString& source) 89 { 90 m_buffer.append(source.data(), source.length()); 91 } 92 93private: 94 Vector<char>& m_buffer; 95}; 96 97void internalNormalizeLineEndingsToCRLF(const CString& from, OutputBuffer& buffer) 98{ 99 // Compute the new length. 100 size_t newLen = 0; 101 const char* p = from.data(); 102 while (char c = *p++) { 103 if (c == '\r') { 104 // Safe to look ahead because of trailing '\0'. 105 if (*p != '\n') { 106 // Turn CR into CRLF. 107 newLen += 2; 108 } 109 } else if (c == '\n') { 110 // Turn LF into CRLF. 111 newLen += 2; 112 } else { 113 // Leave other characters alone. 114 newLen += 1; 115 } 116 } 117 if (newLen < from.length()) 118 return; 119 120 if (newLen == from.length()) { 121 buffer.copy(from); 122 return; 123 } 124 125 p = from.data(); 126 char* q = buffer.allocate(newLen); 127 128 // Make a copy of the string. 129 while (char c = *p++) { 130 if (c == '\r') { 131 // Safe to look ahead because of trailing '\0'. 132 if (*p != '\n') { 133 // Turn CR into CRLF. 134 *q++ = '\r'; 135 *q++ = '\n'; 136 } 137 } else if (c == '\n') { 138 // Turn LF into CRLF. 139 *q++ = '\r'; 140 *q++ = '\n'; 141 } else { 142 // Leave other characters alone. 143 *q++ = c; 144 } 145 } 146} 147 148}; 149 150namespace WebCore { 151 152void normalizeToCROrLF(const CString& from, Vector<char>& result, bool toCR); 153 154// Normalize all line-endings to CR or LF. 155void normalizeToCROrLF(const CString& from, Vector<char>& result, bool toCR) 156{ 157 // Compute the new length. 158 size_t newLen = 0; 159 bool needFix = false; 160 const char* p = from.data(); 161 char fromEndingChar = toCR ? '\n' : '\r'; 162 char toEndingChar = toCR ? '\r' : '\n'; 163 while (char c = *p++) { 164 if (c == '\r' && *p == '\n') { 165 // Turn CRLF into CR or LF. 166 p++; 167 needFix = true; 168 } else if (c == fromEndingChar) { 169 // Turn CR/LF into LF/CR. 170 needFix = true; 171 } 172 newLen += 1; 173 } 174 175 // Grow the result buffer. 176 p = from.data(); 177 size_t oldResultSize = result.size(); 178 result.grow(oldResultSize + newLen); 179 char* q = result.data() + oldResultSize; 180 181 // If no need to fix the string, just copy the string over. 182 if (!needFix) { 183 memcpy(q, p, from.length()); 184 return; 185 } 186 187 // Make a copy of the string. 188 while (char c = *p++) { 189 if (c == '\r' && *p == '\n') { 190 // Turn CRLF or CR into CR or LF. 191 p++; 192 *q++ = toEndingChar; 193 } else if (c == fromEndingChar) { 194 // Turn CR/LF into LF/CR. 195 *q++ = toEndingChar; 196 } else { 197 // Leave other characters alone. 198 *q++ = c; 199 } 200 } 201} 202 203CString normalizeLineEndingsToCRLF(const CString& from) 204{ 205 CString result; 206 CStringBuffer buffer(result); 207 internalNormalizeLineEndingsToCRLF(from, buffer); 208 return buffer.buffer(); 209} 210 211void normalizeLineEndingsToCR(const CString& from, Vector<char>& result) 212{ 213 normalizeToCROrLF(from, result, true); 214} 215 216void normalizeLineEndingsToLF(const CString& from, Vector<char>& result) 217{ 218 normalizeToCROrLF(from, result, false); 219} 220 221void normalizeLineEndingsToNative(const CString& from, Vector<char>& result) 222{ 223#if OS(WINDOWS) 224 VectorCharAppendBuffer buffer(result); 225 internalNormalizeLineEndingsToCRLF(from, buffer); 226#else 227 normalizeLineEndingsToLF(from, result); 228#endif 229} 230 231} // namespace WebCore 232