[pypy-svn] r61035 - in pypy/trunk/pypy/lib: . app_test

arigo at codespeak.net arigo at codespeak.net
Fri Jan 16 14:52:35 CET 2009


Author: arigo
Date: Fri Jan 16 14:52:34 2009
New Revision: 61035

Modified:
   pypy/trunk/pypy/lib/app_test/test_binascii.py
   pypy/trunk/pypy/lib/binascii.py
Log:
Kill the old b2a_qp() and copy it from C.
Allows a new test to pass.


Modified: pypy/trunk/pypy/lib/app_test/test_binascii.py
==============================================================================
--- pypy/trunk/pypy/lib/app_test/test_binascii.py	(original)
+++ pypy/trunk/pypy/lib/app_test/test_binascii.py	Fri Jan 16 14:52:34 2009
@@ -147,6 +147,12 @@
         f('')
     binascii.crc_hqx('', 0)
 
+def test_qp_bug_case():
+    assert binascii.b2a_qp('y'*77, False, False) == 'y'*75 + '=\nyy'
+    assert binascii.b2a_qp(' '*77, False, False) == ' '*75 + '=\n =20'
+    assert binascii.b2a_qp('y'*76, False, False) == 'y'*76
+    assert binascii.b2a_qp(' '*76, False, False) == ' '*75 + '=\n=20'
+
 def test_wrong_padding():
     s = 'CSixpLDtKSC/7Liuvsax4iC6uLmwMcijIKHaILzSwd/H0SC8+LCjwLsgv7W/+Mj3IQ'
     raises(binascii.Error, binascii.a2b_base64, s)

Modified: pypy/trunk/pypy/lib/binascii.py
==============================================================================
--- pypy/trunk/pypy/lib/binascii.py	(original)
+++ pypy/trunk/pypy/lib/binascii.py	Fri Jan 16 14:52:34 2009
@@ -254,70 +254,75 @@
             inp += 1
     return ''.join(odata)
 
-def b2a_qp(s, quotetabs=False, istext=True, header=False):
+def b2a_qp(data, quotetabs=False, istext=True, header=False):
     """quotetabs=True means that tab and space characters are always
        quoted.
        istext=False means that \r and \n are treated as regular characters
        header=True encodes space characters with '_' and requires
        real '_' characters to be quoted.
     """
-    crlf = s.find('\r\n')
-    lf = s.find('\n')
-    linebreak = None
-    if crlf >= 0 and crlf <= lf:
-        linebreak = '\r\n'
-    elif lf > 0:
-        linebreak = '\n'
-    
-    # if linebreak and linebreak == '\r\n':
-    # The above is more efficient for files with \n linebreaks,
-    # but fails badly on files with mixed linebreak encoding
-    if linebreak:
-        s = s.replace('\r\n', '\n')
-    else:
-        linebreak = '\n'
-
-    lines = s.split('\n')
+    MAXLINESIZE = 76
 
-    soft_lbr = '=' + linebreak
-    result = []
-    for line in lines:
-        charlist = []
-        count = 0
-        for c in line:
-            # Don't quote
-            if '!' <= c <= '<' or '>' <= c <= '^' or '`' <= c <= '~' or (
-                c == '_' and not header) or (c in '\n\r' and istext):
-                if count >= 75:
-                    charlist.append(soft_lbr)
-                    count = 0
-                charlist.append(c)
-                count += 1
-            elif not quotetabs and c in '\t ':
-                if count >= 72:
-                    charlist.append(soft_lbr)
-                    count = 0
-
-                if count >= 71: # Quote
-                    count += 3
-                    charlist.append('=' + two_hex_digits(ord(c)))
-                else: # Don't quote
-                    if c == ' ' and header:
-                        charlist.append('_')
-                    else:
-                        charlist.append(c)
-                    count += 1
-            else: # Quote
-                if count >= 72:
-                    charlist.append(soft_lbr)
-                    count = 0
-                count += 3
-                charlist.append('=' + two_hex_digits(ord(c)))
-        if charlist and charlist[-1] in '\t ':
-            # Whitespace at end of line has to be quoted
-            charlist[-1] = '=' + two_hex_digits(ord(charlist[-1]))
-        result.append(''.join(charlist))
-    return linebreak.join(result)
+    # See if this string is using CRLF line ends
+    lf = data.find('\n')
+    crlf = lf > 0 and data[lf-1] == '\r'
+
+    inp = 0
+    linelen = 0
+    odata = []
+    while inp < len(data):
+        c = data[inp]
+        if (c > '~' or
+            c == '=' or
+            (header and c == '_') or
+            (c == '.' and linelen == 0 and (inp == len(data) or
+                                            data[inp+1] == '\n' or
+                                            data[inp+1] == '\r')) or
+            (not istext and (c == '\r' or c == '\n')) or
+            ((c == '\t' or c == ' ') and (inp + 1 == len(data))) or
+            (c <= ' ' and c != '\r' and c != '\n' and
+             (quotetabs or (not quotetabs and (c != '\t' and c != ' '))))):
+            linelen += 3
+            if linelen >= MAXLINESIZE:
+                odata.append('=')
+                if crlf: odata.append('\r')
+                odata.append('\n')
+                linelen = 3
+            odata.append('=' + two_hex_digits(ord(c)))
+            inp += 1
+        else:
+            if (istext and
+                (c == '\n' or (inp+1 < len(data) and c == '\r' and
+                               data[inp+1] == '\n'))):
+                linelen = 0
+                # Protect against whitespace on end of line
+                if (len(odata) > 0 and
+                    (odata[-1] == ' ' or odata[-1] == '\t')):
+                    ch = ord(odata[-1])
+                    odata[-1] = '='
+                    odata.append(two_hex_digits(ch))
+
+                if crlf: odata.append('\r')
+                odata.append('\n')
+                if c == '\r':
+                    inp += 2
+                else:
+                    inp += 1
+            else:
+                if (inp + 1 < len(data) and
+                    data[inp+1] != '\n' and
+                    (linelen + 1) >= MAXLINESIZE):
+                    odata.append('=')
+                    if crlf: odata.append('\r')
+                    odata.append('\n')
+                    linelen = 0
+
+                linelen += 1
+                if header and c == ' ':
+                    c = '_'
+                odata.append(c)
+                inp += 1
+    return ''.join(odata)
 
 hex_numbers = '0123456789ABCDEF'
 def hex(n):



More information about the Pypy-commit mailing list