| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/net/quoted_printable.h" |
| |
| #include "base/logging.h" |
| #include "base/string_util.h" |
| |
| namespace { |
| |
| const int kMaxCharPerLine = 76; |
| const char* const kEOL = "\r\n"; |
| |
| const char kHexTable[] = "0123456789ABCDEF"; |
| |
| } // namespace |
| |
| namespace chrome { |
| namespace browser { |
| namespace net { |
| |
| void QuotedPrintableEncode(const std::string& input, std::string* output) { |
| // The number of characters in the current line. |
| int char_count = 0; |
| for (std::string::const_iterator iter = input.begin(); |
| iter != input.end(); ++iter) { |
| bool last_char = (iter + 1 == input.end()); |
| char c = *iter; |
| // Whether this character can be inserted without encoding. |
| bool as_is = false; |
| // All printable ASCII characters can be included as is (but for =). |
| if (c >= '!' && c <= '~' && c != '=') { |
| as_is = true; |
| } |
| |
| // Space and tab characters can be included as is if they don't appear at |
| // the end of a line or at then end of the input. |
| if (!as_is && (c == '\t' || c == ' ') && !last_char && |
| !IsEOL(iter + 1, input)) { |
| as_is = true; |
| } |
| |
| // End of line should be converted to CR-LF sequences. |
| if (!last_char) { |
| int eol_len = IsEOL(iter, input); |
| if (eol_len > 0) { |
| output->append(kEOL); |
| char_count = 0; |
| iter += (eol_len - 1); // -1 because we'll ++ in the for() above. |
| continue; |
| } |
| } |
| |
| // Insert a soft line break if necessary. |
| int min_chars_needed = as_is ? kMaxCharPerLine - 2 : kMaxCharPerLine - 4; |
| if (!last_char && char_count > min_chars_needed) { |
| output->append("="); |
| output->append(kEOL); |
| char_count = 0; |
| } |
| |
| // Finally, insert the actual character(s). |
| if (as_is) { |
| output->append(1, c); |
| char_count++; |
| } else { |
| output->append("="); |
| output->append(1, kHexTable[static_cast<int>((c >> 4) & 0xF)]); |
| output->append(1, kHexTable[static_cast<int>(c & 0x0F)]); |
| char_count += 3; |
| } |
| } |
| } |
| |
| bool QuotedPrintableDecode(const std::string& input, std::string* output) { |
| bool success = true; |
| for (std::string::const_iterator iter = input.begin(); |
| iter!= input.end(); ++iter) { |
| char c = *iter; |
| if (c != '=') { |
| output->append(1, c); |
| continue; |
| } |
| if (input.end() - iter < 3) { |
| LOG(ERROR) << "unfinished = sequence in input string."; |
| success = false; |
| output->append(1, c); |
| continue; |
| } |
| char c2 = *(++iter); |
| char c3 = *(++iter); |
| if (c2 == '\r' && c3 == '\n') { |
| // Soft line break, ignored. |
| continue; |
| } |
| |
| if (!IsHexDigit(c2) || !IsHexDigit(c3)) { |
| LOG(ERROR) << "invalid = sequence, = followed by non hexa digit " << |
| "chars: " << c2 << " " << c3; |
| success = false; |
| // Just insert the chars as is. |
| output->append("="); |
| output->append(1, c2); |
| output->append(1, c3); |
| continue; |
| } |
| |
| int i1 = HexDigitToInt(c2); |
| int i2 = HexDigitToInt(c3); |
| char r = static_cast<char>(((i1 << 4) & 0xF0) | (i2 & 0x0F)); |
| output->append(1, r); |
| } |
| return success; |
| } |
| |
| int IsEOL(const std::string::const_iterator& iter, const std::string& input) { |
| if (*iter == '\n') |
| return 1; // Single LF. |
| |
| if (*iter == '\r') { |
| if ((iter + 1) == input.end() || *(iter + 1) != '\n') |
| return 1; // Single CR (Commodore and Old Macs). |
| return 2; // CR-LF. |
| } |
| |
| return 0; |
| } |
| |
| } // namespace net |
| } // namespace browser |
| } // namespace chrome |