Skip to content
37 changes: 27 additions & 10 deletions Lib/email/quoprimime.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@
'unquote',
]

import re

from string import ascii_letters, digits, hexdigits

CRLF = '\r\n'
Expand Down Expand Up @@ -281,12 +279,7 @@ def decode(encoded, eol=NL):
decodestring = decode



def _unquote_match(match):
"""Turn a match in the form =AB to the ASCII character with value 0xab"""
s = match.group(0)
return unquote(s)

_HEX_TO_CHAR = {f'{i:02x}': chr(i) for i in range(256)}

# Header decoding is done a bit differently
def header_decode(s):
Expand All @@ -296,5 +289,29 @@ def header_decode(s):
quoted-printable (like =?iso-8859-1?q?Hello_World?=) -- please use
the high level email.header class for that functionality.
"""
s = s.replace('_', ' ')
return re.sub(r'=[a-fA-F0-9]{2}', _unquote_match, s, flags=re.ASCII)
# Check for regex =[a-fA-F0-9]{2}
s = s.replace("_", " ")

if '=' not in s:
return s

result = ''
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Repeatedly appending to a string in a loop is O(n**2). The standard idiom is to make a list of pieces (result=[]) and join after the loop. I suspect that re.sub does the C equivalent.

In any case, I agree that replacing an re call with this much code seems dubious (a bad tradeoff), so closing this might be best.

s_len = len(s)
i = 0
last_append = 0

while i < s_len:
if s[i] == '=' and i + 2 < s_len:
if (hex_str := s[i + 1:i + 3].lower()) in _HEX_TO_CHAR:
if last_append < i:
result += s[last_append:i]
result += _HEX_TO_CHAR[hex_str]
i += 3
last_append = i
continue
i += 1

if last_append < s_len:
result += s[last_append:]

return result
Loading