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 "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
    232