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;
~OutputBuffer()44 virtual ~OutputBuffer() { }
45 };
46
47 class CStringBuffer FINAL : 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) OVERRIDE
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) OVERRIDE
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 FINAL : 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) OVERRIDE
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) OVERRIDE
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 (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.
normalizeToCROrLF(const CString & from,Vector<char> & result,bool toCR)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
normalizeLineEndingsToCRLF(const CString & from)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
normalizeLineEndingsToCR(const CString & from,Vector<char> & result)217 void normalizeLineEndingsToCR(const CString& from, Vector<char>& result)
218 {
219 normalizeToCROrLF(from, result, true);
220 }
221
normalizeLineEndingsToLF(const CString & from,Vector<char> & result)222 void normalizeLineEndingsToLF(const CString& from, Vector<char>& result)
223 {
224 normalizeToCROrLF(from, result, false);
225 }
226
normalizeLineEndingsToNative(const CString & from,Vector<char> & result)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