• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
QuotedPrintableEncode(const std::string & input,std::string * output)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 
QuotedPrintableDecode(const std::string & input,std::string * output)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 
IsEOL(const std::string::const_iterator & iter,const std::string & input)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