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