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