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