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 <wtf/text/CString.h> 36#include <wtf/text/WTFString.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 if (!from.length()) 100 return; 101 // Compute the new length. 102 size_t newLen = 0; 103 const char* p = from.data(); 104 while (p < from.data() + from.length()) { 105 char c = *p++; 106 if (c == '\r') { 107 // Safe to look ahead because of trailing '\0'. 108 if (*p != '\n') { 109 // Turn CR into CRLF. 110 newLen += 2; 111 } 112 } else if (c == '\n') { 113 // Turn LF into CRLF. 114 newLen += 2; 115 } else { 116 // Leave other characters alone. 117 newLen += 1; 118 } 119 } 120 if (newLen < from.length()) 121 return; 122 123 if (newLen == from.length()) { 124 buffer.copy(from); 125 return; 126 } 127 128 p = from.data(); 129 char* q = buffer.allocate(newLen); 130 131 // Make a copy of the string. 132 while (p < from.data() + from.length()) { 133 char c = *p++; 134 if (c == '\r') { 135 // Safe to look ahead because of trailing '\0'. 136 if (*p != '\n') { 137 // Turn CR into CRLF. 138 *q++ = '\r'; 139 *q++ = '\n'; 140 } 141 } else if (c == '\n') { 142 // Turn LF into CRLF. 143 *q++ = '\r'; 144 *q++ = '\n'; 145 } else { 146 // Leave other characters alone. 147 *q++ = c; 148 } 149 } 150} 151 152}; 153 154namespace WebCore { 155 156void normalizeToCROrLF(const CString& from, Vector<char>& result, bool toCR); 157 158// Normalize all line-endings to CR or LF. 159void normalizeToCROrLF(const CString& from, Vector<char>& result, bool toCR) 160{ 161 // Compute the new length. 162 size_t newLen = 0; 163 bool needFix = false; 164 const char* p = from.data(); 165 char fromEndingChar = toCR ? '\n' : '\r'; 166 char toEndingChar = toCR ? '\r' : '\n'; 167 while (p < from.data() + from.length()) { 168 char c = *p++; 169 if (c == '\r' && *p == '\n') { 170 // Turn CRLF into CR or LF. 171 p++; 172 needFix = true; 173 } else if (c == fromEndingChar) { 174 // Turn CR/LF into LF/CR. 175 needFix = true; 176 } 177 newLen += 1; 178 } 179 180 // Grow the result buffer. 181 p = from.data(); 182 size_t oldResultSize = result.size(); 183 result.grow(oldResultSize + newLen); 184 char* q = result.data() + oldResultSize; 185 186 // If no need to fix the string, just copy the string over. 187 if (!needFix) { 188 memcpy(q, p, from.length()); 189 return; 190 } 191 192 // Make a copy of the string. 193 while (p < from.data() + from.length()) { 194 char c = *p++; 195 if (c == '\r' && *p == '\n') { 196 // Turn CRLF or CR into CR or LF. 197 p++; 198 *q++ = toEndingChar; 199 } else if (c == fromEndingChar) { 200 // Turn CR/LF into LF/CR. 201 *q++ = toEndingChar; 202 } else { 203 // Leave other characters alone. 204 *q++ = c; 205 } 206 } 207} 208 209CString normalizeLineEndingsToCRLF(const CString& from) 210{ 211 CString result; 212 CStringBuffer buffer(result); 213 internalNormalizeLineEndingsToCRLF(from, buffer); 214 return buffer.buffer(); 215} 216 217void normalizeLineEndingsToCR(const CString& from, Vector<char>& result) 218{ 219 normalizeToCROrLF(from, result, true); 220} 221 222void normalizeLineEndingsToLF(const CString& from, Vector<char>& result) 223{ 224 normalizeToCROrLF(from, result, false); 225} 226 227void normalizeLineEndingsToNative(const CString& from, Vector<char>& result) 228{ 229#if OS(WINDOWS) 230 VectorCharAppendBuffer buffer(result); 231 internalNormalizeLineEndingsToCRLF(from, buffer); 232#else 233 normalizeLineEndingsToLF(from, result); 234#endif 235} 236 237} // namespace WebCore 238