feat: Android-pyApi v1.0 - 全面翻译 Android SDK API 为 Python
52 个模块覆盖 Android + Java + org.json 标准库
This commit is contained in:
commit
bfe27fdc08
104 files changed
+58750
No files matched your search
Whitespace-only changes.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,628 @@
|
||||
"""
|
||||
Java crypto standard library APIs implemented in Python.
|
||||
javax.crypto package - Cipher, KeyGenerator, Mac, SecretKey, etc.
|
||||
"""
|
||||
|
||||
from .._core import Stub, AndroidOnlyError
|
||||
from .lang import RuntimeException
|
||||
import os as _os
|
||||
|
||||
# Try to import cryptography library
|
||||
try:
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher as _Cipher
|
||||
from cryptography.hazmat.primitives.ciphers import algorithms as _algorithms
|
||||
from cryptography.hazmat.primitives.ciphers import modes as _modes
|
||||
from cryptography.hazmat.primitives import hashes as _hashes
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa as _rsa
|
||||
from cryptography.hazmat.primitives.asymmetric import padding as _padding
|
||||
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC as _PBKDF2
|
||||
from cryptography.hazmat.backends import default_backend as _crypto_backend
|
||||
HAS_CRYPTOGRAPHY = True
|
||||
except ImportError:
|
||||
HAS_CRYPTOGRAPHY = False
|
||||
|
||||
from .security import (
|
||||
GeneralSecurityException, InvalidKeyException,
|
||||
NoSuchAlgorithmException, NoSuchProviderException,
|
||||
Key, SecretKeySpec, AlgorithmParameters, AlgorithmParametersSpi,
|
||||
AlgorithmParameterGenerator, AlgorithmParameterGeneratorSpi,
|
||||
Provider, SecureRandom,
|
||||
)
|
||||
|
||||
IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
|
||||
AEADBadTagException = type("AEADBadTagException", (GeneralSecurityException,), {})
|
||||
BadPaddingException = type("BadPaddingException", (GeneralSecurityException,), {})
|
||||
IllegalBlockSizeException = type("IllegalBlockSizeException", (GeneralSecurityException,), {})
|
||||
NoSuchPaddingException = type("NoSuchPaddingException", (GeneralSecurityException,), {})
|
||||
ShortBufferException = type("ShortBufferException", (GeneralSecurityException,), {})
|
||||
ExemptionMechanismException = type("ExemptionMechanismException", (GeneralSecurityException,), {})
|
||||
|
||||
__all__ = [
|
||||
"Cipher", "CipherSpi",
|
||||
"KeyGenerator", "KeyGeneratorSpi",
|
||||
"SecretKey", "SecretKeyFactory", "SecretKeyFactorySpi",
|
||||
"Mac", "MacSpi",
|
||||
"IvParameterSpec", "PBEParameterSpec", "GCMParameterSpec",
|
||||
"OAEPParameterSpec", "PSource", "MGF1ParameterSpec",
|
||||
"DHParameterSpec", "DSAParameterSpec",
|
||||
"ECParameterSpec", "ECGenParameterSpec", "ECPoint",
|
||||
"ECField", "ECFieldF2m", "ECFieldFp", "EllipticCurve",
|
||||
"AlgorithmParameters", "AlgorithmParameterGenerator",
|
||||
"AlgorithmParametersSpi",
|
||||
"AEADBadTagException", "BadPaddingException",
|
||||
"IllegalBlockSizeException", "NoSuchPaddingException",
|
||||
"ShortBufferException",
|
||||
"ExemptionMechanism", "ExemptionMechanismException",
|
||||
"ExemptionMechanismSpi",
|
||||
]
|
||||
|
||||
|
||||
# ============================================================
|
||||
# SecretKey
|
||||
# ============================================================
|
||||
|
||||
class SecretKey(Key):
|
||||
def __init__(self, key_bytes=None, algorithm=""):
|
||||
super().__init__()
|
||||
self._key = key_bytes or b""
|
||||
self._algorithm = algorithm
|
||||
|
||||
def getAlgorithm(self):
|
||||
return self._algorithm
|
||||
|
||||
def getFormat(self):
|
||||
return "RAW"
|
||||
|
||||
def getEncoded(self):
|
||||
return self._key
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Cipher
|
||||
# ============================================================
|
||||
|
||||
class Cipher(Stub):
|
||||
ENCRYPT_MODE = 1
|
||||
DECRYPT_MODE = 2
|
||||
WRAP_MODE = 3
|
||||
UNWRAP_MODE = 4
|
||||
PUBLIC_KEY = 1
|
||||
PRIVATE_KEY = 2
|
||||
SECRET_KEY = 3
|
||||
|
||||
def __init__(self, transformation):
|
||||
super().__init__()
|
||||
self._transformation = transformation
|
||||
self._opmode = 0
|
||||
self._key = None
|
||||
self._iv = None
|
||||
self._provider = Provider("AndroidOpenSSL", 1.0, "Android OpenSSL provider")
|
||||
|
||||
@staticmethod
|
||||
def getInstance(transformation, provider=None):
|
||||
return Cipher(transformation)
|
||||
|
||||
def init(self, opmode, key_or_cert, params=None, random=None):
|
||||
self._opmode = opmode
|
||||
self._key = key_or_cert
|
||||
if isinstance(params, IvParameterSpec):
|
||||
self._iv = params.getIV()
|
||||
elif isinstance(params, GCMParameterSpec):
|
||||
self._iv = params.getIV()
|
||||
|
||||
def doFinal(self, input_data=None):
|
||||
if input_data is None:
|
||||
return b""
|
||||
if HAS_CRYPTOGRAPHY and self._key is not None:
|
||||
try:
|
||||
algo = self._transformation.split("/")[0].upper()
|
||||
key_bytes = self._key.getEncoded() if hasattr(self._key, "getEncoded") else bytes(self._key)
|
||||
iv = self._iv or b"\x00" * 16
|
||||
if algo == "AES":
|
||||
if len(iv) == 12:
|
||||
mode = _modes.GCM(iv)
|
||||
else:
|
||||
mode = _modes.CBC(iv)
|
||||
cipher = _Cipher(_algorithms.AES(key_bytes), mode, backend=_crypto_backend())
|
||||
elif algo == "DES":
|
||||
cipher = _Cipher(_algorithms.TripleDES(key_bytes), _modes.CBC(iv), backend=_crypto_backend())
|
||||
else:
|
||||
return self._basic_cipher(input_data)
|
||||
if self._opmode == Cipher.ENCRYPT_MODE:
|
||||
encryptor = cipher.encryptor()
|
||||
result = encryptor.update(input_data) + encryptor.finalize()
|
||||
return result
|
||||
else:
|
||||
decryptor = cipher.decryptor()
|
||||
result = decryptor.update(input_data) + decryptor.finalize()
|
||||
return result
|
||||
except Exception:
|
||||
return self._basic_cipher(input_data)
|
||||
else:
|
||||
return self._basic_cipher(input_data)
|
||||
|
||||
def _basic_cipher(self, data):
|
||||
if self._opmode == Cipher.ENCRYPT_MODE:
|
||||
if self._key is not None:
|
||||
key_bytes = self._key.getEncoded() if hasattr(self._key, "getEncoded") else bytes(self._key)
|
||||
return bytes([(b ^ key_bytes[i % len(key_bytes)]) & 0xFF for i, b in enumerate(data)])
|
||||
return data
|
||||
else:
|
||||
if self._key is not None:
|
||||
key_bytes = self._key.getEncoded() if hasattr(self._key, "getEncoded") else bytes(self._key)
|
||||
return bytes([(b ^ key_bytes[i % len(key_bytes)]) & 0xFF for i, b in enumerate(data)])
|
||||
return data
|
||||
|
||||
def update(self, input_data):
|
||||
return self._basic_cipher(input_data)
|
||||
|
||||
def getBlockSize(self):
|
||||
algo = self._transformation.split("/")[0].upper()
|
||||
if algo == "AES":
|
||||
return 16
|
||||
if algo == "DES" or algo == "DESede":
|
||||
return 8
|
||||
return 1
|
||||
|
||||
def getOutputSize(self, input_len):
|
||||
bs = self.getBlockSize()
|
||||
if bs > 1:
|
||||
return input_len + bs - (input_len % bs)
|
||||
return input_len
|
||||
|
||||
def getIV(self):
|
||||
return self._iv
|
||||
|
||||
def getParameters(self):
|
||||
if self._iv:
|
||||
return AlgorithmParameters(self._transformation.split("/")[0])
|
||||
return None
|
||||
|
||||
def getAlgorithm(self):
|
||||
return self._transformation
|
||||
|
||||
def getProvider(self):
|
||||
return self._provider
|
||||
|
||||
def getExemptionMechanism(self):
|
||||
return None
|
||||
|
||||
def unwrap(self, wrapped_key, wrapped_key_algorithm, wrapped_key_type):
|
||||
return SecretKey(wrapped_key, wrapped_key_algorithm)
|
||||
|
||||
def wrap(self, key):
|
||||
key_bytes = key.getEncoded() if hasattr(key, "getEncoded") else b""
|
||||
return self.doFinal(key_bytes)
|
||||
|
||||
@staticmethod
|
||||
def maxAllowedKeyLength(transformation):
|
||||
return 2147483647
|
||||
|
||||
|
||||
class CipherSpi(Stub):
|
||||
pass
|
||||
|
||||
|
||||
# ============================================================
|
||||
# KeyGenerator
|
||||
# ============================================================
|
||||
|
||||
class KeyGenerator(Stub):
|
||||
def __init__(self, algorithm):
|
||||
super().__init__()
|
||||
self._algorithm = algorithm
|
||||
self._key_size = 128
|
||||
self._secure_random = None
|
||||
|
||||
@staticmethod
|
||||
def getInstance(algorithm, provider=None):
|
||||
return KeyGenerator(algorithm)
|
||||
|
||||
def init(self, size_or_random, random=None):
|
||||
if isinstance(size_or_random, int):
|
||||
self._key_size = size_or_random
|
||||
self._secure_random = random
|
||||
else:
|
||||
self._secure_random = size_or_random
|
||||
|
||||
def generateKey(self):
|
||||
key_bytes = _os.urandom(self._key_size // 8)
|
||||
return SecretKey(key_bytes, self._algorithm)
|
||||
|
||||
def getAlgorithm(self):
|
||||
return self._algorithm
|
||||
|
||||
def getProvider(self):
|
||||
return Provider("AndroidOpenSSL", 1.0, "Android OpenSSL provider")
|
||||
|
||||
|
||||
class KeyGeneratorSpi(Stub):
|
||||
pass
|
||||
|
||||
|
||||
# ============================================================
|
||||
# SecretKeyFactory
|
||||
# ============================================================
|
||||
|
||||
class SecretKeyFactory(Stub):
|
||||
def __init__(self, algorithm):
|
||||
super().__init__()
|
||||
self._algorithm = algorithm
|
||||
|
||||
@staticmethod
|
||||
def getInstance(algorithm, provider=None):
|
||||
return SecretKeyFactory(algorithm)
|
||||
|
||||
def generateSecret(self, key_spec):
|
||||
if isinstance(key_spec, SecretKeySpec):
|
||||
return SecretKey(key_spec.getEncoded(), self._algorithm)
|
||||
return SecretKey(b"", self._algorithm)
|
||||
|
||||
def getKeySpec(self, secret_key, key_spec_cls):
|
||||
return SecretKeySpec(secret_key.getEncoded(), self._algorithm)
|
||||
|
||||
def translateKey(self, key):
|
||||
return key
|
||||
|
||||
def getAlgorithm(self):
|
||||
return self._algorithm
|
||||
|
||||
|
||||
class SecretKeyFactorySpi(Stub):
|
||||
pass
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Mac
|
||||
# ============================================================
|
||||
|
||||
class Mac(Stub):
|
||||
def __init__(self, algorithm):
|
||||
super().__init__()
|
||||
self._algorithm = algorithm
|
||||
self._key = None
|
||||
self._state = "UNINITIALIZED"
|
||||
self._data = b""
|
||||
|
||||
@staticmethod
|
||||
def getInstance(algorithm, provider=None):
|
||||
return Mac(algorithm)
|
||||
|
||||
def init(self, key, params=None):
|
||||
self._key = key
|
||||
self._state = "INITIALIZED"
|
||||
self._data = b""
|
||||
|
||||
def update(self, input_data, offset=0, length=-1):
|
||||
if length < 0:
|
||||
self._data += bytes(input_data)
|
||||
else:
|
||||
self._data += bytes(input_data[offset:offset+length])
|
||||
|
||||
def doFinal(self, input_data=None):
|
||||
if input_data is not None:
|
||||
self._data += bytes(input_data)
|
||||
if HAS_CRYPTOGRAPHY and self._key is not None:
|
||||
try:
|
||||
key_bytes = self._key.getEncoded() if hasattr(self._key, "getEncoded") else bytes(self._key)
|
||||
algo = self._algorithm.lower().replace("-", "")
|
||||
if "sha256" in algo or "sha-256" in self._algorithm:
|
||||
h = _hashlib.sha256(key_bytes + self._data)
|
||||
elif "sha1" in algo or "sha-1" in self._algorithm:
|
||||
h = _hashlib.sha1(key_bytes + self._data)
|
||||
elif "md5" in algo:
|
||||
h = _hashlib.md5(key_bytes + self._data)
|
||||
else:
|
||||
h = _hashlib.sha256(key_bytes + self._data)
|
||||
result = h.digest()
|
||||
self._data = b""
|
||||
return result
|
||||
except Exception:
|
||||
pass
|
||||
import hashlib as _hashlib
|
||||
key_bytes = self._key.getEncoded() if self._key and hasattr(self._key, "getEncoded") else b"key"
|
||||
h = _hashlib.sha256(key_bytes + self._data)
|
||||
result = h.digest()
|
||||
self._data = b""
|
||||
return result
|
||||
|
||||
def reset(self):
|
||||
self._data = b""
|
||||
|
||||
def getAlgorithm(self):
|
||||
return self._algorithm
|
||||
|
||||
def getMacLength(self):
|
||||
return 32
|
||||
|
||||
def getProvider(self):
|
||||
return Provider("AndroidOpenSSL", 1.0, "Android OpenSSL provider")
|
||||
|
||||
|
||||
class MacSpi(Stub):
|
||||
pass
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Parameter specs
|
||||
# ============================================================
|
||||
|
||||
class IvParameterSpec(Stub):
|
||||
def __init__(self, iv):
|
||||
super().__init__()
|
||||
self._iv = bytes(iv)
|
||||
|
||||
def getIV(self):
|
||||
return self._iv
|
||||
|
||||
|
||||
class PBEParameterSpec(Stub):
|
||||
def __init__(self, salt, iteration_count):
|
||||
super().__init__()
|
||||
self._salt = bytes(salt)
|
||||
self._iteration_count = iteration_count
|
||||
|
||||
def getSalt(self):
|
||||
return self._salt
|
||||
|
||||
def getIterationCount(self):
|
||||
return self._iteration_count
|
||||
|
||||
|
||||
class GCMParameterSpec(Stub):
|
||||
def __init__(self, t_len, src):
|
||||
super().__init__()
|
||||
self._t_len = t_len
|
||||
self._iv = bytes(src)
|
||||
|
||||
def getTLen(self):
|
||||
return self._t_len
|
||||
|
||||
def getIV(self):
|
||||
return self._iv
|
||||
|
||||
|
||||
class OAEPParameterSpec(Stub):
|
||||
def __init__(self, md_name, mgf_name, mgf_spec, p_src):
|
||||
super().__init__()
|
||||
self._md_name = md_name
|
||||
self._mgf_name = mgf_name
|
||||
self._mgf_spec = mgf_spec
|
||||
self._p_src = p_src
|
||||
|
||||
def getDigestAlgorithm(self):
|
||||
return self._md_name
|
||||
|
||||
def getMGFAlgorithm(self):
|
||||
return self._mgf_name
|
||||
|
||||
def getMGFParameters(self):
|
||||
return self._mgf_spec
|
||||
|
||||
def getPSource(self):
|
||||
return self._p_src
|
||||
|
||||
|
||||
class PSource(Stub):
|
||||
class PSpecified(Stub):
|
||||
DEFAULT = None
|
||||
|
||||
def __init__(self, p):
|
||||
super().__init__()
|
||||
self._p = p
|
||||
|
||||
def getValue(self):
|
||||
return self._p
|
||||
|
||||
def __init__(self, p_src_id):
|
||||
super().__init__()
|
||||
self._p_src_id = p_src_id
|
||||
|
||||
def getAlgorithm(self):
|
||||
return self._p_src_id
|
||||
|
||||
|
||||
PSource.PSpecified.DEFAULT = PSource.PSpecified(b"")
|
||||
|
||||
|
||||
class MGF1ParameterSpec(Stub):
|
||||
SHA1 = None
|
||||
SHA256 = None
|
||||
SHA384 = None
|
||||
SHA512 = None
|
||||
|
||||
def __init__(self, md_name):
|
||||
super().__init__()
|
||||
self._md_name = md_name
|
||||
|
||||
def getDigestAlgorithm(self):
|
||||
return self._md_name
|
||||
|
||||
def toString(self):
|
||||
return f"MGF1 {self._md_name}"
|
||||
|
||||
|
||||
MGF1ParameterSpec.SHA1 = MGF1ParameterSpec("SHA-1")
|
||||
MGF1ParameterSpec.SHA256 = MGF1ParameterSpec("SHA-256")
|
||||
MGF1ParameterSpec.SHA384 = MGF1ParameterSpec("SHA-384")
|
||||
MGF1ParameterSpec.SHA512 = MGF1ParameterSpec("SHA-512")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# DH / DSA / EC parameter specs (stubs)
|
||||
# ============================================================
|
||||
|
||||
class DHParameterSpec(Stub):
|
||||
def __init__(self, p, g, l=0):
|
||||
super().__init__()
|
||||
self._p = p
|
||||
self._g = g
|
||||
self._l = l
|
||||
|
||||
def getP(self):
|
||||
return self._p
|
||||
|
||||
def getG(self):
|
||||
return self._g
|
||||
|
||||
def getL(self):
|
||||
return self._l
|
||||
|
||||
|
||||
class DSAParameterSpec(Stub):
|
||||
def __init__(self, p, q, g):
|
||||
super().__init__()
|
||||
self._p = p
|
||||
self._q = q
|
||||
self._g = g
|
||||
|
||||
def getP(self):
|
||||
return self._p
|
||||
|
||||
def getQ(self):
|
||||
return self._q
|
||||
|
||||
def getG(self):
|
||||
return self._g
|
||||
|
||||
|
||||
class ECPoint(Stub):
|
||||
def __init__(self, affine_x, affine_y):
|
||||
super().__init__()
|
||||
self._affine_x = affine_x
|
||||
self._affine_y = affine_y
|
||||
|
||||
def getAffineX(self):
|
||||
return self._affine_x
|
||||
|
||||
def getAffineY(self):
|
||||
return self._affine_y
|
||||
|
||||
def equals(self, other):
|
||||
if isinstance(other, ECPoint):
|
||||
return self._affine_x == other._affine_x and self._affine_y == other._affine_y
|
||||
return False
|
||||
|
||||
def hashCode(self):
|
||||
return hash((self._affine_x, self._affine_y))
|
||||
|
||||
|
||||
class ECField(Stub):
|
||||
def getFieldSize(self):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class ECFieldFp(ECField):
|
||||
def __init__(self, p):
|
||||
super().__init__()
|
||||
self._p = p
|
||||
|
||||
def getP(self):
|
||||
return self._p
|
||||
|
||||
def getFieldSize(self):
|
||||
return self._p.bit_length()
|
||||
|
||||
|
||||
class ECFieldF2m(ECField):
|
||||
def __init__(self, m, ks=None):
|
||||
super().__init__()
|
||||
self._m = m
|
||||
self._ks = ks
|
||||
|
||||
def getM(self):
|
||||
return self._m
|
||||
|
||||
def getMidTermsOfReductionPolynomial(self):
|
||||
return self._ks
|
||||
|
||||
def getFieldSize(self):
|
||||
return self._m
|
||||
|
||||
|
||||
class EllipticCurve(Stub):
|
||||
def __init__(self, field, a, b, seed=None):
|
||||
super().__init__()
|
||||
self._field = field
|
||||
self._a = a
|
||||
self._b = b
|
||||
self._seed = seed
|
||||
|
||||
def getField(self):
|
||||
return self._field
|
||||
|
||||
def getA(self):
|
||||
return self._a
|
||||
|
||||
def getB(self):
|
||||
return self._b
|
||||
|
||||
def getSeed(self):
|
||||
return self._seed
|
||||
|
||||
|
||||
class ECParameterSpec(Stub):
|
||||
def __init__(self, curve, generator, order, cofactor, seed=None):
|
||||
super().__init__()
|
||||
self._curve = curve
|
||||
self._generator = generator
|
||||
self._order = order
|
||||
self._cofactor = cofactor
|
||||
|
||||
def getCurve(self):
|
||||
return self._curve
|
||||
|
||||
def getGenerator(self):
|
||||
return self._generator
|
||||
|
||||
def getOrder(self):
|
||||
return self._order
|
||||
|
||||
def getCofactor(self):
|
||||
return self._cofactor
|
||||
|
||||
|
||||
class ECGenParameterSpec(Stub):
|
||||
def __init__(self, name):
|
||||
super().__init__()
|
||||
self._name = name
|
||||
|
||||
def getName(self):
|
||||
return self._name
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ExemptionMechanism
|
||||
# ============================================================
|
||||
|
||||
class ExemptionMechanism(Stub):
|
||||
def __init__(self, name):
|
||||
super().__init__()
|
||||
self._name = name
|
||||
self._state = False
|
||||
|
||||
@staticmethod
|
||||
def getInstance(name, provider=None):
|
||||
return ExemptionMechanism(name)
|
||||
|
||||
def init(self, key):
|
||||
self._state = False
|
||||
|
||||
def isCryptoAllowed(self, key):
|
||||
return True
|
||||
|
||||
def genExemptionBlob(self, data=None):
|
||||
return b""
|
||||
|
||||
def getName(self):
|
||||
return self._name
|
||||
|
||||
def getOutputSize(self, input_len):
|
||||
return input_len
|
||||
|
||||
def storeMechanism(self, mechanism):
|
||||
pass
|
||||
|
||||
|
||||
class ExemptionMechanismSpi(Stub):
|
||||
pass
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,683 @@
|
||||
"""
|
||||
Java math standard library APIs implemented in Python.
|
||||
java.math package - BigInteger, BigDecimal, MathContext, RoundingMode.
|
||||
"""
|
||||
|
||||
from .._core import Stub
|
||||
from .lang import Comparable
|
||||
from decimal import (
|
||||
Decimal as _Decimal,
|
||||
ROUND_DOWN as _DEC_ROUND_DOWN,
|
||||
ROUND_HALF_UP as _DEC_ROUND_HALF_UP,
|
||||
ROUND_HALF_EVEN as _DEC_ROUND_HALF_EVEN,
|
||||
ROUND_UP as _DEC_ROUND_UP,
|
||||
ROUND_CEILING as _DEC_ROUND_CEILING,
|
||||
ROUND_FLOOR as _DEC_ROUND_FLOOR,
|
||||
ROUND_HALF_DOWN as _DEC_ROUND_HALF_DOWN,
|
||||
localcontext as _local_context,
|
||||
getcontext as _get_context,
|
||||
)
|
||||
import random as _random
|
||||
import math as _py_math
|
||||
import sys as _sys
|
||||
|
||||
__all__ = [
|
||||
"BigInteger", "BigDecimal", "MathContext", "RoundingMode",
|
||||
]
|
||||
|
||||
|
||||
# ============================================================
|
||||
# RoundingMode
|
||||
# ============================================================
|
||||
|
||||
class RoundingMode(Stub):
|
||||
UP = 0
|
||||
DOWN = 1
|
||||
CEILING = 2
|
||||
FLOOR = 3
|
||||
HALF_UP = 4
|
||||
HALF_DOWN = 5
|
||||
HALF_EVEN = 6
|
||||
UNNECESSARY = 7
|
||||
|
||||
_names = {
|
||||
0: "UP", 1: "DOWN", 2: "CEILING", 3: "FLOOR",
|
||||
4: "HALF_UP", 5: "HALF_DOWN", 6: "HALF_EVEN", 7: "UNNECESSARY",
|
||||
}
|
||||
|
||||
_py_map = {
|
||||
0: _DEC_ROUND_UP,
|
||||
1: _DEC_ROUND_DOWN,
|
||||
2: _DEC_ROUND_CEILING,
|
||||
3: _DEC_ROUND_FLOOR,
|
||||
4: _DEC_ROUND_HALF_UP,
|
||||
5: _DEC_ROUND_HALF_DOWN,
|
||||
6: _DEC_ROUND_HALF_EVEN,
|
||||
7: _DEC_ROUND_HALF_EVEN, # closest approximation
|
||||
}
|
||||
|
||||
def __init__(self, value):
|
||||
super().__init__()
|
||||
self._value = value
|
||||
|
||||
def toString(self):
|
||||
return self._names.get(self._value, "UNKNOWN")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# MathContext
|
||||
# ============================================================
|
||||
|
||||
class MathContext(Stub):
|
||||
UNLIMITED = None
|
||||
DECIMAL32 = None
|
||||
DECIMAL64 = None
|
||||
DECIMAL128 = None
|
||||
|
||||
def __init__(self, *args):
|
||||
super().__init__()
|
||||
if len(args) == 1:
|
||||
if isinstance(args[0], str):
|
||||
s = args[0].strip().lower()
|
||||
if s == "precision=7 roundingmode=half_even":
|
||||
self._precision = 7
|
||||
self._rounding_mode = RoundingMode.HALF_EVEN
|
||||
elif s == "precision=16 roundingmode=half_even":
|
||||
self._precision = 16
|
||||
self._rounding_mode = RoundingMode.HALF_EVEN
|
||||
elif s == "precision=34 roundingmode=half_even":
|
||||
self._precision = 34
|
||||
self._rounding_mode = RoundingMode.HALF_EVEN
|
||||
else:
|
||||
self._precision = 0
|
||||
self._rounding_mode = RoundingMode.HALF_UP
|
||||
else:
|
||||
self._precision = int(args[0])
|
||||
self._rounding_mode = RoundingMode.HALF_UP
|
||||
elif len(args) == 2:
|
||||
self._precision = int(args[0])
|
||||
self._rounding_mode = args[1]
|
||||
|
||||
def getPrecision(self):
|
||||
return self._precision
|
||||
|
||||
def getRoundingMode(self):
|
||||
return self._rounding_mode
|
||||
|
||||
def equals(self, other):
|
||||
if isinstance(other, MathContext):
|
||||
return (self._precision == other._precision and
|
||||
self._rounding_mode == other._rounding_mode)
|
||||
return False
|
||||
|
||||
def hashCode(self):
|
||||
return hash((self._precision, self._rounding_mode)) & 0x7FFFFFFF
|
||||
|
||||
def toString(self):
|
||||
return f"precision={self._precision} roundingMode={self._rounding_mode.toString()}"
|
||||
|
||||
|
||||
MathContext.UNLIMITED = MathContext(0)
|
||||
MathContext.DECIMAL32 = MathContext(7, RoundingMode.HALF_EVEN)
|
||||
MathContext.DECIMAL64 = MathContext(16, RoundingMode.HALF_EVEN)
|
||||
MathContext.DECIMAL128 = MathContext(34, RoundingMode.HALF_EVEN)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# BigInteger
|
||||
# ============================================================
|
||||
|
||||
class BigInteger(Comparable):
|
||||
ZERO = None
|
||||
ONE = None
|
||||
TEN = None
|
||||
|
||||
def __init__(self, *args):
|
||||
super().__init__()
|
||||
if len(args) == 0:
|
||||
self._value = 0
|
||||
elif len(args) == 1:
|
||||
if isinstance(args[0], str):
|
||||
self._value = int(str(args[0]))
|
||||
elif isinstance(args[0], bytes):
|
||||
self._value = int.from_bytes(args[0], byteorder="big", signed=True)
|
||||
elif isinstance(args[0], bytearray):
|
||||
self._value = int.from_bytes(bytes(args[0]), byteorder="big", signed=True)
|
||||
elif isinstance(args[0], int):
|
||||
self._value = args[0]
|
||||
elif isinstance(args[0], BigInteger):
|
||||
self._value = args[0]._value
|
||||
else:
|
||||
self._value = int(args[0])
|
||||
elif len(args) == 2:
|
||||
if isinstance(args[1], _random.Random):
|
||||
bit_length, rng = args
|
||||
self._value = rng.getrandbits(bit_length)
|
||||
elif isinstance(args[1], int):
|
||||
val_str, radix = args
|
||||
self._value = int(str(val_str), radix)
|
||||
else:
|
||||
self._value = int.from_bytes(bytes(args[0]), byteorder="big", signed=True)
|
||||
else:
|
||||
self._value = 0
|
||||
|
||||
@staticmethod
|
||||
def valueOf(val):
|
||||
if isinstance(val, int):
|
||||
if val == 0:
|
||||
return BigInteger.ZERO
|
||||
if val == 1:
|
||||
return BigInteger.ONE
|
||||
if val == 10:
|
||||
return BigInteger.TEN
|
||||
return BigInteger(val)
|
||||
|
||||
def add(self, other):
|
||||
if isinstance(other, BigInteger):
|
||||
return BigInteger(self._value + other._value)
|
||||
return BigInteger(self._value + int(other))
|
||||
|
||||
def subtract(self, other):
|
||||
if isinstance(other, BigInteger):
|
||||
return BigInteger(self._value - other._value)
|
||||
return BigInteger(self._value - int(other))
|
||||
|
||||
def multiply(self, other):
|
||||
if isinstance(other, BigInteger):
|
||||
return BigInteger(self._value * other._value)
|
||||
return BigInteger(self._value * int(other))
|
||||
|
||||
def divide(self, other):
|
||||
if isinstance(other, BigInteger):
|
||||
return BigInteger(self._value // other._value)
|
||||
return BigInteger(self._value // int(other))
|
||||
|
||||
def pow(self, exponent):
|
||||
return BigInteger(self._value ** exponent)
|
||||
|
||||
def gcd(self, other):
|
||||
return BigInteger(_py_math.gcd(self._value, other._value if isinstance(other, BigInteger) else int(other)))
|
||||
|
||||
def abs(self):
|
||||
return BigInteger(abs(self._value))
|
||||
|
||||
def negate(self):
|
||||
return BigInteger(-self._value)
|
||||
|
||||
def signum(self):
|
||||
if self._value > 0:
|
||||
return 1
|
||||
if self._value < 0:
|
||||
return -1
|
||||
return 0
|
||||
|
||||
def mod(self, m):
|
||||
if isinstance(m, BigInteger):
|
||||
return BigInteger(self._value % m._value)
|
||||
return BigInteger(self._value % int(m))
|
||||
|
||||
def remainder(self, other):
|
||||
if isinstance(other, BigInteger):
|
||||
return BigInteger(self._value % other._value)
|
||||
return BigInteger(self._value % int(other))
|
||||
|
||||
def and_(self, other):
|
||||
return BigInteger(self._value & (other._value if isinstance(other, BigInteger) else int(other)))
|
||||
|
||||
def or_(self, other):
|
||||
return BigInteger(self._value | (other._value if isinstance(other, BigInteger) else int(other)))
|
||||
|
||||
def xor(self, other):
|
||||
return BigInteger(self._value ^ (other._value if isinstance(other, BigInteger) else int(other)))
|
||||
|
||||
def not_(self):
|
||||
return BigInteger(~self._value)
|
||||
|
||||
def andNot(self, other):
|
||||
return BigInteger(self._value & ~(other._value if isinstance(other, BigInteger) else int(other)))
|
||||
|
||||
def shiftLeft(self, n):
|
||||
return BigInteger(self._value << n)
|
||||
|
||||
def shiftRight(self, n):
|
||||
return BigInteger(self._value >> n)
|
||||
|
||||
def getLowestSetBit(self):
|
||||
if self._value == 0:
|
||||
return -1
|
||||
return (self._value & -self._value).bit_length() - 1
|
||||
|
||||
def bitLength(self):
|
||||
if self._value == 0:
|
||||
return 0
|
||||
return self._value.bit_length()
|
||||
|
||||
def bitCount(self):
|
||||
return bin(self._value & ((1 << self.bitLength()) - 1) if self._value >= 0 else self._value).count("1")
|
||||
|
||||
def isProbablePrime(self, certainty):
|
||||
if abs(self._value) < 2:
|
||||
return False
|
||||
if abs(self._value) == 2 or abs(self._value) == 3:
|
||||
return True
|
||||
if self._value % 2 == 0:
|
||||
return False
|
||||
d = self._value - 1
|
||||
s = 0
|
||||
while d % 2 == 0:
|
||||
d //= 2
|
||||
s += 1
|
||||
for _ in range(min(certainty, 20)):
|
||||
a = _random.randrange(2, min(self._value - 1, 1000000))
|
||||
x = pow(a, d, self._value)
|
||||
if x == 1 or x == self._value - 1:
|
||||
continue
|
||||
for _ in range(s - 1):
|
||||
x = pow(x, 2, self._value)
|
||||
if x == self._value - 1:
|
||||
break
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
||||
def nextProbablePrime(self):
|
||||
v = self._value + 1
|
||||
if v < 3:
|
||||
return BigInteger(2) if v <= 2 else BigInteger(3)
|
||||
while True:
|
||||
if v % 2 == 0:
|
||||
v += 1
|
||||
for i in range(3, int(_py_math.sqrt(v)) + 1, 2):
|
||||
if v % i == 0:
|
||||
break
|
||||
else:
|
||||
return BigInteger(v)
|
||||
v += 2
|
||||
|
||||
def compareTo(self, other):
|
||||
if isinstance(other, BigInteger):
|
||||
return (self._value > other._value) - (self._value < other._value)
|
||||
return -1
|
||||
|
||||
def equals(self, other):
|
||||
if isinstance(other, BigInteger):
|
||||
return self._value == other._value
|
||||
return False
|
||||
|
||||
def toByteArray(self):
|
||||
if self._value == 0:
|
||||
return b"\x00"
|
||||
byte_length = (self._value.bit_length() + 8) // 8
|
||||
return self._value.to_bytes(byte_length, byteorder="big", signed=True)
|
||||
|
||||
def toString(self, radix=10):
|
||||
if radix == 10:
|
||||
return str(self._value)
|
||||
if radix == 16:
|
||||
return hex(self._value)[2:]
|
||||
if radix == 8:
|
||||
return oct(self._value)[2:]
|
||||
if radix == 2:
|
||||
return bin(self._value)[2:]
|
||||
return str(self._value)
|
||||
|
||||
def intValue(self):
|
||||
return self._value & 0xFFFFFFFF
|
||||
|
||||
def longValue(self):
|
||||
return self._value
|
||||
|
||||
def floatValue(self):
|
||||
return float(self._value)
|
||||
|
||||
def doubleValue(self):
|
||||
return float(self._value)
|
||||
|
||||
def min(self, other):
|
||||
return BigInteger(min(self._value, other._value if isinstance(other, BigInteger) else int(other)))
|
||||
|
||||
def max(self, other):
|
||||
return BigInteger(max(self._value, other._value if isinstance(other, BigInteger) else int(other)))
|
||||
|
||||
def modPow(self, exponent, m):
|
||||
if isinstance(exponent, BigInteger):
|
||||
exp_val = exponent._value
|
||||
else:
|
||||
exp_val = int(exponent)
|
||||
mod_val = m._value if isinstance(m, BigInteger) else int(m)
|
||||
return BigInteger(pow(self._value, exp_val, mod_val))
|
||||
|
||||
def modInverse(self, m):
|
||||
mod_val = m._value if isinstance(m, BigInteger) else int(m)
|
||||
return BigInteger(pow(self._value, -1, mod_val))
|
||||
|
||||
def divideAndRemainder(self, other):
|
||||
if isinstance(other, BigInteger):
|
||||
divisor = other._value
|
||||
else:
|
||||
divisor = int(other)
|
||||
q = self._value // divisor
|
||||
r = self._value % divisor
|
||||
return [BigInteger(q), BigInteger(r)]
|
||||
|
||||
def __int__(self):
|
||||
return self._value
|
||||
|
||||
def __str__(self):
|
||||
return str(self._value)
|
||||
|
||||
def __neg__(self):
|
||||
return self.negate()
|
||||
|
||||
def __abs__(self):
|
||||
return self.abs()
|
||||
|
||||
def __add__(self, other):
|
||||
return self.add(other)
|
||||
|
||||
def __sub__(self, other):
|
||||
return self.subtract(other)
|
||||
|
||||
def __mul__(self, other):
|
||||
return self.multiply(other)
|
||||
|
||||
def __truediv__(self, other):
|
||||
return self.divide(other)
|
||||
|
||||
def __floordiv__(self, other):
|
||||
return self.divide(other)
|
||||
|
||||
def __mod__(self, other):
|
||||
return self.mod(other)
|
||||
|
||||
def __pow__(self, other):
|
||||
return self.pow(other)
|
||||
|
||||
def __and__(self, other):
|
||||
return self.and_(other)
|
||||
|
||||
def __or__(self, other):
|
||||
return self.or_(other)
|
||||
|
||||
def __xor__(self, other):
|
||||
return self.xor(other)
|
||||
|
||||
def __invert__(self):
|
||||
return self.not_()
|
||||
|
||||
def __lshift__(self, n):
|
||||
return self.shiftLeft(n)
|
||||
|
||||
def __rshift__(self, n):
|
||||
return self.shiftRight(n)
|
||||
|
||||
|
||||
BigInteger.ZERO = BigInteger(0)
|
||||
BigInteger.ONE = BigInteger(1)
|
||||
BigInteger.TEN = BigInteger(10)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# BigDecimal
|
||||
# ============================================================
|
||||
|
||||
class BigDecimal(Comparable):
|
||||
ZERO = None
|
||||
ONE = None
|
||||
TEN = None
|
||||
|
||||
ROUND_UP = 0
|
||||
ROUND_DOWN = 1
|
||||
ROUND_CEILING = 2
|
||||
ROUND_FLOOR = 3
|
||||
ROUND_HALF_UP = 4
|
||||
ROUND_HALF_DOWN = 5
|
||||
ROUND_HALF_EVEN = 6
|
||||
ROUND_UNNECESSARY = 7
|
||||
|
||||
_round_map = {
|
||||
0: _DEC_ROUND_UP,
|
||||
1: _DEC_ROUND_DOWN,
|
||||
2: _DEC_ROUND_CEILING,
|
||||
3: _DEC_ROUND_FLOOR,
|
||||
4: _DEC_ROUND_HALF_UP,
|
||||
5: _DEC_ROUND_HALF_DOWN,
|
||||
6: _DEC_ROUND_HALF_EVEN,
|
||||
7: _DEC_ROUND_HALF_EVEN,
|
||||
}
|
||||
|
||||
def __init__(self, *args):
|
||||
super().__init__()
|
||||
if len(args) == 1:
|
||||
val = args[0]
|
||||
if isinstance(val, str):
|
||||
self._dec = _Decimal(str(val))
|
||||
elif isinstance(val, float):
|
||||
self._dec = _Decimal(repr(val))
|
||||
elif isinstance(val, int):
|
||||
self._dec = _Decimal(val)
|
||||
elif isinstance(val, BigInteger):
|
||||
self._dec = _Decimal(val._value)
|
||||
elif isinstance(val, BigDecimal):
|
||||
self._dec = _Decimal(val._dec)
|
||||
elif isinstance(val, _Decimal):
|
||||
self._dec = val
|
||||
else:
|
||||
self._dec = _Decimal(str(val))
|
||||
elif len(args) == 2:
|
||||
val, mc = args
|
||||
if isinstance(val, str):
|
||||
self._dec = _Decimal(str(val))
|
||||
elif isinstance(val, float):
|
||||
self._dec = _Decimal(repr(val))
|
||||
else:
|
||||
self._dec = _Decimal(val)
|
||||
if mc and hasattr(mc, 'getPrecision') and mc.getPrecision() > 0:
|
||||
self._dec = +self._dec
|
||||
|
||||
@staticmethod
|
||||
def valueOf(val):
|
||||
if isinstance(val, int):
|
||||
if val == 0:
|
||||
return BigDecimal.ZERO
|
||||
if val == 1:
|
||||
return BigDecimal.ONE
|
||||
if val == 10:
|
||||
return BigDecimal.TEN
|
||||
if isinstance(val, float):
|
||||
return BigDecimal(repr(val))
|
||||
return BigDecimal(val)
|
||||
|
||||
def add(self, other):
|
||||
if isinstance(other, BigDecimal):
|
||||
return BigDecimal(self._dec + other._dec)
|
||||
return BigDecimal(self._dec + _Decimal(str(other)))
|
||||
|
||||
def subtract(self, other):
|
||||
if isinstance(other, BigDecimal):
|
||||
return BigDecimal(self._dec - other._dec)
|
||||
return BigDecimal(self._dec - _Decimal(str(other)))
|
||||
|
||||
def multiply(self, other):
|
||||
if isinstance(other, BigDecimal):
|
||||
return BigDecimal(self._dec * other._dec)
|
||||
return BigDecimal(self._dec * _Decimal(str(other)))
|
||||
|
||||
def divide(self, *args):
|
||||
if len(args) == 1:
|
||||
other = args[0]
|
||||
if isinstance(other, BigDecimal):
|
||||
return BigDecimal(self._dec / other._dec)
|
||||
return BigDecimal(self._dec / _Decimal(str(other)))
|
||||
elif len(args) == 2:
|
||||
other, rounding_mode = args
|
||||
if isinstance(other, BigDecimal):
|
||||
result = self._dec / other._dec
|
||||
else:
|
||||
result = self._dec / _Decimal(str(other))
|
||||
return BigDecimal(result)
|
||||
elif len(args) == 3:
|
||||
other, scale, rounding_mode = args
|
||||
if isinstance(other, BigDecimal):
|
||||
result = self._dec / other._dec
|
||||
else:
|
||||
result = self._dec / _Decimal(str(other))
|
||||
rounded = BigDecimal(result)
|
||||
return rounded.setScale(scale, rounding_mode)
|
||||
|
||||
def divideToIntegralValue(self, other):
|
||||
if isinstance(other, BigDecimal):
|
||||
return BigDecimal(int(self._dec / other._dec))
|
||||
return BigDecimal(int(self._dec / _Decimal(str(other))))
|
||||
|
||||
def remainder(self, other):
|
||||
if isinstance(other, BigDecimal):
|
||||
return BigDecimal(self._dec % other._dec)
|
||||
return BigDecimal(self._dec % _Decimal(str(other)))
|
||||
|
||||
def pow(self, n):
|
||||
return BigDecimal(self._dec ** n)
|
||||
|
||||
def abs(self):
|
||||
return BigDecimal(abs(self._dec))
|
||||
|
||||
def negate(self):
|
||||
return BigDecimal(-self._dec)
|
||||
|
||||
def signum(self):
|
||||
if self._dec > 0:
|
||||
return 1
|
||||
if self._dec < 0:
|
||||
return -1
|
||||
return 0
|
||||
|
||||
def scale(self):
|
||||
return abs(self._dec.as_tuple().exponent)
|
||||
|
||||
def precision(self):
|
||||
return len(self._dec.as_tuple().digits)
|
||||
|
||||
def round(self, mc):
|
||||
if mc.getPrecision() > 0:
|
||||
with _local_context() as ctx:
|
||||
ctx.prec = mc.getPrecision()
|
||||
return BigDecimal(+self._dec)
|
||||
return BigDecimal(self._dec)
|
||||
|
||||
def setScale(self, new_scale, rounding_mode=None):
|
||||
if rounding_mode is None:
|
||||
qe = _Decimal(10) ** (-new_scale)
|
||||
return BigDecimal(self._dec.quantize(qe))
|
||||
py_mode = self._round_map.get(rounding_mode, _DEC_ROUND_HALF_UP)
|
||||
qe = _Decimal(10) ** (-new_scale)
|
||||
return BigDecimal(self._dec.quantize(qe, rounding=py_mode))
|
||||
|
||||
def ulp(self):
|
||||
exponent = self._dec.as_tuple().exponent
|
||||
return BigDecimal(_Decimal(10) ** exponent)
|
||||
|
||||
def unscaledValue(self):
|
||||
t = self._dec.as_tuple()
|
||||
digits = t.digits
|
||||
val = int("".join(str(d) for d in digits))
|
||||
return BigInteger(-val if t.sign else val)
|
||||
|
||||
def byteValueExact(self):
|
||||
val = self.intValueExact()
|
||||
if val < -128 or val > 127:
|
||||
raise ArithmeticError("Overflow")
|
||||
return val
|
||||
|
||||
def shortValueExact(self):
|
||||
val = self.intValueExact()
|
||||
if val < -32768 or val > 32767:
|
||||
raise ArithmeticError("Overflow")
|
||||
return val
|
||||
|
||||
def intValueExact(self):
|
||||
if self._dec != int(self._dec):
|
||||
raise ArithmeticError("Rounding necessary")
|
||||
return int(self._dec)
|
||||
|
||||
def longValueExact(self):
|
||||
if self._dec != int(self._dec):
|
||||
raise ArithmeticError("Rounding necessary")
|
||||
return int(self._dec)
|
||||
|
||||
def floatValue(self):
|
||||
return float(self._dec)
|
||||
|
||||
def doubleValue(self):
|
||||
return float(self._dec)
|
||||
|
||||
def intValue(self):
|
||||
return int(self._dec)
|
||||
|
||||
def longValue(self):
|
||||
return int(self._dec)
|
||||
|
||||
def toString(self):
|
||||
return str(self._dec)
|
||||
|
||||
def toEngineeringString(self):
|
||||
return format(self._dec, "e")
|
||||
|
||||
def toPlainString(self):
|
||||
return format(self._dec, "f")
|
||||
|
||||
def compareTo(self, other):
|
||||
if isinstance(other, BigDecimal):
|
||||
return (self._dec > other._dec) - (self._dec < other._dec)
|
||||
return -1
|
||||
|
||||
def equals(self, other):
|
||||
if isinstance(other, BigDecimal):
|
||||
return self._dec == other._dec
|
||||
return False
|
||||
|
||||
def hashCode(self):
|
||||
return hash(self._dec) & 0x7FFFFFFF
|
||||
|
||||
def min(self, other):
|
||||
return BigDecimal(min(self._dec, other._dec if isinstance(other, BigDecimal) else _Decimal(str(other))))
|
||||
|
||||
def max(self, other):
|
||||
return BigDecimal(max(self._dec, other._dec if isinstance(other, BigDecimal) else _Decimal(str(other))))
|
||||
|
||||
def __str__(self):
|
||||
return str(self._dec)
|
||||
|
||||
def __int__(self):
|
||||
return int(self._dec)
|
||||
|
||||
def __float__(self):
|
||||
return float(self._dec)
|
||||
|
||||
def __neg__(self):
|
||||
return self.negate()
|
||||
|
||||
def __abs__(self):
|
||||
return self.abs()
|
||||
|
||||
def __add__(self, other):
|
||||
return self.add(other)
|
||||
|
||||
def __sub__(self, other):
|
||||
return self.subtract(other)
|
||||
|
||||
def __mul__(self, other):
|
||||
return self.multiply(other)
|
||||
|
||||
def __truediv__(self, other):
|
||||
return self.divide(other)
|
||||
|
||||
def __mod__(self, other):
|
||||
return self.remainder(other)
|
||||
|
||||
def __pow__(self, other):
|
||||
return self.pow(other)
|
||||
|
||||
|
||||
BigDecimal.ZERO = BigDecimal(0)
|
||||
BigDecimal.ONE = BigDecimal(1)
|
||||
BigDecimal.TEN = BigDecimal(10)
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,622 @@
|
||||
"""
|
||||
Java NIO standard library APIs implemented in Python.
|
||||
java.nio package - Buffer, ByteBuffer, CharBuffer, etc.
|
||||
"""
|
||||
|
||||
from .._core import Stub
|
||||
from .lang import RuntimeException
|
||||
from .io import IOException
|
||||
import struct as _struct
|
||||
import sys as _sys
|
||||
|
||||
IllegalStateException = type("IllegalStateException", (RuntimeException,), {})
|
||||
IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
|
||||
|
||||
__all__ = [
|
||||
"Buffer", "ByteBuffer", "CharBuffer", "ShortBuffer",
|
||||
"IntBuffer", "LongBuffer", "FloatBuffer", "DoubleBuffer",
|
||||
"MappedByteBuffer", "ByteOrder",
|
||||
"BufferOverflowException", "BufferUnderflowException",
|
||||
"ReadOnlyBufferException", "InvalidMarkException",
|
||||
]
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Exception classes
|
||||
# ============================================================
|
||||
|
||||
class BufferOverflowException(RuntimeException):
|
||||
pass
|
||||
|
||||
class BufferUnderflowException(RuntimeException):
|
||||
pass
|
||||
|
||||
class ReadOnlyBufferException(RuntimeException):
|
||||
pass
|
||||
|
||||
class InvalidMarkException(IllegalStateException):
|
||||
pass
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ByteOrder
|
||||
# ============================================================
|
||||
|
||||
class ByteOrder(Stub):
|
||||
BIG_ENDIAN = None
|
||||
LITTLE_ENDIAN = None
|
||||
|
||||
def __init__(self, name):
|
||||
super().__init__()
|
||||
self._name = name
|
||||
|
||||
@staticmethod
|
||||
def nativeOrder():
|
||||
if _sys.byteorder == "little":
|
||||
return ByteOrder.LITTLE_ENDIAN
|
||||
return ByteOrder.BIG_ENDIAN
|
||||
|
||||
def toString(self):
|
||||
return self._name
|
||||
|
||||
|
||||
ByteOrder.BIG_ENDIAN = ByteOrder("BIG_ENDIAN")
|
||||
ByteOrder.LITTLE_ENDIAN = ByteOrder("LITTLE_ENDIAN")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Buffer
|
||||
# ============================================================
|
||||
|
||||
class Buffer(Stub):
|
||||
def __init__(self, capacity, backing=None):
|
||||
super().__init__()
|
||||
self._capacity = capacity
|
||||
self._position = 0
|
||||
self._limit = capacity
|
||||
self._mark = -1
|
||||
self._backing = backing if backing is not None else bytearray(capacity)
|
||||
self._read_only = False
|
||||
|
||||
def capacity(self):
|
||||
return self._capacity
|
||||
|
||||
def position(self):
|
||||
return self._position
|
||||
|
||||
def position(self, new_position):
|
||||
if new_position < 0 or new_position > self._limit:
|
||||
raise IllegalArgumentException("Invalid position")
|
||||
self._position = new_position
|
||||
return self
|
||||
|
||||
def limit(self):
|
||||
return self._limit
|
||||
|
||||
def limit(self, new_limit):
|
||||
if new_limit < 0 or new_limit > self._capacity:
|
||||
raise IllegalArgumentException("Invalid limit")
|
||||
self._limit = new_limit
|
||||
if self._position > self._limit:
|
||||
self._position = self._limit
|
||||
if self._mark > self._limit:
|
||||
self._mark = -1
|
||||
return self
|
||||
|
||||
def mark(self):
|
||||
self._mark = self._position
|
||||
return self
|
||||
|
||||
def reset(self):
|
||||
if self._mark < 0:
|
||||
raise InvalidMarkException()
|
||||
self._position = self._mark
|
||||
return self
|
||||
|
||||
def clear(self):
|
||||
self._position = 0
|
||||
self._limit = self._capacity
|
||||
self._mark = -1
|
||||
return self
|
||||
|
||||
def flip(self):
|
||||
self._limit = self._position
|
||||
self._position = 0
|
||||
self._mark = -1
|
||||
return self
|
||||
|
||||
def rewind(self):
|
||||
self._position = 0
|
||||
self._mark = -1
|
||||
return self
|
||||
|
||||
def remaining(self):
|
||||
return self._limit - self._position
|
||||
|
||||
def hasRemaining(self):
|
||||
return self._position < self._limit
|
||||
|
||||
def isReadOnly(self):
|
||||
return self._read_only
|
||||
|
||||
def isDirect(self):
|
||||
return False
|
||||
|
||||
def array(self):
|
||||
if self._read_only:
|
||||
raise ReadOnlyBufferException()
|
||||
return self._backing
|
||||
|
||||
def arrayOffset(self):
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ByteBuffer
|
||||
# ============================================================
|
||||
|
||||
class ByteBuffer(Buffer):
|
||||
def __init__(self, capacity, backing=None, order=None):
|
||||
super().__init__(capacity, backing)
|
||||
self._order = order or ByteOrder.BIG_ENDIAN
|
||||
|
||||
@staticmethod
|
||||
def allocate(capacity):
|
||||
return ByteBuffer(capacity, bytearray(capacity))
|
||||
|
||||
@staticmethod
|
||||
def allocateDirect(capacity):
|
||||
return ByteBuffer(capacity, bytearray(capacity))
|
||||
|
||||
@staticmethod
|
||||
def wrap(array, offset=0, length=None):
|
||||
if length is None:
|
||||
length = len(array) - offset
|
||||
buf = ByteBuffer(length, bytearray(array))
|
||||
buf._position = offset
|
||||
buf._limit = offset + length
|
||||
return buf
|
||||
|
||||
def put(self, b, index=None):
|
||||
if self._read_only:
|
||||
raise ReadOnlyBufferException()
|
||||
if index is None:
|
||||
if isinstance(b, int):
|
||||
if self._position >= self._limit:
|
||||
raise BufferOverflowException()
|
||||
self._backing[self._position] = b & 0xFF
|
||||
self._position += 1
|
||||
elif isinstance(b, ByteBuffer):
|
||||
n = b.remaining()
|
||||
if self.remaining() < n:
|
||||
raise BufferOverflowException()
|
||||
self._backing[self._position:self._position+n] = b._backing[b._position:b._limit]
|
||||
self._position += n
|
||||
b._position = b._limit
|
||||
elif isinstance(b, (bytes, bytearray)):
|
||||
if self.remaining() < len(b):
|
||||
raise BufferOverflowException()
|
||||
self._backing[self._position:self._position+len(b)] = b
|
||||
self._position += len(b)
|
||||
else:
|
||||
self._backing[index] = b & 0xFF
|
||||
return self
|
||||
|
||||
def get(self, index=None):
|
||||
if index is None:
|
||||
if self._position >= self._limit:
|
||||
raise BufferUnderflowException()
|
||||
val = self._backing[self._position]
|
||||
self._position += 1
|
||||
return val & 0xFF
|
||||
return self._backing[index] & 0xFF
|
||||
|
||||
def putInt(self, value, index=None):
|
||||
data = _struct.pack(">i" if self._order == ByteOrder.BIG_ENDIAN else "<i", value)
|
||||
if index is not None:
|
||||
self._backing[index:index+4] = data
|
||||
else:
|
||||
if self.remaining() < 4:
|
||||
raise BufferOverflowException()
|
||||
self._backing[self._position:self._position+4] = data
|
||||
self._position += 4
|
||||
return self
|
||||
|
||||
def getInt(self, index=None):
|
||||
if index is not None:
|
||||
data = self._backing[index:index+4]
|
||||
else:
|
||||
if self.remaining() < 4:
|
||||
raise BufferUnderflowException()
|
||||
data = self._backing[self._position:self._position+4]
|
||||
self._position += 4
|
||||
return _struct.unpack(">i" if self._order == ByteOrder.BIG_ENDIAN else "<i", bytes(data))[0]
|
||||
|
||||
def putLong(self, value, index=None):
|
||||
data = _struct.pack(">q" if self._order == ByteOrder.BIG_ENDIAN else "<q", value)
|
||||
if index is not None:
|
||||
self._backing[index:index+8] = data
|
||||
else:
|
||||
if self.remaining() < 8:
|
||||
raise BufferOverflowException()
|
||||
self._backing[self._position:self._position+8] = data
|
||||
self._position += 8
|
||||
return self
|
||||
|
||||
def getLong(self, index=None):
|
||||
if index is not None:
|
||||
data = self._backing[index:index+8]
|
||||
else:
|
||||
if self.remaining() < 8:
|
||||
raise BufferUnderflowException()
|
||||
data = self._backing[self._position:self._position+8]
|
||||
self._position += 8
|
||||
return _struct.unpack(">q" if self._order == ByteOrder.BIG_ENDIAN else "<q", bytes(data))[0]
|
||||
|
||||
def putFloat(self, value, index=None):
|
||||
data = _struct.pack(">f" if self._order == ByteOrder.BIG_ENDIAN else "<f", value)
|
||||
if index is not None:
|
||||
self._backing[index:index+4] = data
|
||||
else:
|
||||
if self.remaining() < 4:
|
||||
raise BufferOverflowException()
|
||||
self._backing[self._position:self._position+4] = data
|
||||
self._position += 4
|
||||
return self
|
||||
|
||||
def getFloat(self, index=None):
|
||||
if index is not None:
|
||||
data = self._backing[index:index+4]
|
||||
else:
|
||||
if self.remaining() < 4:
|
||||
raise BufferUnderflowException()
|
||||
data = self._backing[self._position:self._position+4]
|
||||
self._position += 4
|
||||
return _struct.unpack(">f" if self._order == ByteOrder.BIG_ENDIAN else "<f", bytes(data))[0]
|
||||
|
||||
def putDouble(self, value, index=None):
|
||||
data = _struct.pack(">d" if self._order == ByteOrder.BIG_ENDIAN else "<d", value)
|
||||
if index is not None:
|
||||
self._backing[index:index+8] = data
|
||||
else:
|
||||
if self.remaining() < 8:
|
||||
raise BufferOverflowException()
|
||||
self._backing[self._position:self._position+8] = data
|
||||
self._position += 8
|
||||
return self
|
||||
|
||||
def getDouble(self, index=None):
|
||||
if index is not None:
|
||||
data = self._backing[index:index+8]
|
||||
else:
|
||||
if self.remaining() < 8:
|
||||
raise BufferUnderflowException()
|
||||
data = self._backing[self._position:self._position+8]
|
||||
self._position += 8
|
||||
return _struct.unpack(">d" if self._order == ByteOrder.BIG_ENDIAN else "<d", bytes(data))[0]
|
||||
|
||||
def putShort(self, value, index=None):
|
||||
data = _struct.pack(">h" if self._order == ByteOrder.BIG_ENDIAN else "<h", value)
|
||||
if index is not None:
|
||||
self._backing[index:index+2] = data
|
||||
else:
|
||||
if self.remaining() < 2:
|
||||
raise BufferOverflowException()
|
||||
self._backing[self._position:self._position+2] = data
|
||||
self._position += 2
|
||||
return self
|
||||
|
||||
def getShort(self, index=None):
|
||||
if index is not None:
|
||||
data = self._backing[index:index+2]
|
||||
else:
|
||||
if self.remaining() < 2:
|
||||
raise BufferUnderflowException()
|
||||
data = self._backing[self._position:self._position+2]
|
||||
self._position += 2
|
||||
return _struct.unpack(">h" if self._order == ByteOrder.BIG_ENDIAN else "<h", bytes(data))[0]
|
||||
|
||||
def putChar(self, value, index=None):
|
||||
return self.putShort(ord(value), index)
|
||||
|
||||
def getChar(self, index=None):
|
||||
return chr(self.getShort(index))
|
||||
|
||||
def asIntBuffer(self):
|
||||
return IntBuffer(self.remaining() // 4, self._backing, self._position, self._order)
|
||||
|
||||
def asLongBuffer(self):
|
||||
return LongBuffer(self.remaining() // 8, self._backing, self._position, self._order)
|
||||
|
||||
def asFloatBuffer(self):
|
||||
return FloatBuffer(self.remaining() // 4, self._backing, self._position, self._order)
|
||||
|
||||
def asDoubleBuffer(self):
|
||||
return DoubleBuffer(self.remaining() // 8, self._backing, self._position, self._order)
|
||||
|
||||
def asShortBuffer(self):
|
||||
return ShortBuffer(self.remaining() // 2, self._backing, self._position, self._order)
|
||||
|
||||
def asCharBuffer(self):
|
||||
return CharBuffer(self.remaining() // 2, self._backing, self._position, self._order)
|
||||
|
||||
def slice(self):
|
||||
n = self.remaining()
|
||||
buf = ByteBuffer(n, self._backing[self._position:self._limit])
|
||||
return buf
|
||||
|
||||
def duplicate(self):
|
||||
buf = ByteBuffer(self._capacity, bytearray(self._backing))
|
||||
buf._position = self._position
|
||||
buf._limit = self._limit
|
||||
buf._order = self._order
|
||||
return buf
|
||||
|
||||
def asReadOnlyBuffer(self):
|
||||
buf = self.duplicate()
|
||||
buf._read_only = True
|
||||
return buf
|
||||
|
||||
def order(self, order=None):
|
||||
if order is not None:
|
||||
self._order = order
|
||||
return self
|
||||
return self._order
|
||||
|
||||
def compact(self):
|
||||
if self._read_only:
|
||||
raise ReadOnlyBufferException()
|
||||
remaining = self.remaining()
|
||||
self._backing[:remaining] = self._backing[self._position:self._limit]
|
||||
self._position = remaining
|
||||
self._limit = self._capacity
|
||||
self._mark = -1
|
||||
return self
|
||||
|
||||
def toString(self):
|
||||
return f"ByteBuffer[pos={self._position} lim={self._limit} cap={self._capacity}]"
|
||||
|
||||
def hashCode(self):
|
||||
return hash(bytes(self._backing)) & 0x7FFFFFFF
|
||||
|
||||
def equals(self, other):
|
||||
if isinstance(other, ByteBuffer):
|
||||
return bytes(self._backing[self._position:self._limit]) == bytes(other._backing[other._position:other._limit])
|
||||
return False
|
||||
|
||||
def compareTo(self, other):
|
||||
if isinstance(other, ByteBuffer):
|
||||
a = bytes(self._backing[self._position:self._limit])
|
||||
b = bytes(other._backing[other._position:other._limit])
|
||||
return (a > b) - (a < b)
|
||||
return -1
|
||||
|
||||
|
||||
# ============================================================
|
||||
# IntBuffer
|
||||
# ============================================================
|
||||
|
||||
class IntBuffer(Buffer):
|
||||
def __init__(self, capacity, backing, offset=0, order=None):
|
||||
super().__init__(capacity, backing)
|
||||
self._int_order = order or ByteOrder.BIG_ENDIAN
|
||||
self._int_offset = offset
|
||||
|
||||
def get(self, index=None):
|
||||
if index is not None:
|
||||
idx = self._int_offset + index * 4
|
||||
return _struct.unpack(">i" if self._int_order == ByteOrder.BIG_ENDIAN else "<i",
|
||||
bytes(self._backing[idx:idx+4]))[0]
|
||||
if self.remaining() < 4:
|
||||
raise BufferUnderflowException()
|
||||
val = _struct.unpack(">i" if self._int_order == ByteOrder.BIG_ENDIAN else "<i",
|
||||
bytes(self._backing[self._position:self._position+4]))[0]
|
||||
self._position += 4
|
||||
return val
|
||||
|
||||
def put(self, value, index=None):
|
||||
data = _struct.pack(">i" if self._int_order == ByteOrder.BIG_ENDIAN else "<i", value)
|
||||
if index is not None:
|
||||
idx = self._int_offset + index * 4
|
||||
self._backing[idx:idx+4] = data
|
||||
else:
|
||||
if self.remaining() < 4:
|
||||
raise BufferOverflowException()
|
||||
self._backing[self._position:self._position+4] = data
|
||||
self._position += 4
|
||||
return self
|
||||
|
||||
|
||||
# ============================================================
|
||||
# LongBuffer
|
||||
# ============================================================
|
||||
|
||||
class LongBuffer(Buffer):
|
||||
def __init__(self, capacity, backing, offset=0, order=None):
|
||||
super().__init__(capacity, backing)
|
||||
self._long_order = order or ByteOrder.BIG_ENDIAN
|
||||
self._long_offset = offset
|
||||
|
||||
def get(self, index=None):
|
||||
if index is not None:
|
||||
idx = self._long_offset + index * 8
|
||||
return _struct.unpack(">q" if self._long_order == ByteOrder.BIG_ENDIAN else "<q",
|
||||
bytes(self._backing[idx:idx+8]))[0]
|
||||
if self.remaining() < 8:
|
||||
raise BufferUnderflowException()
|
||||
val = _struct.unpack(">q" if self._long_order == ByteOrder.BIG_ENDIAN else "<q",
|
||||
bytes(self._backing[self._position:self._position+8]))[0]
|
||||
self._position += 8
|
||||
return val
|
||||
|
||||
def put(self, value, index=None):
|
||||
data = _struct.pack(">q" if self._long_order == ByteOrder.BIG_ENDIAN else "<q", value)
|
||||
if index is not None:
|
||||
idx = self._long_offset + index * 8
|
||||
self._backing[idx:idx+8] = data
|
||||
else:
|
||||
if self.remaining() < 8:
|
||||
raise BufferOverflowException()
|
||||
self._backing[self._position:self._position+8] = data
|
||||
self._position += 8
|
||||
return self
|
||||
|
||||
|
||||
# ============================================================
|
||||
# FloatBuffer
|
||||
# ============================================================
|
||||
|
||||
class FloatBuffer(Buffer):
|
||||
def __init__(self, capacity, backing, offset=0, order=None):
|
||||
super().__init__(capacity, backing)
|
||||
self._float_order = order or ByteOrder.BIG_ENDIAN
|
||||
self._float_offset = offset
|
||||
|
||||
def get(self, index=None):
|
||||
if index is not None:
|
||||
idx = self._float_offset + index * 4
|
||||
return _struct.unpack(">f" if self._float_order == ByteOrder.BIG_ENDIAN else "<f",
|
||||
bytes(self._backing[idx:idx+4]))[0]
|
||||
if self.remaining() < 4:
|
||||
raise BufferUnderflowException()
|
||||
val = _struct.unpack(">f" if self._float_order == ByteOrder.BIG_ENDIAN else "<f",
|
||||
bytes(self._backing[self._position:self._position+4]))[0]
|
||||
self._position += 4
|
||||
return val
|
||||
|
||||
def put(self, value, index=None):
|
||||
data = _struct.pack(">f" if self._float_order == ByteOrder.BIG_ENDIAN else "<f", value)
|
||||
if index is not None:
|
||||
idx = self._float_offset + index * 4
|
||||
self._backing[idx:idx+4] = data
|
||||
else:
|
||||
if self.remaining() < 4:
|
||||
raise BufferOverflowException()
|
||||
self._backing[self._position:self._position+4] = data
|
||||
self._position += 4
|
||||
return self
|
||||
|
||||
|
||||
# ============================================================
|
||||
# DoubleBuffer
|
||||
# ============================================================
|
||||
|
||||
class DoubleBuffer(Buffer):
|
||||
def __init__(self, capacity, backing, offset=0, order=None):
|
||||
super().__init__(capacity, backing)
|
||||
self._double_order = order or ByteOrder.BIG_ENDIAN
|
||||
self._double_offset = offset
|
||||
|
||||
def get(self, index=None):
|
||||
if index is not None:
|
||||
idx = self._double_offset + index * 8
|
||||
return _struct.unpack(">d" if self._double_order == ByteOrder.BIG_ENDIAN else "<d",
|
||||
bytes(self._backing[idx:idx+8]))[0]
|
||||
if self.remaining() < 8:
|
||||
raise BufferUnderflowException()
|
||||
val = _struct.unpack(">d" if self._double_order == ByteOrder.BIG_ENDIAN else "<d",
|
||||
bytes(self._backing[self._position:self._position+8]))[0]
|
||||
self._position += 8
|
||||
return val
|
||||
|
||||
def put(self, value, index=None):
|
||||
data = _struct.pack(">d" if self._double_order == ByteOrder.BIG_ENDIAN else "<d", value)
|
||||
if index is not None:
|
||||
idx = self._double_offset + index * 8
|
||||
self._backing[idx:idx+8] = data
|
||||
else:
|
||||
if self.remaining() < 8:
|
||||
raise BufferOverflowException()
|
||||
self._backing[self._position:self._position+8] = data
|
||||
self._position += 8
|
||||
return self
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ShortBuffer
|
||||
# ============================================================
|
||||
|
||||
class ShortBuffer(Buffer):
|
||||
def __init__(self, capacity, backing, offset=0, order=None):
|
||||
super().__init__(capacity, backing)
|
||||
self._short_order = order or ByteOrder.BIG_ENDIAN
|
||||
self._short_offset = offset
|
||||
|
||||
def get(self, index=None):
|
||||
if index is not None:
|
||||
idx = self._short_offset + index * 2
|
||||
return _struct.unpack(">h" if self._short_order == ByteOrder.BIG_ENDIAN else "<h",
|
||||
bytes(self._backing[idx:idx+2]))[0]
|
||||
if self.remaining() < 2:
|
||||
raise BufferUnderflowException()
|
||||
val = _struct.unpack(">h" if self._short_order == ByteOrder.BIG_ENDIAN else "<h",
|
||||
bytes(self._backing[self._position:self._position+2]))[0]
|
||||
self._position += 2
|
||||
return val
|
||||
|
||||
def put(self, value, index=None):
|
||||
data = _struct.pack(">h" if self._short_order == ByteOrder.BIG_ENDIAN else "<h", value)
|
||||
if index is not None:
|
||||
idx = self._short_offset + index * 2
|
||||
self._backing[idx:idx+2] = data
|
||||
else:
|
||||
if self.remaining() < 2:
|
||||
raise BufferOverflowException()
|
||||
self._backing[self._position:self._position+2] = data
|
||||
self._position += 2
|
||||
return self
|
||||
|
||||
|
||||
# ============================================================
|
||||
# CharBuffer
|
||||
# ============================================================
|
||||
|
||||
class CharBuffer(Buffer):
|
||||
def __init__(self, capacity, backing, offset=0, order=None):
|
||||
super().__init__(capacity, backing)
|
||||
self._char_order = order or ByteOrder.BIG_ENDIAN
|
||||
self._char_offset = offset
|
||||
|
||||
def get(self, index=None):
|
||||
if index is not None:
|
||||
idx = self._char_offset + index * 2
|
||||
val = _struct.unpack(">h" if self._char_order == ByteOrder.BIG_ENDIAN else "<h",
|
||||
bytes(self._backing[idx:idx+2]))[0]
|
||||
return chr(val)
|
||||
if self.remaining() < 2:
|
||||
raise BufferUnderflowException()
|
||||
val = _struct.unpack(">h" if self._char_order == ByteOrder.BIG_ENDIAN else "<h",
|
||||
bytes(self._backing[self._position:self._position+2]))[0]
|
||||
self._position += 2
|
||||
return chr(val)
|
||||
|
||||
def put(self, value, index=None):
|
||||
char_val = ord(value) if isinstance(value, str) else value
|
||||
data = _struct.pack(">h" if self._char_order == ByteOrder.BIG_ENDIAN else "<h", char_val)
|
||||
if index is not None:
|
||||
idx = self._char_offset + index * 2
|
||||
self._backing[idx:idx+2] = data
|
||||
else:
|
||||
if self.remaining() < 2:
|
||||
raise BufferOverflowException()
|
||||
self._backing[self._position:self._position+2] = data
|
||||
self._position += 2
|
||||
return self
|
||||
|
||||
|
||||
# ============================================================
|
||||
# MappedByteBuffer
|
||||
# ============================================================
|
||||
|
||||
class MappedByteBuffer(ByteBuffer):
|
||||
def __init__(self, capacity, backing=None):
|
||||
super().__init__(capacity, backing)
|
||||
|
||||
def force(self):
|
||||
return self
|
||||
|
||||
def isLoaded(self):
|
||||
return True
|
||||
|
||||
def load(self):
|
||||
return self
|
||||
@@ -0,0 +1,703 @@
|
||||
"""
|
||||
Java NIO File standard library APIs implemented in Python.
|
||||
java.nio.file package - Path, Files, FileSystem, FileVisitor, etc.
|
||||
"""
|
||||
|
||||
from .._core import Stub
|
||||
from .io import IOException
|
||||
from .lang import RuntimeException, Comparable
|
||||
import os as _os
|
||||
import shutil as _shutil
|
||||
import stat as _stat
|
||||
from pathlib import Path as _PathLibPath
|
||||
import tempfile as _tempfile
|
||||
|
||||
IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
|
||||
|
||||
__all__ = [
|
||||
"Path", "Paths", "Files", "FileSystem", "FileSystems",
|
||||
"FileStore", "FileVisitResult", "FileVisitor", "SimpleFileVisitor",
|
||||
"DirectoryStream", "DirectoryStreamFilter",
|
||||
"PathMatcher", "WatchService", "WatchKey", "WatchEvent", "Watchable",
|
||||
"CopyOption", "StandardCopyOption", "LinkOption", "OpenOption",
|
||||
"StandardOpenOption",
|
||||
"FileAlreadyExistsException", "DirectoryNotEmptyException",
|
||||
"NoSuchFileException", "FileSystemLoopException",
|
||||
"FileSystemNotFoundException", "ProviderMismatchException",
|
||||
"ProviderNotFoundException", "NotDirectoryException", "NotLinkException",
|
||||
"AtomicMoveNotSupportedException", "AccessDeniedException",
|
||||
"AccessMode",
|
||||
]
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Exception classes
|
||||
# ============================================================
|
||||
|
||||
class FileAlreadyExistsException(IOException):
|
||||
pass
|
||||
|
||||
class DirectoryNotEmptyException(IOException):
|
||||
pass
|
||||
|
||||
class NoSuchFileException(IOException):
|
||||
def __init__(self, file=None, other=None, reason=None):
|
||||
msg = str(file) if file else ""
|
||||
super().__init__(msg)
|
||||
|
||||
class FileSystemLoopException(IOException):
|
||||
pass
|
||||
|
||||
class FileSystemNotFoundException(IOException):
|
||||
pass
|
||||
|
||||
class ProviderMismatchException(IllegalArgumentException):
|
||||
pass
|
||||
|
||||
class ProviderNotFoundException(IllegalArgumentException):
|
||||
pass
|
||||
|
||||
class NotDirectoryException(IOException):
|
||||
pass
|
||||
|
||||
class NotLinkException(IOException):
|
||||
pass
|
||||
|
||||
class AtomicMoveNotSupportedException(IOException):
|
||||
pass
|
||||
|
||||
class AccessDeniedException(IOException):
|
||||
pass
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Enums / Constants
|
||||
# ============================================================
|
||||
|
||||
class FileVisitResult:
|
||||
CONTINUE = 0
|
||||
TERMINATE = 1
|
||||
SKIP_SUBTREE = 2
|
||||
SKIP_SIBLINGS = 3
|
||||
|
||||
class StandardCopyOption:
|
||||
REPLACE_EXISTING = 0
|
||||
COPY_ATTRIBUTES = 1
|
||||
ATOMIC_MOVE = 2
|
||||
|
||||
class StandardOpenOption:
|
||||
READ = 0
|
||||
WRITE = 1
|
||||
APPEND = 2
|
||||
TRUNCATE_EXISTING = 3
|
||||
CREATE = 4
|
||||
CREATE_NEW = 5
|
||||
DELETE_ON_CLOSE = 6
|
||||
SPARSE = 7
|
||||
SYNC = 8
|
||||
DSYNC = 9
|
||||
|
||||
class LinkOption:
|
||||
NOFOLLOW_LINKS = 0
|
||||
|
||||
class CopyOption(Stub):
|
||||
pass
|
||||
|
||||
class OpenOption(Stub):
|
||||
pass
|
||||
|
||||
class AccessMode:
|
||||
READ = 0
|
||||
WRITE = 1
|
||||
EXECUTE = 2
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Path
|
||||
# ============================================================
|
||||
|
||||
class Path(Comparable):
|
||||
def __init__(self, path_str, *more):
|
||||
super().__init__()
|
||||
if more:
|
||||
path_str = _os.path.join(path_str, *more)
|
||||
self._path = str(path_str)
|
||||
self._pypath = _PathLibPath(self._path)
|
||||
|
||||
def getFileName(self):
|
||||
return Path(self._pypath.name)
|
||||
|
||||
def getParent(self):
|
||||
parent = self._pypath.parent
|
||||
if parent == self._pypath:
|
||||
return None
|
||||
return Path(str(parent))
|
||||
|
||||
def getRoot(self):
|
||||
root = self._pypath.anchor
|
||||
return Path(root) if root else None
|
||||
|
||||
def toAbsolutePath(self):
|
||||
return Path(str(self._pypath.absolute()))
|
||||
|
||||
def toRealPath(self):
|
||||
return Path(str(self._pypath.resolve()))
|
||||
|
||||
def getName(self, index):
|
||||
parts = self._pypath.parts
|
||||
if self.getRoot():
|
||||
parts = parts[1:]
|
||||
if index < 0 or index >= len(parts):
|
||||
raise IllegalArgumentException("Invalid index")
|
||||
return Path(parts[index])
|
||||
|
||||
def getNameCount(self):
|
||||
parts = self._pypath.parts
|
||||
if self.getRoot():
|
||||
parts = parts[1:]
|
||||
return len(parts)
|
||||
|
||||
def subpath(self, beginIndex, endIndex):
|
||||
parts = self._pypath.parts
|
||||
if self.getRoot():
|
||||
parts = parts[1:]
|
||||
return Path(_os.path.join(*parts[beginIndex:endIndex]))
|
||||
|
||||
def startsWith(self, other):
|
||||
if isinstance(other, Path):
|
||||
return str(self._pypath).startswith(str(other._pypath))
|
||||
return str(self._pypath).startswith(str(other))
|
||||
|
||||
def endsWith(self, other):
|
||||
if isinstance(other, Path):
|
||||
return str(self._pypath).endswith(str(other._pypath))
|
||||
return str(self._pypath).endswith(str(other))
|
||||
|
||||
def normalize(self):
|
||||
return Path(_os.path.normpath(self._path))
|
||||
|
||||
def resolve(self, other):
|
||||
if isinstance(other, Path):
|
||||
other_path = str(other)
|
||||
else:
|
||||
other_path = str(other)
|
||||
if _os.path.isabs(other_path):
|
||||
return Path(other_path)
|
||||
return Path(_os.path.join(self._path, other_path))
|
||||
|
||||
def resolveSibling(self, other):
|
||||
parent = self.getParent()
|
||||
if parent:
|
||||
return parent.resolve(other)
|
||||
return Path(other)
|
||||
|
||||
def relativize(self, other):
|
||||
if isinstance(other, Path):
|
||||
other_str = str(other._pypath)
|
||||
else:
|
||||
other_str = str(other)
|
||||
try:
|
||||
rel = _os.path.relpath(other_str, self._path)
|
||||
return Path(rel)
|
||||
except ValueError:
|
||||
return other
|
||||
|
||||
def compareTo(self, other):
|
||||
if isinstance(other, Path):
|
||||
return (self._path > other._path) - (self._path < other._path)
|
||||
return -1
|
||||
|
||||
def toString(self):
|
||||
return self._path
|
||||
|
||||
def toFile(self):
|
||||
from ..io import File
|
||||
return File(self._path)
|
||||
|
||||
def isAbsolute(self):
|
||||
return _os.path.isabs(self._path)
|
||||
|
||||
def getFileSystem(self):
|
||||
return FileSystems.getDefault()
|
||||
|
||||
def iterator(self):
|
||||
parts = self._pypath.parts
|
||||
if self.getRoot():
|
||||
parts = parts[1:]
|
||||
return iter([Path(p) for p in parts])
|
||||
|
||||
def register(self, watcher, events, *modifiers):
|
||||
raise AndroidOnlyError("WatchService nio")
|
||||
|
||||
def __str__(self):
|
||||
return self._path
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, Path):
|
||||
return self._path == other._path
|
||||
return NotImplemented
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self._path)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Paths
|
||||
# ============================================================
|
||||
|
||||
class Paths(Stub):
|
||||
@staticmethod
|
||||
def get(first, *more):
|
||||
parts = [str(first)]
|
||||
parts.extend(str(m) for m in more)
|
||||
return Path(_os.path.join(*parts))
|
||||
|
||||
|
||||
# ============================================================
|
||||
# FileSystem
|
||||
# ============================================================
|
||||
|
||||
class FileSystem(Stub):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._separator = _os.sep
|
||||
self._open = True
|
||||
|
||||
def getPath(self, first, *more):
|
||||
return Paths.get(first, *more)
|
||||
|
||||
def getSeparator(self):
|
||||
return self._separator
|
||||
|
||||
def getRootDirectories(self):
|
||||
if _os.name == "nt":
|
||||
import string
|
||||
return [Path(d + ":\\") for d in string.ascii_uppercase if _os.path.exists(d + ":\\")]
|
||||
return [Path("/")]
|
||||
|
||||
def getUserPrincipalLookupService(self):
|
||||
raise AndroidOnlyError("UserPrincipalLookupService")
|
||||
|
||||
def newWatchService(self):
|
||||
raise AndroidOnlyError("WatchService")
|
||||
|
||||
def getFileStores(self):
|
||||
return [FileStore("/")]
|
||||
|
||||
def supportedFileAttributeViews(self):
|
||||
return ["basic", "owner", "posix"]
|
||||
|
||||
def close(self):
|
||||
self._open = False
|
||||
|
||||
def isOpen(self):
|
||||
return self._open
|
||||
|
||||
def isReadOnly(self):
|
||||
return False
|
||||
|
||||
|
||||
class FileSystems(Stub):
|
||||
_default = None
|
||||
|
||||
@staticmethod
|
||||
def getDefault():
|
||||
if FileSystems._default is None:
|
||||
FileSystems._default = FileSystem()
|
||||
return FileSystems._default
|
||||
|
||||
|
||||
# ============================================================
|
||||
# FileStore
|
||||
# ============================================================
|
||||
|
||||
class FileStore(Stub):
|
||||
def __init__(self, path):
|
||||
super().__init__()
|
||||
self._path = path
|
||||
|
||||
def name(self):
|
||||
return _os.path.basename(self._path) or "/"
|
||||
|
||||
def type(self):
|
||||
return "ext4"
|
||||
|
||||
def isReadOnly(self):
|
||||
return False
|
||||
|
||||
def getTotalSpace(self):
|
||||
try:
|
||||
st = _os.statvfs(self._path)
|
||||
return st.f_frsize * st.f_blocks
|
||||
except OSError:
|
||||
return 0
|
||||
|
||||
def getUsableSpace(self):
|
||||
try:
|
||||
st = _os.statvfs(self._path)
|
||||
return st.f_frsize * st.f_bavail
|
||||
except OSError:
|
||||
return 0
|
||||
|
||||
def getUnallocatedSpace(self):
|
||||
try:
|
||||
st = _os.statvfs(self._path)
|
||||
return st.f_frsize * st.f_bfree
|
||||
except OSError:
|
||||
return 0
|
||||
|
||||
def toString(self):
|
||||
return f"{self.name()} ({self.type()})"
|
||||
|
||||
|
||||
# ============================================================
|
||||
# FileVisitor / SimpleFileVisitor
|
||||
# ============================================================
|
||||
|
||||
class FileVisitor(Stub):
|
||||
def preVisitDirectory(self, dir, attrs):
|
||||
return FileVisitResult.CONTINUE
|
||||
|
||||
def postVisitDirectory(self, dir, exc):
|
||||
return FileVisitResult.CONTINUE
|
||||
|
||||
def visitFile(self, file, attrs):
|
||||
return FileVisitResult.CONTINUE
|
||||
|
||||
def visitFileFailed(self, file, exc):
|
||||
return FileVisitResult.CONTINUE
|
||||
|
||||
|
||||
class SimpleFileVisitor(FileVisitor):
|
||||
pass
|
||||
|
||||
|
||||
# ============================================================
|
||||
# DirectoryStream / Filter
|
||||
# ============================================================
|
||||
|
||||
class DirectoryStream(Stub):
|
||||
def __init__(self, path, filter=None):
|
||||
super().__init__()
|
||||
self._path = path
|
||||
self._filter = filter
|
||||
|
||||
def __iter__(self):
|
||||
try:
|
||||
entries = _os.listdir(str(self._path))
|
||||
for entry in entries:
|
||||
p = Path(self._path, entry)
|
||||
if self._filter is None or self._filter.accept(p):
|
||||
yield p
|
||||
except OSError:
|
||||
raise IOException(f"Failed to list directory: {self._path}")
|
||||
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
|
||||
class DirectoryStreamFilter(Stub):
|
||||
def accept(self, entry):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
# ============================================================
|
||||
# PathMatcher
|
||||
# ============================================================
|
||||
|
||||
class PathMatcher(Stub):
|
||||
def __init__(self, pattern):
|
||||
super().__init__()
|
||||
self._pattern = pattern
|
||||
|
||||
def matches(self, path):
|
||||
import fnmatch
|
||||
return fnmatch.fnmatch(str(path), self._pattern)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# WatchService / WatchKey / WatchEvent / Watchable (stubs)
|
||||
# ============================================================
|
||||
|
||||
class Watchable(Stub):
|
||||
def register(self, watcher, events, *modifiers):
|
||||
raise AndroidOnlyError("WatchService")
|
||||
|
||||
class WatchService(Stub):
|
||||
def close(self):
|
||||
pass
|
||||
def poll(self):
|
||||
return None
|
||||
def take(self):
|
||||
raise AndroidOnlyError("WatchService.take")
|
||||
def poll(self, timeout, unit):
|
||||
return None
|
||||
|
||||
class WatchKey(Stub):
|
||||
def isValid(self):
|
||||
return True
|
||||
def pollEvents(self):
|
||||
return []
|
||||
def reset(self):
|
||||
return True
|
||||
def cancel(self):
|
||||
pass
|
||||
def watchable(self):
|
||||
return None
|
||||
|
||||
class WatchEvent(Stub):
|
||||
class Kind(Stub):
|
||||
def name(self):
|
||||
return ""
|
||||
def type(self):
|
||||
return None
|
||||
|
||||
def kind(self):
|
||||
return None
|
||||
def count(self):
|
||||
return 0
|
||||
def context(self):
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Files
|
||||
# ============================================================
|
||||
|
||||
class Files(Stub):
|
||||
@staticmethod
|
||||
def copy(source, target, *options):
|
||||
src = str(source)
|
||||
dst = str(target)
|
||||
replace = any(isinstance(o, StandardCopyOption) and o == StandardCopyOption.REPLACE_EXISTING for o in options)
|
||||
try:
|
||||
if replace and _os.path.exists(dst):
|
||||
_os.remove(dst)
|
||||
if _os.path.isdir(src):
|
||||
_shutil.copytree(src, dst)
|
||||
else:
|
||||
_shutil.copy2(src, dst)
|
||||
except OSError as e:
|
||||
raise IOException(str(e))
|
||||
|
||||
@staticmethod
|
||||
def move(source, target, *options):
|
||||
src = str(source)
|
||||
dst = str(target)
|
||||
replace = any(isinstance(o, StandardCopyOption) and o == StandardCopyOption.REPLACE_EXISTING for o in options)
|
||||
try:
|
||||
if replace and _os.path.exists(dst):
|
||||
_os.remove(dst)
|
||||
_shutil.move(src, dst)
|
||||
except OSError as e:
|
||||
raise IOException(str(e))
|
||||
|
||||
@staticmethod
|
||||
def delete(path):
|
||||
try:
|
||||
p = str(path)
|
||||
if _os.path.isdir(p):
|
||||
_os.rmdir(p)
|
||||
else:
|
||||
_os.remove(p)
|
||||
except OSError as e:
|
||||
raise NoSuchFileException(str(path))
|
||||
|
||||
@staticmethod
|
||||
def deleteIfExists(path):
|
||||
try:
|
||||
Files.delete(path)
|
||||
return True
|
||||
except NoSuchFileException:
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def createDirectories(path):
|
||||
_os.makedirs(str(path), exist_ok=True)
|
||||
return path
|
||||
|
||||
@staticmethod
|
||||
def createDirectory(path, attrs=None):
|
||||
_os.makedirs(str(path), exist_ok=True)
|
||||
return path
|
||||
|
||||
@staticmethod
|
||||
def createFile(path, attrs=None):
|
||||
p = str(path)
|
||||
if _os.path.exists(p):
|
||||
raise FileAlreadyExistsException(str(path))
|
||||
open(p, "a").close()
|
||||
return path
|
||||
|
||||
@staticmethod
|
||||
def createTempFile(prefix, suffix, dir=None):
|
||||
f = _tempfile.NamedTemporaryFile(prefix=prefix, suffix=suffix,
|
||||
dir=str(dir) if dir else None, delete=False)
|
||||
p = f.name
|
||||
f.close()
|
||||
return Path(p)
|
||||
|
||||
@staticmethod
|
||||
def createTempDirectory(prefix, attrs=None):
|
||||
d = _tempfile.mkdtemp(prefix=prefix)
|
||||
return Path(d)
|
||||
|
||||
@staticmethod
|
||||
def exists(path, *options):
|
||||
return _os.path.exists(str(path))
|
||||
|
||||
@staticmethod
|
||||
def notExists(path, *options):
|
||||
return not _os.path.exists(str(path))
|
||||
|
||||
@staticmethod
|
||||
def isReadable(path):
|
||||
return _os.access(str(path), _os.R_OK)
|
||||
|
||||
@staticmethod
|
||||
def isWritable(path):
|
||||
return _os.access(str(path), _os.W_OK)
|
||||
|
||||
@staticmethod
|
||||
def isExecutable(path):
|
||||
return _os.access(str(path), _os.X_OK)
|
||||
|
||||
@staticmethod
|
||||
def isDirectory(path, *options):
|
||||
return _os.path.isdir(str(path))
|
||||
|
||||
@staticmethod
|
||||
def isRegularFile(path, *options):
|
||||
return _os.path.isfile(str(path))
|
||||
|
||||
@staticmethod
|
||||
def isSymbolicLink(path):
|
||||
return _os.path.islink(str(path))
|
||||
|
||||
@staticmethod
|
||||
def isHidden(path):
|
||||
return _os.path.basename(str(path)).startswith(".")
|
||||
|
||||
@staticmethod
|
||||
def getLastModifiedTime(path, *options):
|
||||
return int(_os.path.getmtime(str(path)) * 1000)
|
||||
|
||||
@staticmethod
|
||||
def setLastModifiedTime(path, time):
|
||||
_os.utime(str(path), (time / 1000, time / 1000))
|
||||
|
||||
@staticmethod
|
||||
def getAttribute(path, attribute, *options):
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def setAttribute(path, attribute, value, *options):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def getPosixFilePermissions(path, *options):
|
||||
return []
|
||||
|
||||
@staticmethod
|
||||
def setPosixFilePermissions(path, perms, *options):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def newInputStream(path, *options):
|
||||
from ..io import FileInputStream
|
||||
return FileInputStream(str(path))
|
||||
|
||||
@staticmethod
|
||||
def newOutputStream(path, *options):
|
||||
from ..io import FileOutputStream
|
||||
append = any(isinstance(o, StandardOpenOption) and o == StandardOpenOption.APPEND for o in options)
|
||||
return FileOutputStream(str(path), append)
|
||||
|
||||
@staticmethod
|
||||
def newBufferedReader(path, charset=None):
|
||||
from ..io import BufferedReader, InputStreamReader, FileInputStream
|
||||
inp = FileInputStream(str(path))
|
||||
reader = InputStreamReader(inp, charset or "utf-8")
|
||||
return BufferedReader(reader)
|
||||
|
||||
@staticmethod
|
||||
def newBufferedWriter(path, charset=None, *options):
|
||||
from ..io import BufferedWriter, OutputStreamWriter, FileOutputStream
|
||||
append = any(isinstance(o, StandardOpenOption) and o == StandardOpenOption.APPEND for o in options)
|
||||
out = FileOutputStream(str(path), append)
|
||||
writer = OutputStreamWriter(out, charset or "utf-8")
|
||||
return BufferedWriter(writer)
|
||||
|
||||
@staticmethod
|
||||
def readAllBytes(path):
|
||||
with open(str(path), "rb") as f:
|
||||
return f.read()
|
||||
|
||||
@staticmethod
|
||||
def readAllLines(path, charset=None):
|
||||
with open(str(path), "r", encoding=charset or "utf-8") as f:
|
||||
return f.read().splitlines()
|
||||
|
||||
@staticmethod
|
||||
def readString(path, charset=None):
|
||||
with open(str(path), "r", encoding=charset or "utf-8") as f:
|
||||
return f.read()
|
||||
|
||||
@staticmethod
|
||||
def write(path, content, *options):
|
||||
mode = "wb" if isinstance(content, bytes) else "w"
|
||||
open_mode = mode
|
||||
if any(isinstance(o, StandardOpenOption) and o == StandardOpenOption.APPEND for o in options):
|
||||
open_mode = "ab" if mode == "wb" else "a"
|
||||
with open(str(path), open_mode) as f:
|
||||
f.write(content)
|
||||
|
||||
@staticmethod
|
||||
def writeString(path, content, *options):
|
||||
open_mode = "w"
|
||||
if any(isinstance(o, StandardOpenOption) and o == StandardOpenOption.APPEND for o in options):
|
||||
open_mode = "a"
|
||||
with open(str(path), open_mode, encoding="utf-8") as f:
|
||||
f.write(content)
|
||||
|
||||
@staticmethod
|
||||
def list(path):
|
||||
try:
|
||||
return [Path(_os.path.join(str(path), entry)) for entry in _os.listdir(str(path))]
|
||||
except OSError:
|
||||
raise IOException(f"Failed to list directory: {path}")
|
||||
|
||||
@staticmethod
|
||||
def walk(path, maxDepth=None):
|
||||
for root, dirs, files in _os.walk(str(path)):
|
||||
yield Path(root)
|
||||
|
||||
@staticmethod
|
||||
def find(start, maxDepth, matcher, *options):
|
||||
for root, dirs, files in _os.walk(str(start)):
|
||||
for f in files:
|
||||
p = Path(_os.path.join(root, f))
|
||||
if matcher.matches(p):
|
||||
yield p
|
||||
|
||||
@staticmethod
|
||||
def lines(path, charset=None):
|
||||
with open(str(path), "r", encoding=charset or "utf-8") as f:
|
||||
for line in f:
|
||||
yield line.rstrip("\n")
|
||||
|
||||
@staticmethod
|
||||
def getFileStore(path):
|
||||
return FileStore(str(path))
|
||||
|
||||
@staticmethod
|
||||
def probeContentType(path):
|
||||
return "application/octet-stream"
|
||||
|
||||
@staticmethod
|
||||
def getOwner(path, *options):
|
||||
raise AndroidOnlyError("getOwner")
|
||||
|
||||
@staticmethod
|
||||
def setOwner(path, owner, *options):
|
||||
raise AndroidOnlyError("setOwner")
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,287 @@
|
||||
"""
|
||||
Java regex standard library APIs implemented in Python.
|
||||
java.util.regex package - Pattern, Matcher, MatchResult, PatternSyntaxException.
|
||||
"""
|
||||
|
||||
from .._core import Stub
|
||||
from .io import IOException
|
||||
from .lang import RuntimeException
|
||||
import re as _re
|
||||
|
||||
IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
|
||||
IllegalStateException = type("IllegalStateException", (RuntimeException,), {})
|
||||
|
||||
__all__ = [
|
||||
"Pattern", "Matcher", "MatchResult", "PatternSyntaxException",
|
||||
]
|
||||
|
||||
|
||||
# ============================================================
|
||||
# PatternSyntaxException
|
||||
# ============================================================
|
||||
|
||||
class PatternSyntaxException(IllegalArgumentException):
|
||||
def __init__(self, desc, regex, index):
|
||||
super().__init__(f"{desc}: {regex} at index {index}")
|
||||
self._desc = desc
|
||||
self._regex = regex
|
||||
self._index = index
|
||||
|
||||
def getDescription(self):
|
||||
return self._desc
|
||||
|
||||
def getPattern(self):
|
||||
return self._regex
|
||||
|
||||
def getIndex(self):
|
||||
return self._index
|
||||
|
||||
def getMessage(self):
|
||||
return f"{self._desc} near index {self._index}: {self._regex}"
|
||||
|
||||
|
||||
# ============================================================
|
||||
# MatchResult
|
||||
# ============================================================
|
||||
|
||||
class MatchResult(Stub):
|
||||
def start(self, group=None):
|
||||
raise NotImplementedError
|
||||
|
||||
def end(self, group=None):
|
||||
raise NotImplementedError
|
||||
|
||||
def group(self, group=None):
|
||||
raise NotImplementedError
|
||||
|
||||
def groupCount(self):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Matcher
|
||||
# ============================================================
|
||||
|
||||
class Matcher(MatchResult):
|
||||
def __init__(self, pattern, input_str):
|
||||
super().__init__()
|
||||
self._pattern = pattern
|
||||
self._input = input_str
|
||||
self._re_pattern = pattern._pattern
|
||||
self._match = None
|
||||
self._region_start = 0
|
||||
self._region_end = len(input_str)
|
||||
self._transparent_bounds = False
|
||||
self._anchoring_bounds = True
|
||||
self._last_match = None
|
||||
|
||||
def matches(self):
|
||||
self._match = self._re_pattern.fullmatch(self._input, self._region_start, self._region_end)
|
||||
self._last_match = self._match
|
||||
return self._match is not None
|
||||
|
||||
def find(self, start=None):
|
||||
if start is not None:
|
||||
self._match = self._re_pattern.search(self._input, start, self._region_end)
|
||||
else:
|
||||
if self._match is None:
|
||||
self._match = self._re_pattern.search(self._input, self._region_start, self._region_end)
|
||||
else:
|
||||
pos = self._match.end()
|
||||
self._match = self._re_pattern.search(self._input, pos, self._region_end)
|
||||
if self._match:
|
||||
self._last_match = self._match
|
||||
return self._match is not None
|
||||
|
||||
def lookingAt(self):
|
||||
self._match = self._re_pattern.match(self._input, self._region_start, self._region_end)
|
||||
self._last_match = self._match
|
||||
return self._match is not None
|
||||
|
||||
def start(self, group=0):
|
||||
if self._match is None:
|
||||
raise IllegalStateException("No match available")
|
||||
if group == 0:
|
||||
return self._match.start()
|
||||
return self._match.start(group)
|
||||
|
||||
def end(self, group=0):
|
||||
if self._match is None:
|
||||
raise IllegalStateException("No match available")
|
||||
if group == 0:
|
||||
return self._match.end()
|
||||
return self._match.end(group)
|
||||
|
||||
def group(self, group=0):
|
||||
if self._match is None:
|
||||
raise IllegalStateException("No match available")
|
||||
if isinstance(group, str):
|
||||
return self._match.group(group)
|
||||
return self._match.group(group)
|
||||
|
||||
def groupCount(self):
|
||||
return self._re_pattern.groups
|
||||
|
||||
def replaceAll(self, replacement):
|
||||
return self._re_pattern.sub(replacement, self._input)
|
||||
|
||||
def replaceFirst(self, replacement):
|
||||
return self._re_pattern.sub(replacement, self._input, count=1)
|
||||
|
||||
def appendReplacement(self, sb, replacement):
|
||||
if self._match is None:
|
||||
raise IllegalStateException("No match available")
|
||||
self._append_pos = getattr(self, '_append_pos', 0)
|
||||
sb.append(self._input[self._append_pos:self._match.start()])
|
||||
sb.append(self._re_pattern.sub(replacement, self._match.group(), count=1))
|
||||
self._append_pos = self._match.end()
|
||||
return self
|
||||
|
||||
def appendTail(self, sb):
|
||||
self._append_pos = getattr(self, '_append_pos', 0)
|
||||
sb.append(self._input[self._append_pos:])
|
||||
return sb
|
||||
|
||||
def reset(self, input_str=None):
|
||||
if input_str is not None:
|
||||
self._input = input_str
|
||||
self._region_end = len(input_str)
|
||||
self._match = None
|
||||
self._last_match = None
|
||||
return self
|
||||
|
||||
def region(self, start, end):
|
||||
self._region_start = start
|
||||
self._region_end = end
|
||||
return self
|
||||
|
||||
def regionStart(self):
|
||||
return self._region_start
|
||||
|
||||
def regionEnd(self):
|
||||
return self._region_end
|
||||
|
||||
def hasTransparentBounds(self):
|
||||
return self._transparent_bounds
|
||||
|
||||
def hasAnchoringBounds(self):
|
||||
return self._anchoring_bounds
|
||||
|
||||
def useAnchoringBounds(self, value):
|
||||
self._anchoring_bounds = value
|
||||
return self
|
||||
|
||||
def useTransparentBounds(self, value):
|
||||
self._transparent_bounds = value
|
||||
return self
|
||||
|
||||
def hitEnd(self):
|
||||
return self._match is not None and self._match.end() >= self._region_end
|
||||
|
||||
def requireEnd(self):
|
||||
return self._match is not None and not self.hitEnd()
|
||||
|
||||
def toMatchResult(self):
|
||||
result = Matcher(self._pattern, self._input)
|
||||
result._match = self._match
|
||||
result._last_match = self._last_match
|
||||
return result
|
||||
|
||||
def pattern(self):
|
||||
return self._pattern
|
||||
|
||||
def toString(self):
|
||||
return f"Matcher[pattern={self._pattern.pattern()}]"
|
||||
|
||||
def namedGroups(self):
|
||||
return self._re_pattern.groupindex
|
||||
|
||||
|
||||
class IllegalStateException(RuntimeException):
|
||||
pass
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Pattern
|
||||
# ============================================================
|
||||
|
||||
class Pattern(Stub):
|
||||
CANON_EQ = 128
|
||||
CASE_INSENSITIVE = 2
|
||||
COMMENTS = 4
|
||||
DOTALL = 32
|
||||
LITERAL = 16
|
||||
MULTILINE = 8
|
||||
UNICODE_CASE = 64
|
||||
UNICODE_CHARACTER_CLASS = 256
|
||||
UNIX_LINES = 1
|
||||
|
||||
_re_flags_map = {
|
||||
0: 0, # default
|
||||
2: _re.IGNORECASE,
|
||||
8: _re.MULTILINE,
|
||||
32: _re.DOTALL,
|
||||
64: _re.UNICODE,
|
||||
4: _re.VERBOSE,
|
||||
}
|
||||
|
||||
def __init__(self, regex, flags=0):
|
||||
super().__init__()
|
||||
self._regex = str(regex)
|
||||
self._flags = flags
|
||||
re_flags = 0
|
||||
for java_flag, py_flag in self._re_flags_map.items():
|
||||
if flags & java_flag:
|
||||
re_flags |= py_flag
|
||||
try:
|
||||
self._pattern = _re.compile(self._regex, re_flags)
|
||||
except _re.error as e:
|
||||
raise PatternSyntaxException(str(e), self._regex, e.pos if hasattr(e, 'pos') else 0)
|
||||
|
||||
@staticmethod
|
||||
def compile(regex, flags=0):
|
||||
return Pattern(regex, flags)
|
||||
|
||||
def matcher(self, input_str):
|
||||
return Matcher(self, input_str)
|
||||
|
||||
def split(self, input_str, limit=0):
|
||||
if limit <= 0:
|
||||
parts = self._pattern.split(str(input_str))
|
||||
if limit == 0:
|
||||
while parts and parts[-1] == "":
|
||||
parts.pop()
|
||||
else:
|
||||
parts = self._pattern.split(str(input_str), maxsplit=limit - 1)
|
||||
while len(parts) < limit:
|
||||
parts.append("")
|
||||
return parts
|
||||
|
||||
def splitAsStream(self, input_str):
|
||||
return iter(self.split(input_str))
|
||||
|
||||
@staticmethod
|
||||
def matches(regex, input_str):
|
||||
return bool(_re.fullmatch(regex, str(input_str)))
|
||||
|
||||
@staticmethod
|
||||
def quote(s):
|
||||
return _re.escape(str(s))
|
||||
|
||||
def flags(self):
|
||||
return self._flags
|
||||
|
||||
def pattern(self):
|
||||
return self._regex
|
||||
|
||||
def toString(self):
|
||||
return self._regex
|
||||
|
||||
def predicate(self):
|
||||
return lambda s: bool(self._pattern.fullmatch(str(s)))
|
||||
|
||||
def asPredicate(self):
|
||||
return self.predicate()
|
||||
|
||||
def asMatchPredicate(self):
|
||||
return lambda s: bool(self._pattern.fullmatch(str(s)))
|
||||
@@ -0,0 +1,697 @@
|
||||
"""
|
||||
Java zip standard library APIs implemented in Python.
|
||||
java.util.zip package - ZipFile, ZipEntry, GZIP, CRC, Deflater, Inflater.
|
||||
"""
|
||||
|
||||
from .._core import Stub
|
||||
from .io import IOException, Closeable, Flushable
|
||||
import zipfile as _zipfile
|
||||
import gzip as _gzip
|
||||
import zlib as _zlib
|
||||
import io as _pyio
|
||||
import os as _os
|
||||
from datetime import datetime as _datetime
|
||||
|
||||
__all__ = [
|
||||
"ZipFile", "ZipEntry", "ZipOutputStream", "ZipInputStream",
|
||||
"GZIPInputStream", "GZIPOutputStream",
|
||||
"CRC32", "CheckedInputStream", "CheckedOutputStream",
|
||||
"Adler32",
|
||||
"DataFormatException", "ZipException",
|
||||
"Deflater", "Inflater",
|
||||
"DeflaterOutputStream", "InflaterInputStream",
|
||||
]
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Exception classes
|
||||
# ============================================================
|
||||
|
||||
class ZipException(IOException):
|
||||
pass
|
||||
|
||||
class DataFormatException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
# ============================================================
|
||||
# CRC32
|
||||
# ============================================================
|
||||
|
||||
class CRC32(Stub):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._value = 0
|
||||
|
||||
def getValue(self):
|
||||
return self._value
|
||||
|
||||
def reset(self):
|
||||
self._value = 0
|
||||
|
||||
def update(self, b, off=None, length=None):
|
||||
if isinstance(b, int):
|
||||
self._value = _zlib.crc32(bytes([b & 0xFF]), self._value) & 0xFFFFFFFF
|
||||
elif isinstance(b, (bytes, bytearray)):
|
||||
if off is not None and length is not None:
|
||||
self._value = _zlib.crc32(bytes(b[off:off+length]), self._value) & 0xFFFFFFFF
|
||||
else:
|
||||
self._value = _zlib.crc32(bytes(b), self._value) & 0xFFFFFFFF
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Adler32
|
||||
# ============================================================
|
||||
|
||||
class Adler32(Stub):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._value = 1
|
||||
|
||||
def getValue(self):
|
||||
return self._value
|
||||
|
||||
def reset(self):
|
||||
self._value = 1
|
||||
|
||||
def update(self, b, off=None, length=None):
|
||||
if isinstance(b, int):
|
||||
self._value = _zlib.adler32(bytes([b & 0xFF]), self._value) & 0xFFFFFFFF
|
||||
elif isinstance(b, (bytes, bytearray)):
|
||||
if off is not None and length is not None:
|
||||
self._value = _zlib.adler32(bytes(b[off:off+length]), self._value) & 0xFFFFFFFF
|
||||
else:
|
||||
self._value = _zlib.adler32(bytes(b), self._value) & 0xFFFFFFFF
|
||||
|
||||
|
||||
# ============================================================
|
||||
# CheckedInputStream / CheckedOutputStream
|
||||
# ============================================================
|
||||
|
||||
class CheckedInputStream(Closeable):
|
||||
def __init__(self, inp, cksum):
|
||||
super().__init__()
|
||||
self._in = inp
|
||||
self._cksum = cksum
|
||||
|
||||
def read(self, b=None, off=None, length=None):
|
||||
if b is None:
|
||||
result = self._in.read()
|
||||
if result >= 0:
|
||||
self._cksum.update(result)
|
||||
return result
|
||||
if off is None:
|
||||
off = 0
|
||||
if length is None:
|
||||
length = len(b)
|
||||
result = self._in.read(b, off, length)
|
||||
if result > 0:
|
||||
self._cksum.update(b[off:off+result])
|
||||
return result
|
||||
|
||||
def getChecksum(self):
|
||||
return self._cksum
|
||||
|
||||
def close(self):
|
||||
self._in.close()
|
||||
|
||||
def skip(self, n):
|
||||
return self._in.skip(n)
|
||||
|
||||
|
||||
class CheckedOutputStream(Closeable, Flushable):
|
||||
def __init__(self, out, cksum):
|
||||
super().__init__()
|
||||
self._out = out
|
||||
self._cksum = cksum
|
||||
|
||||
def write(self, b, off=None, length=None):
|
||||
if isinstance(b, int):
|
||||
self._out.write(b)
|
||||
self._cksum.update(b)
|
||||
else:
|
||||
if off is not None and length is not None:
|
||||
data = bytes(b[off:off+length])
|
||||
else:
|
||||
data = bytes(b)
|
||||
self._out.write(data)
|
||||
self._cksum.update(data)
|
||||
|
||||
def getChecksum(self):
|
||||
return self._cksum
|
||||
|
||||
def flush(self):
|
||||
self._out.flush()
|
||||
|
||||
def close(self):
|
||||
self._out.close()
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ZipEntry
|
||||
# ============================================================
|
||||
|
||||
class ZipEntry(Stub):
|
||||
STORED = 0
|
||||
DEFLATED = 8
|
||||
|
||||
def __init__(self, name):
|
||||
super().__init__()
|
||||
self._name = name
|
||||
self._method = ZipEntry.DEFLATED
|
||||
self._size = 0
|
||||
self._compressed_size = 0
|
||||
self._crc = 0
|
||||
self._comment = ""
|
||||
self._time = 0
|
||||
self._extra = b""
|
||||
self._is_directory = name.endswith("/")
|
||||
|
||||
def getName(self):
|
||||
return self._name
|
||||
|
||||
def getMethod(self):
|
||||
return self._method
|
||||
|
||||
def setMethod(self, method):
|
||||
self._method = method
|
||||
|
||||
def getSize(self):
|
||||
return self._size
|
||||
|
||||
def setSize(self, size):
|
||||
self._size = size
|
||||
|
||||
def getCompressedSize(self):
|
||||
return self._compressed_size
|
||||
|
||||
def setCompressedSize(self, size):
|
||||
self._compressed_size = size
|
||||
|
||||
def getCrc(self):
|
||||
return self._crc
|
||||
|
||||
def setCrc(self, crc):
|
||||
self._crc = crc
|
||||
|
||||
def getComment(self):
|
||||
return self._comment
|
||||
|
||||
def setComment(self, comment):
|
||||
self._comment = comment
|
||||
|
||||
def getTime(self):
|
||||
return self._time
|
||||
|
||||
def setTime(self, time):
|
||||
self._time = time
|
||||
|
||||
def getExtra(self):
|
||||
return self._extra
|
||||
|
||||
def setExtra(self, extra):
|
||||
self._extra = extra
|
||||
|
||||
def isDirectory(self):
|
||||
return self._is_directory
|
||||
|
||||
def toString(self):
|
||||
return self._name
|
||||
|
||||
def __str__(self):
|
||||
return self._name
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ZipFile
|
||||
# ============================================================
|
||||
|
||||
class ZipFile(Closeable):
|
||||
OPEN_READ = 1
|
||||
OPEN_DELETE = 2
|
||||
|
||||
def __init__(self, file, mode="r"):
|
||||
super().__init__()
|
||||
if isinstance(file, str):
|
||||
path = file
|
||||
else:
|
||||
path = file.getPath()
|
||||
self._path = path
|
||||
self._mode = mode
|
||||
try:
|
||||
self._zfile = _zipfile.ZipFile(path, mode)
|
||||
except Exception as e:
|
||||
raise ZipException(str(e))
|
||||
|
||||
def entries(self):
|
||||
return iter(self._zfile.infolist())
|
||||
|
||||
def getEntry(self, name):
|
||||
try:
|
||||
info = self._zfile.getinfo(name)
|
||||
entry = ZipEntry(info.filename)
|
||||
entry.setMethod(info.compress_type)
|
||||
entry.setSize(info.file_size)
|
||||
entry.setCompressedSize(info.compress_size)
|
||||
entry.setCrc(info.CRC)
|
||||
entry.setTime(int(_datetime(*info.date_time).timestamp() * 1000) if info.date_time else 0)
|
||||
return entry
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
def getInputStream(self, entry):
|
||||
try:
|
||||
data = self._zfile.read(entry.getName() if isinstance(entry, ZipEntry) else entry)
|
||||
from ..io import ByteArrayInputStream
|
||||
return ByteArrayInputStream(data)
|
||||
except Exception as e:
|
||||
raise ZipException(str(e))
|
||||
|
||||
def close(self):
|
||||
self._zfile.close()
|
||||
|
||||
def size(self):
|
||||
return len(self._zfile.namelist())
|
||||
|
||||
def getName(self):
|
||||
return self._path
|
||||
|
||||
def getComment(self):
|
||||
return ""
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ZipOutputStream
|
||||
# ============================================================
|
||||
|
||||
class ZipOutputStream(Closeable, Flushable):
|
||||
STORED = 0
|
||||
DEFLATED = 8
|
||||
|
||||
def __init__(self, out):
|
||||
super().__init__()
|
||||
self._out = out
|
||||
self._zfile = _zipfile.ZipFile(out, "w", _zipfile.ZIP_DEFLATED)
|
||||
self._method = ZipOutputStream.DEFLATED
|
||||
self._level = -1
|
||||
self._comment = ""
|
||||
|
||||
def putNextEntry(self, entry):
|
||||
zi = _zipfile.ZipInfo(entry.getName() if isinstance(entry, ZipEntry) else str(entry))
|
||||
if hasattr(entry, 'getTime') and entry.getTime():
|
||||
dt = _datetime.fromtimestamp(entry.getTime() / 1000.0)
|
||||
zi.date_time = dt.timetuple()[:6]
|
||||
self._zfile.writestr(zi, b"")
|
||||
|
||||
def closeEntry(self):
|
||||
pass
|
||||
|
||||
def write(self, b, off=None, length=None):
|
||||
if off is not None and length is not None:
|
||||
self._zfile._zout.write(bytes(b[off:off+length]))
|
||||
else:
|
||||
self._zfile._zout.write(bytes(b) if not isinstance(b, (bytes, bytearray)) else b)
|
||||
|
||||
def finish(self):
|
||||
self._zfile.close()
|
||||
|
||||
def close(self):
|
||||
self._zfile.close()
|
||||
|
||||
def setMethod(self, method):
|
||||
self._method = method
|
||||
|
||||
def setLevel(self, level):
|
||||
self._level = level
|
||||
|
||||
def setComment(self, comment):
|
||||
self._comment = comment
|
||||
|
||||
def flush(self):
|
||||
self._zfile._zout.flush() if hasattr(self._zfile._zout, 'flush') else None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ZipInputStream
|
||||
# ============================================================
|
||||
|
||||
class ZipInputStream(Closeable):
|
||||
def __init__(self, inp):
|
||||
super().__init__()
|
||||
self._inp = inp
|
||||
self._zfile = _zipfile.ZipFile(inp)
|
||||
self._entries = iter(self._zfile.infolist())
|
||||
self._current_entry = None
|
||||
self._current_data = b""
|
||||
self._current_pos = 0
|
||||
|
||||
def getNextEntry(self):
|
||||
try:
|
||||
info = next(self._entries)
|
||||
entry = ZipEntry(info.filename)
|
||||
entry.setMethod(info.compress_type)
|
||||
entry.setSize(info.file_size)
|
||||
entry.setCompressedSize(info.compress_size)
|
||||
entry.setCrc(info.CRC)
|
||||
self._current_entry = info
|
||||
self._current_data = self._zfile.read(info)
|
||||
self._current_pos = 0
|
||||
return entry
|
||||
except StopIteration:
|
||||
self._current_entry = None
|
||||
self._current_data = b""
|
||||
return None
|
||||
|
||||
def read(self, b=None, off=None, length=None):
|
||||
if self._current_entry is None:
|
||||
return -1
|
||||
avail = len(self._current_data) - self._current_pos
|
||||
if avail <= 0:
|
||||
return -1
|
||||
if b is None:
|
||||
val = self._current_data[self._current_pos]
|
||||
self._current_pos += 1
|
||||
return val
|
||||
if off is None:
|
||||
off = 0
|
||||
if length is None:
|
||||
length = len(b)
|
||||
n = min(length, avail)
|
||||
if isinstance(b, bytearray):
|
||||
b[off:off+n] = self._current_data[self._current_pos:self._current_pos+n]
|
||||
self._current_pos += n
|
||||
return n
|
||||
|
||||
def closeEntry(self):
|
||||
self._current_entry = None
|
||||
self._current_data = b""
|
||||
|
||||
def available(self):
|
||||
if self._current_entry is None:
|
||||
return 0
|
||||
return len(self._current_data) - self._current_pos
|
||||
|
||||
def close(self):
|
||||
self._zfile.close()
|
||||
|
||||
|
||||
# ============================================================
|
||||
# GZIPInputStream
|
||||
# ============================================================
|
||||
|
||||
class GZIPInputStream(Closeable):
|
||||
def __init__(self, inp, size=512):
|
||||
super().__init__()
|
||||
self._inp = inp
|
||||
self._gzip_file = _gzip.GzipFile(fileobj=_pyio.BufferedReader(inp) if hasattr(inp, 'read') else inp)
|
||||
|
||||
def read(self, b=None, off=None, length=None):
|
||||
if b is None:
|
||||
data = self._gzip_file.read(1)
|
||||
return data[0] if data else -1
|
||||
if off is None:
|
||||
off = 0
|
||||
if length is None:
|
||||
length = len(b)
|
||||
data = self._gzip_file.read(length)
|
||||
if not data:
|
||||
return -1
|
||||
n = len(data)
|
||||
if isinstance(b, bytearray):
|
||||
b[off:off+n] = data
|
||||
else:
|
||||
ba = bytearray(b)
|
||||
ba[off:off+n] = data
|
||||
b[:] = bytes(ba)
|
||||
return n
|
||||
|
||||
def close(self):
|
||||
self._gzip_file.close()
|
||||
|
||||
|
||||
# ============================================================
|
||||
# GZIPOutputStream
|
||||
# ============================================================
|
||||
|
||||
class GZIPOutputStream(Closeable, Flushable):
|
||||
def __init__(self, out, size=512):
|
||||
super().__init__()
|
||||
self._out = out
|
||||
self._gzip_file = _gzip.GzipFile(fileobj=out, mode="wb")
|
||||
|
||||
def write(self, b, off=None, length=None):
|
||||
if isinstance(b, int):
|
||||
self._gzip_file.write(bytes([b & 0xFF]))
|
||||
elif isinstance(b, (bytes, bytearray)):
|
||||
if off is not None and length is not None:
|
||||
self._gzip_file.write(bytes(b[off:off+length]))
|
||||
else:
|
||||
self._gzip_file.write(bytes(b))
|
||||
|
||||
def finish(self):
|
||||
self._gzip_file.close()
|
||||
|
||||
def close(self):
|
||||
self._gzip_file.close()
|
||||
|
||||
def flush(self):
|
||||
self._gzip_file.flush()
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Deflater
|
||||
# ============================================================
|
||||
|
||||
class Deflater(Stub):
|
||||
BEST_COMPRESSION = 9
|
||||
BEST_SPEED = 1
|
||||
DEFAULT_COMPRESSION = -1
|
||||
DEFAULT_STRATEGY = 0
|
||||
FILTERED = 1
|
||||
HUFFMAN_ONLY = 2
|
||||
NO_COMPRESSION = 0
|
||||
NO_FLUSH = 0
|
||||
SYNC_FLUSH = 2
|
||||
FULL_FLUSH = 3
|
||||
|
||||
def __init__(self, level=-1, nowrap=False):
|
||||
super().__init__()
|
||||
self._level = level
|
||||
self._nowrap = nowrap
|
||||
self._compress = _zlib.compressobj(level=level if level >= 0 else 6,
|
||||
method=_zlib.DEFLATED,
|
||||
wbits=-_zlib.MAX_WBITS if nowrap else _zlib.MAX_WBITS)
|
||||
self._input_buffer = b""
|
||||
self._finished = False
|
||||
|
||||
def setInput(self, data, off=0, length=-1):
|
||||
if length < 0:
|
||||
length = len(data) - off
|
||||
self._input_buffer = bytes(data[off:off+length])
|
||||
|
||||
def needsInput(self):
|
||||
return len(self._input_buffer) == 0
|
||||
|
||||
def setDictionary(self, dictionary):
|
||||
pass
|
||||
|
||||
def getTotalIn(self):
|
||||
return len(self._input_buffer)
|
||||
|
||||
def getTotalOut(self):
|
||||
return 0
|
||||
|
||||
def deflate(self, output, off=0, length=-1):
|
||||
if length < 0:
|
||||
length = len(output) - off
|
||||
data = self._compress.compress(self._input_buffer)
|
||||
self._input_buffer = b""
|
||||
n = min(len(data), length)
|
||||
if isinstance(output, bytearray):
|
||||
output[off:off+n] = data[:n]
|
||||
else:
|
||||
ba = bytearray(output)
|
||||
ba[off:off+n] = data[:n]
|
||||
output[:] = bytes(ba)
|
||||
return n
|
||||
|
||||
def finish(self):
|
||||
self._finished = True
|
||||
|
||||
def finished(self):
|
||||
return self._finished
|
||||
|
||||
def end(self):
|
||||
pass
|
||||
|
||||
def getAdler(self):
|
||||
return 1
|
||||
|
||||
def reset(self):
|
||||
self._compress = _zlib.compressobj(level=self._level if self._level >= 0 else 6,
|
||||
method=_zlib.DEFLATED,
|
||||
wbits=-_zlib.MAX_WBITS if self._nowrap else _zlib.MAX_WBITS)
|
||||
self._input_buffer = b""
|
||||
self._finished = False
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Inflater
|
||||
# ============================================================
|
||||
|
||||
class Inflater(Stub):
|
||||
def __init__(self, nowrap=False):
|
||||
super().__init__()
|
||||
self._nowrap = nowrap
|
||||
wbits = -_zlib.MAX_WBITS if nowrap else _zlib.MAX_WBITS
|
||||
self._decompress = _zlib.decompressobj(wbits)
|
||||
self._input_buffer = b""
|
||||
self._finished = False
|
||||
|
||||
def setInput(self, data, off=0, length=-1):
|
||||
if length < 0:
|
||||
length = len(data) - off
|
||||
self._input_buffer = bytes(data[off:off+length])
|
||||
|
||||
def needsInput(self):
|
||||
return len(self._input_buffer) == 0
|
||||
|
||||
def setDictionary(self, dictionary):
|
||||
pass
|
||||
|
||||
def getTotalIn(self):
|
||||
return len(self._input_buffer)
|
||||
|
||||
def getTotalOut(self):
|
||||
return 0
|
||||
|
||||
def inflate(self, output, off=0, length=-1):
|
||||
if length < 0:
|
||||
length = len(output) - off
|
||||
try:
|
||||
data = self._decompress.decompress(self._input_buffer)
|
||||
self._input_buffer = b""
|
||||
n = min(len(data), length)
|
||||
if isinstance(output, bytearray):
|
||||
output[off:off+n] = data[:n]
|
||||
else:
|
||||
ba = bytearray(output)
|
||||
ba[off:off+n] = data[:n]
|
||||
output[:] = bytes(ba)
|
||||
return n
|
||||
except _zlib.error as e:
|
||||
raise DataFormatException(str(e))
|
||||
|
||||
def finished(self):
|
||||
return self._finished
|
||||
|
||||
def end(self):
|
||||
pass
|
||||
|
||||
def getAdler(self):
|
||||
return 1
|
||||
|
||||
def needsDictionary(self):
|
||||
return False
|
||||
|
||||
def reset(self):
|
||||
wbits = -_zlib.MAX_WBITS if self._nowrap else _zlib.MAX_WBITS
|
||||
self._decompress = _zlib.decompressobj(wbits)
|
||||
self._input_buffer = b""
|
||||
self._finished = False
|
||||
|
||||
|
||||
# ============================================================
|
||||
# DeflaterOutputStream
|
||||
# ============================================================
|
||||
|
||||
class DeflaterOutputStream(Closeable, Flushable):
|
||||
def __init__(self, out, deflater=None, size=512):
|
||||
super().__init__()
|
||||
self._out = out
|
||||
self._deflater = deflater or Deflater()
|
||||
self._buffer = bytearray(size)
|
||||
|
||||
def write(self, b, off=None, length=None):
|
||||
if isinstance(b, int):
|
||||
self._out.write(bytes([b & 0xFF]))
|
||||
else:
|
||||
if off is not None and length is not None:
|
||||
self._out.write(bytes(b[off:off+length]))
|
||||
else:
|
||||
self._deflater.setInput(bytes(b) if isinstance(b, (bytes, bytearray)) else bytes(b))
|
||||
while not self._deflater.needsInput():
|
||||
n = self._deflater.deflate(self._buffer)
|
||||
if n > 0:
|
||||
self._out.write(bytes(self._buffer[:n]))
|
||||
|
||||
def finish(self):
|
||||
self._deflater.finish()
|
||||
while not self._deflater.finished():
|
||||
n = self._deflater.deflate(self._buffer)
|
||||
if n > 0:
|
||||
self._out.write(bytes(self._buffer[:n]))
|
||||
|
||||
def close(self):
|
||||
self.finish()
|
||||
self._deflater.end()
|
||||
self._out.close()
|
||||
|
||||
def flush(self):
|
||||
self._out.flush()
|
||||
|
||||
|
||||
# ============================================================
|
||||
# InflaterInputStream
|
||||
# ============================================================
|
||||
|
||||
class InflaterInputStream(Closeable):
|
||||
def __init__(self, inp, inflater=None, size=512):
|
||||
super().__init__()
|
||||
self._in = inp
|
||||
self._inflater = inflater or Inflater()
|
||||
self._buffer = bytearray(size)
|
||||
|
||||
def read(self, b=None, off=None, length=None):
|
||||
if b is None:
|
||||
buf = bytearray(1)
|
||||
n = self._read_from_inflater(buf, 0, 1)
|
||||
return buf[0] if n > 0 else -1
|
||||
if off is None:
|
||||
off = 0
|
||||
if length is None:
|
||||
length = len(b)
|
||||
return self._read_from_inflater(b, off, length)
|
||||
|
||||
def _read_from_inflater(self, b, off, length):
|
||||
while not self._inflater.finished():
|
||||
if self._inflater.needsInput():
|
||||
data = self._in.read(self._buffer)
|
||||
if data is None or data == -1 or data == 0:
|
||||
break
|
||||
if isinstance(data, int):
|
||||
break
|
||||
self._inflater.setInput(data)
|
||||
try:
|
||||
n = self._inflater.inflate(b, off, length)
|
||||
if n > 0:
|
||||
return n
|
||||
except DataFormatException:
|
||||
break
|
||||
return -1
|
||||
|
||||
def available(self):
|
||||
return 0
|
||||
|
||||
def close(self):
|
||||
self._inflater.end()
|
||||
self._in.close()
|
||||
|
||||
def mark(self, readlimit):
|
||||
pass
|
||||
|
||||
def reset(self):
|
||||
raise IOException("mark/reset not supported")
|
||||
|
||||
def markSupported(self):
|
||||
return False
|
||||
Reference in new issue
Block a user