e819aef549e01aca18842e26dd4b57c963713c64
[WebKit-https.git] / Source / WTF / wtf / text / LineEnding.cpp
1 /*
2  * Copyright (C) 2005, 2006, 2008, 2017 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
38 namespace {
39
40 class OutputBuffer {
41 public:
42     virtual uint8_t* 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     uint8_t* allocate(size_t size) override
56     {
57         char* ptr;
58         m_buffer = CString::newUninitialized(size, ptr);
59         return reinterpret_cast<uint8_t*>(ptr);
60     }
61
62     void copy(const CString& source) override
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 #if OS(WINDOWS)
74 class VectorCharAppendBuffer : public OutputBuffer {
75 public:
76     VectorCharAppendBuffer(Vector<uint8_t>& buffer)
77         : m_buffer(buffer)
78     {
79     }
80     virtual ~VectorCharAppendBuffer() { }
81
82     uint8_t* allocate(size_t size) override
83     {
84         size_t oldSize = m_buffer.size();
85         m_buffer.grow(oldSize + size);
86         return m_buffer.data() + oldSize;
87     }
88
89     void copy(const CString& source) override
90     {
91         m_buffer.append(source.data(), source.length());
92     }
93
94 private:
95     Vector<uint8_t>& m_buffer;
96 };
97 #endif
98
99 void internalNormalizeLineEndingsToCRLF(const CString& from, OutputBuffer& buffer)
100 {
101     if (!from.length())
102         return;
103     // Compute the new length.
104     size_t newLen = 0;
105     const char* p = from.data();
106     while (p < from.data() + from.length()) {
107         char c = *p++;
108         if (c == '\r') {
109             // Safe to look ahead because of trailing '\0'.
110             if (*p != '\n') {
111                 // Turn CR into CRLF.
112                 newLen += 2;
113             }
114         } else if (c == '\n') {
115             // Turn LF into CRLF.
116             newLen += 2;
117         } else {
118             // Leave other characters alone.
119             newLen += 1;
120         }
121     }
122     if (newLen < from.length())
123         return;
124
125     if (newLen == from.length()) {
126         buffer.copy(from);
127         return;
128     }
129
130     p = from.data();
131     uint8_t* q = buffer.allocate(newLen);
132
133     // Make a copy of the string.
134     while (p < from.data() + from.length()) {
135         char c = *p++;
136         if (c == '\r') {
137             // Safe to look ahead because of trailing '\0'.
138             if (*p != '\n') {
139                 // Turn CR into CRLF.
140                 *q++ = '\r';
141                 *q++ = '\n';
142             }
143         } else if (c == '\n') {
144             // Turn LF into CRLF.
145             *q++ = '\r';
146             *q++ = '\n';
147         } else {
148             // Leave other characters alone.
149             *q++ = c;
150         }
151     }
152 }
153
154 };
155
156 namespace WTF {
157
158 // Normalize all line-endings to CR or LF.
159 static void normalizeToCROrLF(const CString& from, Vector<uint8_t>& 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     uint8_t* 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
209 CString normalizeLineEndingsToCRLF(const CString& from)
210 {
211     CString result;
212     ::CStringBuffer buffer(result);
213     internalNormalizeLineEndingsToCRLF(from, buffer);
214     return buffer.buffer();
215 }
216
217 void normalizeAndAppendLineEndingsToNative(const CString& from, Vector<uint8_t>& result)
218 {
219 #if OS(WINDOWS)
220     VectorCharAppendBuffer buffer(result);
221     internalNormalizeLineEndingsToCRLF(from, buffer);
222 #else
223     normalizeToCROrLF(from, result, false);
224 #endif
225 }
226
227 } // namespace WTF