initial import
[vuplus_webkit] / Source / WebCore / platform / text / LineEnding.cpp
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;
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 (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.
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
203 CString normalizeLineEndingsToCRLF(const CString& from)
204 {
205     CString result;
206     CStringBuffer buffer(result);
207     internalNormalizeLineEndingsToCRLF(from, buffer);
208     return buffer.buffer();
209 }
210
211 void normalizeLineEndingsToCR(const CString& from, Vector<char>& result)
212 {
213     normalizeToCROrLF(from, result, true);
214 }
215
216 void normalizeLineEndingsToLF(const CString& from, Vector<char>& result)
217 {
218     normalizeToCROrLF(from, result, false);
219 }
220
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