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
38 namespace {
39
40 class OutputBuffer {
41 public:
42 virtual char* allocate(size_t size) = 0;
43 virtual void copy(const CString&) = 0;
~OutputBuffer()44 virtual ~OutputBuffer() { }
45 };
46
47 class CStringBuffer : public OutputBuffer {
48 public:
CStringBuffer(CString & buffer)49 CStringBuffer(CString& buffer)
50 : m_buffer(buffer)
51 {
52 }
~CStringBuffer()53 virtual ~CStringBuffer() { }
54
allocate(size_t size)55 virtual char* allocate(size_t size)
56 {
57 char* ptr;
58 m_buffer = CString::newUninitialized(size, ptr);
59 return ptr;
60 }
61
copy(const CString & source)62 virtual void copy(const CString& source)
63 {
64 m_buffer = source;
65 }
66
buffer() const67 const CString& buffer() const { return m_buffer; }
68
69 private:
70 CString m_buffer;
71 };
72
73 class VectorCharAppendBuffer : public OutputBuffer {
74 public:
VectorCharAppendBuffer(Vector<char> & buffer)75 VectorCharAppendBuffer(Vector<char>& buffer)
76 : m_buffer(buffer)
77 {
78 }
~VectorCharAppendBuffer()79 virtual ~VectorCharAppendBuffer() { }
80
allocate(size_t size)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
copy(const CString & source)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
internalNormalizeLineEndingsToCRLF(const CString & from,OutputBuffer & buffer)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 (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
150 namespace WebCore {
151
152 void normalizeToCROrLF(const CString& from, Vector<char>& result, bool toCR);
153
154 // Normalize all line-endings to CR or LF.
normalizeToCROrLF(const CString & from,Vector<char> & result,bool toCR)155 void 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
normalizeLineEndingsToCRLF(const CString & from)203 CString normalizeLineEndingsToCRLF(const CString& from)
204 {
205 CString result;
206 CStringBuffer buffer(result);
207 internalNormalizeLineEndingsToCRLF(from, buffer);
208 return buffer.buffer();
209 }
210
normalizeLineEndingsToCR(const CString & from,Vector<char> & result)211 void normalizeLineEndingsToCR(const CString& from, Vector<char>& result)
212 {
213 normalizeToCROrLF(from, result, true);
214 }
215
normalizeLineEndingsToLF(const CString & from,Vector<char> & result)216 void normalizeLineEndingsToLF(const CString& from, Vector<char>& result)
217 {
218 normalizeToCROrLF(from, result, false);
219 }
220
normalizeLineEndingsToNative(const CString & from,Vector<char> & result)221 void 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