Implementing compat function codecs_open

This commit is contained in:
Miroslav Stampar 2025-12-26 00:04:31 +01:00
parent 137687e120
commit 2b44aa1fbb
4 changed files with 119 additions and 3 deletions

View File

@ -188,7 +188,7 @@ c4bfb493a03caf84dd362aec7c248097841de804b7413d0e1ecb8a90c8550bc0 lib/core/readl
d1bd70c1a55858495c727fbec91e30af267459c8f64d50fabf9e4ee2c007e920 lib/core/replication.py d1bd70c1a55858495c727fbec91e30af267459c8f64d50fabf9e4ee2c007e920 lib/core/replication.py
1d0f80b0193ac5204527bfab4bde1a7aee0f693fd008e86b4b29f606d1ef94f3 lib/core/revision.py 1d0f80b0193ac5204527bfab4bde1a7aee0f693fd008e86b4b29f606d1ef94f3 lib/core/revision.py
d2eb8e4b05ac93551272b3d4abfaf5b9f2d3ac92499a7704c16ed0b4f200db38 lib/core/session.py d2eb8e4b05ac93551272b3d4abfaf5b9f2d3ac92499a7704c16ed0b4f200db38 lib/core/session.py
8c5ad7a690a3c6843ad22c8d88c7facd33307c200a435820e7dcb1d7d7ccce4a lib/core/settings.py 07334f49a15c569a20523fcf2c7a8706d9e253e6b44c9cdb897796f91898f22a lib/core/settings.py
1c5eab9494eb969bc9ce118a2ea6954690c6851cbe54c18373c723b99734bf09 lib/core/shell.py 1c5eab9494eb969bc9ce118a2ea6954690c6851cbe54c18373c723b99734bf09 lib/core/shell.py
4eea6dcf023e41e3c64b210cb5c2efc7ca893b727f5e49d9c924f076bb224053 lib/core/subprocessng.py 4eea6dcf023e41e3c64b210cb5c2efc7ca893b727f5e49d9c924f076bb224053 lib/core/subprocessng.py
cdd352e1331c6b535e780f6edea79465cb55af53aa2114dcea0e8bf382e56d1a lib/core/target.py cdd352e1331c6b535e780f6edea79465cb55af53aa2114dcea0e8bf382e56d1a lib/core/target.py

View File

@ -47,6 +47,7 @@ from extra.beep.beep import beep
from extra.cloak.cloak import decloak from extra.cloak.cloak import decloak
from lib.core.bigarray import BigArray from lib.core.bigarray import BigArray
from lib.core.compat import cmp from lib.core.compat import cmp
from lib.core.compat import codecs_open
from lib.core.compat import LooseVersion from lib.core.compat import LooseVersion
from lib.core.compat import round from lib.core.compat import round
from lib.core.compat import xrange from lib.core.compat import xrange
@ -3819,7 +3820,7 @@ def openFile(filename, mode='r', encoding=UNICODE_ENCODING, errors="reversible",
return contextlib.closing(io.StringIO(readCachedFileContent(filename))) return contextlib.closing(io.StringIO(readCachedFileContent(filename)))
else: else:
try: try:
return codecs.open(filename, mode, encoding, errors, buffering) return codecs_open(filename, mode, encoding, errors, buffering)
except IOError: except IOError:
errMsg = "there has been a file opening error for filename '%s'. " % filename errMsg = "there has been a file opening error for filename '%s'. " % filename
errMsg += "Please check %s permissions on a file " % ("write" if mode and ('w' in mode or 'a' in mode or '+' in mode) else "read") errMsg += "Please check %s permissions on a file " % ("write" if mode and ('w' in mode or 'a' in mode or '+' in mode) else "read")

View File

@ -7,8 +7,10 @@ See the file 'LICENSE' for copying permission
from __future__ import division from __future__ import division
import codecs
import binascii import binascii
import functools import functools
import io
import math import math
import os import os
import random import random
@ -312,3 +314,116 @@ def LooseVersion(version):
result = float("NaN") result = float("NaN")
return result return result
# NOTE: codecs.open re-implementation (deprecated in Python 3.14)
try:
# Py2
_text_type = unicode
_bytes_types = (str, bytearray)
except NameError:
# Py3
_text_type = str
_bytes_types = (bytes, bytearray, memoryview)
_WRITE_CHARS = ("w", "a", "x", "+")
def _is_write_mode(mode):
return any(ch in mode for ch in _WRITE_CHARS)
class MixedWriteTextIO(object):
"""
Text-ish stream wrapper that accepts both text and bytes in write().
Bytes are decoded using the file's (encoding, errors) before writing.
Optionally approximates line-buffering by flushing when a newline is written.
"""
def __init__(self, fh, encoding, errors, line_buffered=False):
self._fh = fh
self._encoding = encoding
self._errors = errors
self._line_buffered = line_buffered
def write(self, data):
# bytes-like but not text -> decode
if isinstance(data, _bytes_types) and not isinstance(data, _text_type):
data = bytes(data).decode(self._encoding, self._errors)
elif not isinstance(data, _text_type):
data = _text_type(data)
n = self._fh.write(data)
# Approximate "line buffering" behavior if requested
if self._line_buffered and u"\n" in data:
try:
self._fh.flush()
except Exception:
pass
return n
def writelines(self, lines):
for x in lines:
self.write(x)
def __iter__(self):
return iter(self._fh)
def __next__(self):
return next(self._fh)
def next(self): # Py2
return self.__next__()
def __getattr__(self, name):
return getattr(self._fh, name)
def __enter__(self):
self._fh.__enter__()
return self
def __exit__(self, exc_type, exc, tb):
return self._fh.__exit__(exc_type, exc, tb)
def _codecs_open(filename, mode="r", encoding=None, errors="strict", buffering=-1):
"""
Replacement for deprecated codecs.open() entry point with sqlmap-friendly behavior.
- If encoding is None: return io.open(...) as-is.
- If encoding is set: force underlying binary mode and wrap via StreamReaderWriter
(like codecs.open()).
- For write-ish modes: return a wrapper that also accepts bytes on .write().
- Handles buffering=1 in binary mode by downgrading underlying buffering to -1,
while optionally preserving "flush on newline" behavior in the wrapper.
"""
if encoding is None:
return io.open(filename, mode, buffering=buffering)
bmode = mode
if "b" not in bmode:
bmode += "b"
# Avoid line-buffering warnings/errors on binary streams
line_buffered = (buffering == 1)
if line_buffered:
buffering = -1
f = io.open(filename, bmode, buffering=buffering)
try:
info = codecs.lookup(encoding)
srw = codecs.StreamReaderWriter(f, info.streamreader, info.streamwriter, errors)
srw.encoding = encoding
if _is_write_mode(mode):
return MixedWriteTextIO(srw, encoding, errors, line_buffered=line_buffered)
return srw
except Exception:
try:
f.close()
finally:
raise
codecs_open = _codecs_open if sys.version_info >= (3, 14) else codecs.open

View File

@ -19,7 +19,7 @@ from lib.core.enums import OS
from thirdparty import six from thirdparty import six
# sqlmap version (<major>.<minor>.<month>.<monthly commit>) # sqlmap version (<major>.<minor>.<month>.<monthly commit>)
VERSION = "1.9.12.16" VERSION = "1.9.12.17"
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable" TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34} TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE) VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)