• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "platform/text/QuotedPrintable.h"
33 
34 #include "wtf/ASCIICType.h"
35 
36 namespace blink {
37 
38 static const size_t maximumLineLength = 76;
39 
40 static const char crlfLineEnding[] = "\r\n";
41 
lengthOfLineEndingAtIndex(const char * input,size_t inputLength,size_t index)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 
quotedPrintableEncode(const Vector<char> & in,Vector<char> & out)57 void quotedPrintableEncode(const Vector<char>& in, Vector<char>& out)
58 {
59     quotedPrintableEncode(in.data(), in.size(), out);
60 }
61 
quotedPrintableEncode(const char * input,size_t inputLength,Vector<char> & out)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 
quotedPrintableDecode(const Vector<char> & in,Vector<char> & out)116 void quotedPrintableDecode(const Vector<char>& in, Vector<char>& out)
117 {
118     quotedPrintableDecode(in.data(), in.size(), out);
119 }
120 
quotedPrintableDecode(const char * data,size_t dataLength,Vector<char> & out)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