Home | History | Annotate | Download | only in net
      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