Home | History | Annotate | Download | only in text
      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