1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/net/quoted_printable.h" 6 7 #include "base/logging.h" 8 #include "base/string_util.h" 9 10 namespace { 11 12 const int kMaxCharPerLine = 76; 13 const char* const kEOL = "\r\n"; 14 15 const char kHexTable[] = "0123456789ABCDEF"; 16 17 } // namespace 18 19 namespace chrome { 20 namespace browser { 21 namespace net { 22 23 void QuotedPrintableEncode(const std::string& input, std::string* output) { 24 // The number of characters in the current line. 25 int char_count = 0; 26 for (std::string::const_iterator iter = input.begin(); 27 iter != input.end(); ++iter) { 28 bool last_char = (iter + 1 == input.end()); 29 char c = *iter; 30 // Whether this character can be inserted without encoding. 31 bool as_is = false; 32 // All printable ASCII characters can be included as is (but for =). 33 if (c >= '!' && c <= '~' && c != '=') { 34 as_is = true; 35 } 36 37 // Space and tab characters can be included as is if they don't appear at 38 // the end of a line or at then end of the input. 39 if (!as_is && (c == '\t' || c == ' ') && !last_char && 40 !IsEOL(iter + 1, input)) { 41 as_is = true; 42 } 43 44 // End of line should be converted to CR-LF sequences. 45 if (!last_char) { 46 int eol_len = IsEOL(iter, input); 47 if (eol_len > 0) { 48 output->append(kEOL); 49 char_count = 0; 50 iter += (eol_len - 1); // -1 because we'll ++ in the for() above. 51 continue; 52 } 53 } 54 55 // Insert a soft line break if necessary. 56 int min_chars_needed = as_is ? kMaxCharPerLine - 2 : kMaxCharPerLine - 4; 57 if (!last_char && char_count > min_chars_needed) { 58 output->append("="); 59 output->append(kEOL); 60 char_count = 0; 61 } 62 63 // Finally, insert the actual character(s). 64 if (as_is) { 65 output->append(1, c); 66 char_count++; 67 } else { 68 output->append("="); 69 output->append(1, kHexTable[static_cast<int>((c >> 4) & 0xF)]); 70 output->append(1, kHexTable[static_cast<int>(c & 0x0F)]); 71 char_count += 3; 72 } 73 } 74 } 75 76 bool QuotedPrintableDecode(const std::string& input, std::string* output) { 77 bool success = true; 78 for (std::string::const_iterator iter = input.begin(); 79 iter!= input.end(); ++iter) { 80 char c = *iter; 81 if (c != '=') { 82 output->append(1, c); 83 continue; 84 } 85 if (input.end() - iter < 3) { 86 LOG(ERROR) << "unfinished = sequence in input string."; 87 success = false; 88 output->append(1, c); 89 continue; 90 } 91 char c2 = *(++iter); 92 char c3 = *(++iter); 93 if (c2 == '\r' && c3 == '\n') { 94 // Soft line break, ignored. 95 continue; 96 } 97 98 if (!IsHexDigit(c2) || !IsHexDigit(c3)) { 99 LOG(ERROR) << "invalid = sequence, = followed by non hexa digit " << 100 "chars: " << c2 << " " << c3; 101 success = false; 102 // Just insert the chars as is. 103 output->append("="); 104 output->append(1, c2); 105 output->append(1, c3); 106 continue; 107 } 108 109 int i1 = HexDigitToInt(c2); 110 int i2 = HexDigitToInt(c3); 111 char r = static_cast<char>(((i1 << 4) & 0xF0) | (i2 & 0x0F)); 112 output->append(1, r); 113 } 114 return success; 115 } 116 117 int IsEOL(const std::string::const_iterator& iter, const std::string& input) { 118 if (*iter == '\n') 119 return 1; // Single LF. 120 121 if (*iter == '\r') { 122 if ((iter + 1) == input.end() || *(iter + 1) != '\n') 123 return 1; // Single CR (Commodore and Old Macs). 124 return 2; // CR-LF. 125 } 126 127 return 0; 128 } 129 130 } // namespace net 131 } // namespace browser 132 } // namespace chrome 133