1#!/usr/bin/env python
2
3"""
4Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
5See the file 'LICENSE' for copying permission
6"""
7
8import binascii
9import re
10import string
11import sys
12
13if sys.version_info >= (3, 0):
14    xrange = range
15    text_type = str
16    string_types = (str,)
17    unichr = chr
18else:
19    text_type = unicode
20    string_types = (basestring,)
21
22# Regex used for recognition of hex encoded characters
23HEX_ENCODED_CHAR_REGEX = r"(?P<result>\\x[0-9A-Fa-f]{2})"
24
25# Raw chars that will be safe encoded to their slash (\) representations (e.g. newline to \n)
26SAFE_ENCODE_SLASH_REPLACEMENTS = "\t\n\r\x0b\x0c"
27
28# Characters that don't need to be safe encoded
29SAFE_CHARS = "".join([_ for _ in string.printable.replace('\\', '') if _ not in SAFE_ENCODE_SLASH_REPLACEMENTS])
30
31# Prefix used for hex encoded values
32HEX_ENCODED_PREFIX = r"\x"
33
34# Strings used for temporary marking of hex encoded prefixes (to prevent double encoding)
35HEX_ENCODED_PREFIX_MARKER = "__HEX_ENCODED_PREFIX__"
36
37# String used for temporary marking of slash characters
38SLASH_MARKER = "__SLASH__"
39
40def safecharencode(value):
41    """
42    Returns safe representation of a given basestring value
43
44    >>> safecharencode(u'test123') == u'test123'
45    True
46    >>> safecharencode(u'test\x01\x02\xaf') == u'test\\\\x01\\\\x02\\xaf'
47    True
48    """
49
50    retVal = value
51
52    if isinstance(value, string_types):
53        if any(_ not in SAFE_CHARS for _ in value):
54            retVal = retVal.replace(HEX_ENCODED_PREFIX, HEX_ENCODED_PREFIX_MARKER)
55            retVal = retVal.replace('\\', SLASH_MARKER)
56
57            for char in SAFE_ENCODE_SLASH_REPLACEMENTS:
58                retVal = retVal.replace(char, repr(char).strip('\''))
59
60            for char in set(retVal):
61                if not (char in string.printable or isinstance(value, text_type) and ord(char) >= 160):
62                    retVal = retVal.replace(char, '\\x%02x' % ord(char))
63
64            retVal = retVal.replace(SLASH_MARKER, "\\\\")
65            retVal = retVal.replace(HEX_ENCODED_PREFIX_MARKER, HEX_ENCODED_PREFIX)
66    elif isinstance(value, list):
67        for i in xrange(len(value)):
68            retVal[i] = safecharencode(value[i])
69
70    return retVal
71
72def safechardecode(value, binary=False):
73    """
74    Reverse function to safecharencode
75    """
76
77    retVal = value
78    if isinstance(value, string_types):
79        retVal = retVal.replace('\\\\', SLASH_MARKER)
80
81        while True:
82            match = re.search(HEX_ENCODED_CHAR_REGEX, retVal)
83            if match:
84                retVal = retVal.replace(match.group("result"), unichr(ord(binascii.unhexlify(match.group("result").lstrip("\\x")))))
85            else:
86                break
87
88        for char in SAFE_ENCODE_SLASH_REPLACEMENTS[::-1]:
89            retVal = retVal.replace(repr(char).strip('\''), char)
90
91        retVal = retVal.replace(SLASH_MARKER, '\\')
92
93        if binary:
94            if isinstance(retVal, text_type):
95                retVal = retVal.encode("utf8")
96
97    elif isinstance(value, (list, tuple)):
98        for i in xrange(len(value)):
99            retVal[i] = safechardecode(value[i])
100
101    return retVal
102