Home | History | Annotate | Download | only in text
      1 /*
      2  * Copyright (C) 2011 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "core/platform/text/QuotedPrintable.h"
     33 
     34 #include "wtf/ASCIICType.h"
     35 
     36 namespace WebCore {
     37 
     38 static const size_t maximumLineLength = 76;
     39 
     40 static const char crlfLineEnding[] = "\r\n";
     41 
     42 static size_t lengthOfLineEndingAtIndex(const char* input, size_t inputLength, size_t index)
     43 {
     44     ASSERT_WITH_SECURITY_IMPLICATION(index < inputLength);
     45     if (input[index] == '\n')
     46         return 1; // Single LF.
     47 
     48     if (input[index] == '\r') {
     49         if ((index + 1) == inputLength || input[index + 1] != '\n')
     50             return 1; // Single CR (Classic Mac OS).
     51         return 2; // CR-LF.
     52     }
     53 
     54     return 0;
     55 }
     56 
     57 void quotedPrintableEncode(const Vector<char>& in, Vector<char>& out)
     58 {
     59     quotedPrintableEncode(in.data(), in.size(), out);
     60 }
     61 
     62 void quotedPrintableEncode(const char* input, size_t inputLength, Vector<char>& out)
     63 {
     64     out.clear();
     65     out.reserveCapacity(inputLength);
     66     size_t currentLineLength = 0;
     67     for (size_t i = 0; i < inputLength; ++i) {
     68         bool isLastCharacter = (i == inputLength - 1);
     69         char currentCharacter = input[i];
     70         bool requiresEncoding = false;
     71         // All non-printable ASCII characters and = require encoding.
     72         if ((currentCharacter < ' ' || currentCharacter > '~' || currentCharacter == '=') && currentCharacter != '\t')
     73             requiresEncoding = true;
     74 
     75         // Space and tab characters have to be encoded if they appear at the end of a line.
     76         if (!requiresEncoding && (currentCharacter == '\t' || currentCharacter == ' ') && (isLastCharacter || lengthOfLineEndingAtIndex(input, inputLength, i + 1)))
     77             requiresEncoding = true;
     78 
     79         // End of line should be converted to CR-LF sequences.
     80         if (!isLastCharacter) {
     81             size_t lengthOfLineEnding = lengthOfLineEndingAtIndex(input, inputLength, i);
     82             if (lengthOfLineEnding) {
     83                 out.append(crlfLineEnding, strlen(crlfLineEnding));
     84                 currentLineLength = 0;
     85                 i += (lengthOfLineEnding - 1); // -1 because we'll ++ in the for() above.
     86                 continue;
     87             }
     88         }
     89 
     90         size_t lengthOfEncodedCharacter = 1;
     91         if (requiresEncoding)
     92             lengthOfEncodedCharacter += 2;
     93         if (!isLastCharacter)
     94             lengthOfEncodedCharacter += 1; // + 1 for the = (soft line break).
     95 
     96         // Insert a soft line break if necessary.
     97         if (currentLineLength + lengthOfEncodedCharacter > maximumLineLength) {
     98             out.append('=');
     99             out.append(crlfLineEnding, strlen(crlfLineEnding));
    100             currentLineLength = 0;
    101         }
    102 
    103         // Finally, insert the actual character(s).
    104         if (requiresEncoding) {
    105             out.append('=');
    106             out.append(upperNibbleToASCIIHexDigit(currentCharacter));
    107             out.append(lowerNibbleToASCIIHexDigit(currentCharacter));
    108             currentLineLength += 3;
    109         } else {
    110             out.append(currentCharacter);
    111             currentLineLength++;
    112         }
    113     }
    114 }
    115 
    116 void quotedPrintableDecode(const Vector<char>& in, Vector<char>& out)
    117 {
    118     quotedPrintableDecode(in.data(), in.size(), out);
    119 }
    120 
    121 void quotedPrintableDecode(const char* data, size_t dataLength, Vector<char>& out)
    122 {
    123     out.clear();
    124     if (!dataLength)
    125         return;
    126 
    127     for (size_t i = 0; i < dataLength; ++i) {
    128         char currentCharacter = data[i];
    129         if (currentCharacter != '=') {
    130             out.append(currentCharacter);
    131             continue;
    132         }
    133         // We are dealing with a '=xx' sequence.
    134         if (dataLength - i < 3) {
    135             // Unfinished = sequence, append as is.
    136             out.append(currentCharacter);
    137             continue;
    138         }
    139         char upperCharacter = data[++i];
    140         char lowerCharacter = data[++i];
    141         if (upperCharacter == '\r' && lowerCharacter == '\n')
    142             continue;
    143 
    144         if (!isASCIIHexDigit(upperCharacter) || !isASCIIHexDigit(lowerCharacter)) {
    145             // Invalid sequence, = followed by non hex digits, just insert the characters as is.
    146             out.append('=');
    147             out.append(upperCharacter);
    148             out.append(lowerCharacter);
    149             continue;
    150         }
    151         out.append(static_cast<char>(toASCIIHexValue(upperCharacter, lowerCharacter)));
    152     }
    153 }
    154 
    155 }
    156