|
7 | 7 |
|
8 | 8 | from __future__ import division |
9 | 9 |
|
| 10 | +import codecs |
10 | 11 | import binascii |
11 | 12 | import functools |
| 13 | +import io |
12 | 14 | import math |
13 | 15 | import os |
14 | 16 | import random |
@@ -312,3 +314,116 @@ def LooseVersion(version): |
312 | 314 | result = float("NaN") |
313 | 315 |
|
314 | 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 |
0 commit comments