Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sqlmapproject
GitHub Repository: sqlmapproject/sqlmap
Path: blob/master/lib/core/compat.py
3554 views
1
#!/usr/bin/env python
2
3
"""
4
Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
5
See the file 'LICENSE' for copying permission
6
"""
7
8
from __future__ import division
9
10
import codecs
11
import binascii
12
import functools
13
import io
14
import math
15
import os
16
import random
17
import re
18
import sys
19
import time
20
import uuid
21
22
class WichmannHill(random.Random):
23
"""
24
Reference: https://svn.python.org/projects/python/trunk/Lib/random.py
25
"""
26
27
VERSION = 1 # used by getstate/setstate
28
29
def seed(self, a=None):
30
"""Initialize internal state from hashable object.
31
32
None or no argument seeds from current time or from an operating
33
system specific randomness source if available.
34
35
If a is not None or an int or long, hash(a) is used instead.
36
37
If a is an int or long, a is used directly. Distinct values between
38
0 and 27814431486575L inclusive are guaranteed to yield distinct
39
internal states (this guarantee is specific to the default
40
Wichmann-Hill generator).
41
"""
42
43
if a is None:
44
try:
45
a = int(binascii.hexlify(os.urandom(16)), 16)
46
except NotImplementedError:
47
a = int(time.time() * 256) # use fractional seconds
48
49
if not isinstance(a, int):
50
a = hash(a)
51
52
a, x = divmod(a, 30268)
53
a, y = divmod(a, 30306)
54
a, z = divmod(a, 30322)
55
self._seed = int(x) + 1, int(y) + 1, int(z) + 1
56
57
self.gauss_next = None
58
59
def random(self):
60
"""Get the next random number in the range [0.0, 1.0)."""
61
62
# Wichman-Hill random number generator.
63
#
64
# Wichmann, B. A. & Hill, I. D. (1982)
65
# Algorithm AS 183:
66
# An efficient and portable pseudo-random number generator
67
# Applied Statistics 31 (1982) 188-190
68
#
69
# see also:
70
# Correction to Algorithm AS 183
71
# Applied Statistics 33 (1984) 123
72
#
73
# McLeod, A. I. (1985)
74
# A remark on Algorithm AS 183
75
# Applied Statistics 34 (1985),198-200
76
77
# This part is thread-unsafe:
78
# BEGIN CRITICAL SECTION
79
x, y, z = self._seed
80
x = (171 * x) % 30269
81
y = (172 * y) % 30307
82
z = (170 * z) % 30323
83
self._seed = x, y, z
84
# END CRITICAL SECTION
85
86
# Note: on a platform using IEEE-754 double arithmetic, this can
87
# never return 0.0 (asserted by Tim; proof too long for a comment).
88
return (x / 30269.0 + y / 30307.0 + z / 30323.0) % 1.0
89
90
def getstate(self):
91
"""Return internal state; can be passed to setstate() later."""
92
return self.VERSION, self._seed, self.gauss_next
93
94
def setstate(self, state):
95
"""Restore internal state from object returned by getstate()."""
96
version = state[0]
97
if version == 1:
98
version, self._seed, self.gauss_next = state
99
else:
100
raise ValueError("state with version %s passed to "
101
"Random.setstate() of version %s" %
102
(version, self.VERSION))
103
104
def jumpahead(self, n):
105
"""Act as if n calls to random() were made, but quickly.
106
107
n is an int, greater than or equal to 0.
108
109
Example use: If you have 2 threads and know that each will
110
consume no more than a million random numbers, create two Random
111
objects r1 and r2, then do
112
r2.setstate(r1.getstate())
113
r2.jumpahead(1000000)
114
Then r1 and r2 will use guaranteed-disjoint segments of the full
115
period.
116
"""
117
118
if n < 0:
119
raise ValueError("n must be >= 0")
120
x, y, z = self._seed
121
x = int(x * pow(171, n, 30269)) % 30269
122
y = int(y * pow(172, n, 30307)) % 30307
123
z = int(z * pow(170, n, 30323)) % 30323
124
self._seed = x, y, z
125
126
def __whseed(self, x=0, y=0, z=0):
127
"""Set the Wichmann-Hill seed from (x, y, z).
128
129
These must be integers in the range [0, 256).
130
"""
131
132
if not type(x) == type(y) == type(z) == int:
133
raise TypeError('seeds must be integers')
134
if not (0 <= x < 256 and 0 <= y < 256 and 0 <= z < 256):
135
raise ValueError('seeds must be in range(0, 256)')
136
if 0 == x == y == z:
137
# Initialize from current time
138
t = int(time.time() * 256)
139
t = int((t & 0xffffff) ^ (t >> 24))
140
t, x = divmod(t, 256)
141
t, y = divmod(t, 256)
142
t, z = divmod(t, 256)
143
# Zero is a poor seed, so substitute 1
144
self._seed = (x or 1, y or 1, z or 1)
145
146
self.gauss_next = None
147
148
def whseed(self, a=None):
149
"""Seed from hashable object's hash code.
150
151
None or no argument seeds from current time. It is not guaranteed
152
that objects with distinct hash codes lead to distinct internal
153
states.
154
155
This is obsolete, provided for compatibility with the seed routine
156
used prior to Python 2.1. Use the .seed() method instead.
157
"""
158
159
if a is None:
160
self.__whseed()
161
return
162
a = hash(a)
163
a, x = divmod(a, 256)
164
a, y = divmod(a, 256)
165
a, z = divmod(a, 256)
166
x = (x + a) % 256 or 1
167
y = (y + a) % 256 or 1
168
z = (z + a) % 256 or 1
169
self.__whseed(x, y, z)
170
171
def patchHeaders(headers):
172
if headers is not None and not hasattr(headers, "headers"):
173
if isinstance(headers, dict):
174
class _(dict):
175
def __getitem__(self, key):
176
for key_ in self:
177
if key_.lower() == key.lower():
178
return super(_, self).__getitem__(key_)
179
180
raise KeyError(key)
181
182
def get(self, key, default=None):
183
try:
184
return self[key]
185
except KeyError:
186
return default
187
188
headers = _(headers)
189
190
headers.headers = ["%s: %s\r\n" % (header, headers[header]) for header in headers]
191
192
return headers
193
194
def cmp(a, b):
195
"""
196
>>> cmp("a", "b")
197
-1
198
>>> cmp(2, 1)
199
1
200
"""
201
202
if a < b:
203
return -1
204
elif a > b:
205
return 1
206
else:
207
return 0
208
209
# Reference: https://github.com/urllib3/urllib3/blob/master/src/urllib3/filepost.py
210
def choose_boundary():
211
"""
212
>>> len(choose_boundary()) == 32
213
True
214
"""
215
216
retval = ""
217
218
try:
219
retval = uuid.uuid4().hex
220
except AttributeError:
221
retval = "".join(random.sample("0123456789abcdef", 1)[0] for _ in xrange(32))
222
223
return retval
224
225
# Reference: http://python3porting.com/differences.html
226
def round(x, d=0):
227
"""
228
>>> round(2.0)
229
2.0
230
>>> round(2.5)
231
3.0
232
"""
233
234
p = 10 ** d
235
if x > 0:
236
return float(math.floor((x * p) + 0.5)) / p
237
else:
238
return float(math.ceil((x * p) - 0.5)) / p
239
240
# Reference: https://code.activestate.com/recipes/576653-convert-a-cmp-function-to-a-key-function/
241
def cmp_to_key(mycmp):
242
"""Convert a cmp= function into a key= function"""
243
class K(object):
244
__slots__ = ['obj']
245
246
def __init__(self, obj, *args):
247
self.obj = obj
248
249
def __lt__(self, other):
250
return mycmp(self.obj, other.obj) < 0
251
252
def __gt__(self, other):
253
return mycmp(self.obj, other.obj) > 0
254
255
def __eq__(self, other):
256
return mycmp(self.obj, other.obj) == 0
257
258
def __le__(self, other):
259
return mycmp(self.obj, other.obj) <= 0
260
261
def __ge__(self, other):
262
return mycmp(self.obj, other.obj) >= 0
263
264
def __ne__(self, other):
265
return mycmp(self.obj, other.obj) != 0
266
267
def __hash__(self):
268
raise TypeError('hash not implemented')
269
270
return K
271
272
# Note: patch for Python 2.6
273
if not hasattr(functools, "cmp_to_key"):
274
functools.cmp_to_key = cmp_to_key
275
276
if sys.version_info >= (3, 0):
277
xrange = range
278
buffer = memoryview
279
else:
280
xrange = xrange
281
buffer = buffer
282
283
def LooseVersion(version):
284
"""
285
>>> LooseVersion("1.0") == LooseVersion("1.0")
286
True
287
>>> LooseVersion("1.0.1") > LooseVersion("1.0")
288
True
289
>>> LooseVersion("1.0.1-") == LooseVersion("1.0.1")
290
True
291
>>> LooseVersion("1.0.11") < LooseVersion("1.0.111")
292
True
293
>>> LooseVersion("foobar") > LooseVersion("1.0")
294
False
295
>>> LooseVersion("1.0") > LooseVersion("foobar")
296
False
297
>>> LooseVersion("3.22-mysql") == LooseVersion("3.22-mysql-ubuntu0.3")
298
True
299
>>> LooseVersion("8.0.22-0ubuntu0.20.04.2")
300
8.000022
301
"""
302
303
match = re.search(r"\A(\d[\d.]*)", version or "")
304
305
if match:
306
result = 0
307
value = match.group(1)
308
weight = 1.0
309
for part in value.strip('.').split('.'):
310
if part.isdigit():
311
result += int(part) * weight
312
weight *= 1e-3
313
else:
314
result = float("NaN")
315
316
return result
317
318
# NOTE: codecs.open re-implementation (deprecated in Python 3.14)
319
320
try:
321
# Py2
322
_text_type = unicode
323
_bytes_types = (str, bytearray)
324
except NameError:
325
# Py3
326
_text_type = str
327
_bytes_types = (bytes, bytearray, memoryview)
328
329
_WRITE_CHARS = ("w", "a", "x", "+")
330
331
def _is_write_mode(mode):
332
return any(ch in mode for ch in _WRITE_CHARS)
333
334
class MixedWriteTextIO(object):
335
"""
336
Text-ish stream wrapper that accepts both text and bytes in write().
337
Bytes are decoded using the file's (encoding, errors) before writing.
338
339
Optionally approximates line-buffering by flushing when a newline is written.
340
"""
341
def __init__(self, fh, encoding, errors, line_buffered=False):
342
self._fh = fh
343
self._encoding = encoding
344
self._errors = errors
345
self._line_buffered = line_buffered
346
347
def write(self, data):
348
# bytes-like but not text -> decode
349
if isinstance(data, _bytes_types) and not isinstance(data, _text_type):
350
data = bytes(data).decode(self._encoding, self._errors)
351
elif not isinstance(data, _text_type):
352
data = _text_type(data)
353
354
n = self._fh.write(data)
355
356
# Approximate "line buffering" behavior if requested
357
if self._line_buffered and u"\n" in data:
358
try:
359
self._fh.flush()
360
except Exception:
361
pass
362
363
return n
364
365
def writelines(self, lines):
366
for x in lines:
367
self.write(x)
368
369
def __iter__(self):
370
return iter(self._fh)
371
372
def __next__(self):
373
return next(self._fh)
374
375
def next(self): # Py2
376
return self.__next__()
377
378
def __getattr__(self, name):
379
return getattr(self._fh, name)
380
381
def __enter__(self):
382
self._fh.__enter__()
383
return self
384
385
def __exit__(self, exc_type, exc, tb):
386
return self._fh.__exit__(exc_type, exc, tb)
387
388
389
def _codecs_open(filename, mode="r", encoding=None, errors="strict", buffering=-1):
390
"""
391
Replacement for deprecated codecs.open() entry point with sqlmap-friendly behavior.
392
393
- If encoding is None: return io.open(...) as-is.
394
- If encoding is set: force underlying binary mode and wrap via StreamReaderWriter
395
(like codecs.open()).
396
- For write-ish modes: return a wrapper that also accepts bytes on .write().
397
- Handles buffering=1 in binary mode by downgrading underlying buffering to -1,
398
while optionally preserving "flush on newline" behavior in the wrapper.
399
"""
400
if encoding is None:
401
return io.open(filename, mode, buffering=buffering)
402
403
bmode = mode
404
if "b" not in bmode:
405
bmode += "b"
406
407
# Avoid line-buffering warnings/errors on binary streams
408
line_buffered = (buffering == 1)
409
if line_buffered:
410
buffering = -1
411
412
f = io.open(filename, bmode, buffering=buffering)
413
414
try:
415
info = codecs.lookup(encoding)
416
srw = codecs.StreamReaderWriter(f, info.streamreader, info.streamwriter, errors)
417
srw.encoding = encoding
418
419
if _is_write_mode(mode):
420
return MixedWriteTextIO(srw, encoding, errors, line_buffered=line_buffered)
421
422
return srw
423
except Exception:
424
try:
425
f.close()
426
finally:
427
raise
428
429
codecs_open = _codecs_open if sys.version_info >= (3, 14) else codecs.open
430
431