feat: 大规模扩充至212个模块/175K行代码 — 覆盖android/java/javax/org/dalvik全包
- android/ 167个模块 (app/content/os/view/widget/graphics/media/hardware/net/telephony/provider等) - java/ 35个模块 (lang/io/util/net/nio/security/crypto/sql/beans/rmi/awt等) - javax/ 4个模块 (net/crypto/security/sql) - org/ 5个模块 (json/w3c_dom/xml_sax/xml_pull/apache_http) - dalvik/ 1个模块 (system) - ~3053个类/接口,方法签名完全对齐Android SDK - 桌面跨平台运行 (Windows/macOS/Linux) - 修复所有导入错误和Python关键字冲突
This commit is contained in:
1 parent
506f9ac725
commit
a51854455b
128 files changed
+100571
-3
No files matched your search
@@ -0,0 +1,573 @@
|
||||
"""
|
||||
Java java.nio.charset APIs implemented in Python.
|
||||
java.nio.charset package - Charset, CharsetEncoder, CharsetDecoder, CoderResult, etc.
|
||||
Wraps Python codecs module.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from .._core import Stub, AndroidOnlyError
|
||||
import codecs as _codecs
|
||||
import encodings as _encodings
|
||||
from typing import Set as _Set, List as _List
|
||||
|
||||
__all__ = [
|
||||
"Charset", "CharsetEncoder", "CharsetDecoder", "CoderResult",
|
||||
"CodingErrorAction", "StandardCharsets",
|
||||
]
|
||||
|
||||
|
||||
# ============================================================
|
||||
# CodingErrorAction
|
||||
# ============================================================
|
||||
|
||||
class CodingErrorAction(Stub):
|
||||
"""
|
||||
java.nio.charset.CodingErrorAction
|
||||
Describes actions that a charset encoder or decoder may take on a coding error.
|
||||
"""
|
||||
REPORT: "CodingErrorAction" = None
|
||||
IGNORE: "CodingErrorAction" = None
|
||||
REPLACE: "CodingErrorAction" = None
|
||||
|
||||
def __init__(self, name: str):
|
||||
super().__init__()
|
||||
self._name = name
|
||||
|
||||
def name(self) -> str:
|
||||
return self._name
|
||||
|
||||
def toString(self) -> str:
|
||||
return self._name
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
if isinstance(other, CodingErrorAction):
|
||||
return self._name == other._name
|
||||
return False
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash(self._name) & 0x7FFFFFFF
|
||||
|
||||
|
||||
CodingErrorAction.REPORT = CodingErrorAction("REPORT")
|
||||
CodingErrorAction.IGNORE = CodingErrorAction("IGNORE")
|
||||
CodingErrorAction.REPLACE = CodingErrorAction("REPLACE")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# CoderResult
|
||||
# ============================================================
|
||||
|
||||
class CoderResult(Stub):
|
||||
"""
|
||||
java.nio.charset.CoderResult
|
||||
Describes the result state of a coder (encoder or decoder).
|
||||
"""
|
||||
UNDERFLOW: "CoderResult" = None
|
||||
OVERFLOW: "CoderResult" = None
|
||||
|
||||
def __init__(self, _type: str, _length: int = 0):
|
||||
super().__init__()
|
||||
self._type = _type
|
||||
self._length = _length
|
||||
|
||||
def isUnderflow(self) -> bool:
|
||||
"""Returns True if the result is underflow (more input needed)."""
|
||||
return self._type == "UNDERFLOW"
|
||||
|
||||
def isOverflow(self) -> bool:
|
||||
"""Returns True if the result is overflow (output buffer too small)."""
|
||||
return self._type == "OVERFLOW"
|
||||
|
||||
def isError(self) -> bool:
|
||||
"""Returns True if the result is an error (malformed or unmappable)."""
|
||||
return self._type in ("MALFORMED", "UNMAPPABLE")
|
||||
|
||||
def isMalformed(self) -> bool:
|
||||
"""Returns True if the result is a malformed-input error."""
|
||||
return self._type == "MALFORMED"
|
||||
|
||||
def isUnmappable(self) -> bool:
|
||||
"""Returns True if the result is an unmappable-character error."""
|
||||
return self._type == "UNMAPPABLE"
|
||||
|
||||
def length(self) -> int:
|
||||
"""Returns the length of the erroneous input (for errors)."""
|
||||
return self._length
|
||||
|
||||
@classmethod
|
||||
def malformedForLength(cls, length: int) -> "CoderResult":
|
||||
"""Creates a malformed CoderResult for the given length."""
|
||||
return cls("MALFORMED", length)
|
||||
|
||||
@classmethod
|
||||
def unmappableForLength(cls, length: int) -> "CoderResult":
|
||||
"""Creates an unmappable CoderResult for the given length."""
|
||||
return cls("UNMAPPABLE", length)
|
||||
|
||||
def toString(self) -> str:
|
||||
if self._type == "UNDERFLOW":
|
||||
return "UNDERFLOW"
|
||||
elif self._type == "OVERFLOW":
|
||||
return "OVERFLOW"
|
||||
return f"{self._type}[{self._length}]"
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
if not isinstance(other, CoderResult):
|
||||
return False
|
||||
return self._type == other._type and self._length == other._length
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash((self._type, self._length)) & 0x7FFFFFFF
|
||||
|
||||
|
||||
CoderResult.UNDERFLOW = CoderResult("UNDERFLOW")
|
||||
CoderResult.OVERFLOW = CoderResult("OVERFLOW")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Charset
|
||||
# ============================================================
|
||||
|
||||
class Charset(Stub):
|
||||
"""
|
||||
java.nio.charset.Charset
|
||||
A named mapping between sequences of 16-bit Unicode characters
|
||||
and sequences of bytes.
|
||||
"""
|
||||
|
||||
_cache: dict = {}
|
||||
_aliases: dict = {}
|
||||
|
||||
# Standard charset constants
|
||||
US_ASCII: "Charset" = None
|
||||
ISO_8859_1: "Charset" = None
|
||||
UTF_8: "Charset" = None
|
||||
UTF_16: "Charset" = None
|
||||
UTF_16BE: "Charset" = None
|
||||
UTF_16LE: "Charset" = None
|
||||
|
||||
def __init__(self, canonical_name: str, aliases: _List[str] = None):
|
||||
super().__init__()
|
||||
self._name = canonical_name
|
||||
self._aliases = aliases or []
|
||||
self._registered = True
|
||||
|
||||
def name(self) -> str:
|
||||
"""Returns the canonical name of this charset."""
|
||||
return self._name
|
||||
|
||||
def displayName(self, locale=None) -> str:
|
||||
"""Returns the display name of this charset."""
|
||||
return self._name
|
||||
|
||||
def aliases(self) -> _Set[str]:
|
||||
"""Returns a set containing this charset's aliases."""
|
||||
return set(self._aliases)
|
||||
|
||||
def isRegistered(self) -> bool:
|
||||
"""Returns True if this charset is registered in the IANA registry."""
|
||||
return self._registered
|
||||
|
||||
def canEncode(self) -> bool:
|
||||
"""Returns True if this charset supports encoding."""
|
||||
try:
|
||||
_codecs.lookup(self._name)
|
||||
return True
|
||||
except LookupError:
|
||||
return False
|
||||
|
||||
def encode(self, text: str) -> "ByteBuffer":
|
||||
"""
|
||||
Converts a string into bytes using this charset.
|
||||
Returns a ByteBuffer.
|
||||
"""
|
||||
encoded = text.encode(self._name, errors="replace")
|
||||
from ..nio import ByteBuffer
|
||||
buf = ByteBuffer.allocate(len(encoded))
|
||||
buf.put(list(encoded))
|
||||
buf.flip()
|
||||
return buf
|
||||
|
||||
def decode(self, buf: "ByteBuffer") -> "CharBuffer":
|
||||
"""
|
||||
Converts bytes from a ByteBuffer into a CharBuffer.
|
||||
"""
|
||||
arr = bytearray()
|
||||
for i in range(buf.position(), buf.limit()):
|
||||
arr.append(buf.get(i))
|
||||
decoded = arr.decode(self._name, errors="replace")
|
||||
from ..nio import CharBuffer
|
||||
cb = CharBuffer.allocate(len(decoded))
|
||||
cb.put(decoded)
|
||||
cb.flip()
|
||||
return cb
|
||||
|
||||
def newDecoder(self) -> "CharsetDecoder":
|
||||
"""Returns a new CharsetDecoder for this charset."""
|
||||
return CharsetDecoder(self)
|
||||
|
||||
def newEncoder(self) -> "CharsetEncoder":
|
||||
"""Returns a new CharsetEncoder for this charset."""
|
||||
return CharsetEncoder(self)
|
||||
|
||||
def toString(self) -> str:
|
||||
return self._name
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash(self._name) & 0x7FFFFFFF
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
if not isinstance(other, Charset):
|
||||
return False
|
||||
return self._name == other._name
|
||||
|
||||
def compareTo(self, other: "Charset") -> int:
|
||||
"""Compares this charset to another by canonical name."""
|
||||
if not isinstance(other, Charset):
|
||||
return -1
|
||||
if self._name < other._name:
|
||||
return -1
|
||||
elif self._name > other._name:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@classmethod
|
||||
def forName(cls, charset_name: str) -> "Charset":
|
||||
"""Returns a Charset for the given charset name."""
|
||||
if charset_name in cls._cache:
|
||||
return cls._cache[charset_name]
|
||||
|
||||
try:
|
||||
_codecs.lookup(charset_name)
|
||||
except LookupError:
|
||||
raise AndroidOnlyError(f"Charset not found: {charset_name}")
|
||||
|
||||
# Resolve aliases
|
||||
canonical = charset_name.lower()
|
||||
alias_map = {
|
||||
"ascii": "US-ASCII", "us-ascii": "US-ASCII",
|
||||
"iso-8859-1": "ISO-8859-1", "latin1": "ISO-8859-1",
|
||||
"utf-8": "UTF-8", "utf8": "UTF-8",
|
||||
"utf-16": "UTF-16", "utf16": "UTF-16",
|
||||
"utf-16be": "UTF-16BE", "utf16be": "UTF-16BE",
|
||||
"utf-16le": "UTF-16LE", "utf16le": "UTF-16LE",
|
||||
}
|
||||
canonical_name = alias_map.get(canonical, charset_name.upper())
|
||||
|
||||
charset = cls(canonical_name)
|
||||
cls._cache[charset_name] = charset
|
||||
return charset
|
||||
|
||||
@classmethod
|
||||
def forNameUEE(cls, charset_name: str) -> "Charset":
|
||||
"""Same as forName but wraps exception."""
|
||||
try:
|
||||
return cls.forName(charset_name)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def isSupported(cls, charset_name: str) -> bool:
|
||||
"""Returns True if the named charset is supported."""
|
||||
try:
|
||||
_codecs.lookup(charset_name)
|
||||
return True
|
||||
except LookupError:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def defaultCharset(cls) -> "Charset":
|
||||
"""Returns the default charset of the JVM (platform native encoding)."""
|
||||
import locale
|
||||
enc = locale.getpreferredencoding()
|
||||
return cls.forName(enc)
|
||||
|
||||
@classmethod
|
||||
def availableCharsets(cls) -> dict:
|
||||
"""Returns a sorted map of available charset names to Charset objects."""
|
||||
result = {}
|
||||
for name in _codecs.available_encodings():
|
||||
try:
|
||||
result[name] = cls.forName(name)
|
||||
except Exception:
|
||||
pass
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def requiredCharsets(cls) -> _Set[str]:
|
||||
"""Returns the set of required charset names per Java spec."""
|
||||
return {
|
||||
"US-ASCII", "ISO-8859-1", "UTF-8", "UTF-16",
|
||||
"UTF-16BE", "UTF-16LE",
|
||||
}
|
||||
|
||||
|
||||
# Initialize standard charset constants
|
||||
Charset.US_ASCII = Charset("US-ASCII", ["ASCII", "US-ASCII", "ascii", "cp367"])
|
||||
Charset.ISO_8859_1 = Charset("ISO-8859-1", ["ISO-8859-1", "latin1", "LATIN-1", "l1", "cp819"])
|
||||
Charset.UTF_8 = Charset("UTF-8", ["UTF-8", "utf8", "UTF8"])
|
||||
Charset.UTF_16 = Charset("UTF-16", ["UTF-16", "utf16", "UTF16", "UnicodeBig"])
|
||||
Charset.UTF_16BE = Charset("UTF-16BE", ["UTF-16BE", "utf16be", "UTF16BE", "ISO-10646-UCS-2"])
|
||||
Charset.UTF_16LE = Charset("UTF-16LE", ["UTF-16LE", "utf16le", "UTF16LE"])
|
||||
|
||||
|
||||
# ============================================================
|
||||
# CharsetEncoder
|
||||
# ============================================================
|
||||
|
||||
class CharsetEncoder(Stub):
|
||||
"""
|
||||
java.nio.charset.CharsetEncoder
|
||||
Converts character data to byte data using a Charset.
|
||||
"""
|
||||
|
||||
def __init__(self, charset: Charset, average_bytes_per_char: float = 1.0,
|
||||
max_bytes_per_char: float = 4.0, replacement: bytes = b'?'):
|
||||
super().__init__()
|
||||
self._charset = charset
|
||||
self._average_bytes_per_char = average_bytes_per_char
|
||||
self._max_bytes_per_char = max_bytes_per_char
|
||||
self._replacement = replacement
|
||||
self._malformed_input_action = CodingErrorAction.REPORT
|
||||
self._unmappable_action = CodingErrorAction.REPORT
|
||||
|
||||
def charset(self) -> Charset:
|
||||
"""Returns the charset that created this encoder."""
|
||||
return self._charset
|
||||
|
||||
def replacement(self) -> bytes:
|
||||
"""Returns the replacement value."""
|
||||
return self._replacement
|
||||
|
||||
def replaceWith(self, new_replacement: bytes) -> "CharsetEncoder":
|
||||
"""Sets a new replacement value."""
|
||||
self._replacement = new_replacement
|
||||
return self
|
||||
|
||||
def encode(self, input_str: str) -> "ByteBuffer":
|
||||
"""Encodes a string into bytes."""
|
||||
encoded = input_str.encode(self._charset.name(), errors="replace")
|
||||
from ..nio import ByteBuffer
|
||||
buf = ByteBuffer.allocate(len(encoded))
|
||||
buf.put(list(encoded))
|
||||
buf.flip()
|
||||
return buf
|
||||
|
||||
def encode(self, input: "CharBuffer", output: "ByteBuffer", end_of_input: bool) -> CoderResult:
|
||||
"""Encodes as much as possible from input to output."""
|
||||
in_str = ""
|
||||
for i in range(input.position(), input.limit()):
|
||||
in_str += chr(input.get(i))
|
||||
try:
|
||||
encoded = in_str.encode(self._charset.name())
|
||||
from ..nio import ByteBuffer
|
||||
out_arr = bytearray()
|
||||
for i in range(output.position(), output.limit()):
|
||||
if i < len(encoded):
|
||||
out_arr.append(encoded[i])
|
||||
return CoderResult.UNDERFLOW
|
||||
except UnicodeEncodeError:
|
||||
return CoderResult.unmappableForLength(1)
|
||||
|
||||
def encodeLoop(self, input: "CharBuffer", output: "ByteBuffer") -> CoderResult:
|
||||
"""The encoding loop (subclass hook)."""
|
||||
return self.encode(input, output, True)
|
||||
|
||||
def implReplaceWith(self, new_replacement: bytes):
|
||||
"""Hook for subclasses to react to replacement changes."""
|
||||
pass
|
||||
|
||||
def implOnMalformedInput(self, new_action: CodingErrorAction):
|
||||
"""Hook for subclasses to react to malformed input action changes."""
|
||||
pass
|
||||
|
||||
def implOnUnmappableCharacter(self, new_action: CodingErrorAction):
|
||||
"""Hook for subclasses to react to unmappable char action changes."""
|
||||
pass
|
||||
|
||||
def implReset(self):
|
||||
"""Hook for subclasses to reset internal state."""
|
||||
pass
|
||||
|
||||
def averageBytesPerChar(self) -> float:
|
||||
return self._average_bytes_per_char
|
||||
|
||||
def maxBytesPerChar(self) -> float:
|
||||
return self._max_bytes_per_char
|
||||
|
||||
def isLegalReplacement(self, repl: bytes) -> bool:
|
||||
"""Returns True if the replacement is a legal byte sequence."""
|
||||
return len(repl) > 0
|
||||
|
||||
def malformedInputAction(self) -> CodingErrorAction:
|
||||
return self._malformed_input_action
|
||||
|
||||
def unmappableCharacterAction(self) -> CodingErrorAction:
|
||||
return self._unmappable_action
|
||||
|
||||
def onMalformedInput(self, action: CodingErrorAction) -> "CharsetEncoder":
|
||||
self._malformed_input_action = action
|
||||
return self
|
||||
|
||||
def onUnmappableCharacter(self, action: CodingErrorAction) -> "CharsetEncoder":
|
||||
self._unmappable_action = action
|
||||
return self
|
||||
|
||||
def reset(self) -> "CharsetEncoder":
|
||||
"""Resets this encoder, clearing any internal state."""
|
||||
self.implReset()
|
||||
return self
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"CharsetEncoder@{hex(id(self))}[charset={self._charset.name()}]"
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
if not isinstance(other, CharsetEncoder):
|
||||
return False
|
||||
return self._charset == other._charset
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash(self._charset.name()) & 0x7FFFFFFF
|
||||
|
||||
|
||||
# ============================================================
|
||||
# CharsetDecoder
|
||||
# ============================================================
|
||||
|
||||
class CharsetDecoder(Stub):
|
||||
"""
|
||||
java.nio.charset.CharsetDecoder
|
||||
Converts byte data to character data using a Charset.
|
||||
"""
|
||||
|
||||
def __init__(self, charset: Charset, average_chars_per_byte: float = 1.0,
|
||||
max_chars_per_byte: float = 2.0, replacement: str = '\ufffd'):
|
||||
super().__init__()
|
||||
self._charset = charset
|
||||
self._average_chars_per_byte = average_chars_per_byte
|
||||
self._max_chars_per_byte = max_chars_per_byte
|
||||
self._replacement = replacement
|
||||
self._malformed_input_action = CodingErrorAction.REPORT
|
||||
self._unmappable_action = CodingErrorAction.REPORT
|
||||
self._auto_detect = False
|
||||
self._detected_charset = None
|
||||
|
||||
def charset(self) -> Charset:
|
||||
"""Returns the charset that created this decoder."""
|
||||
return self._charset
|
||||
|
||||
def replacement(self) -> str:
|
||||
"""Returns the replacement value."""
|
||||
return self._replacement
|
||||
|
||||
def replaceWith(self, new_replacement: str) -> "CharsetDecoder":
|
||||
"""Sets a new replacement value."""
|
||||
self._replacement = new_replacement
|
||||
return self
|
||||
|
||||
def decode(self, buf: "ByteBuffer") -> "CharBuffer":
|
||||
"""Decodes bytes from a ByteBuffer into a CharBuffer."""
|
||||
arr = bytearray()
|
||||
for i in range(buf.position(), buf.limit()):
|
||||
arr.append(buf.get(i))
|
||||
decoded = arr.decode(self._charset.name(), errors="replace")
|
||||
from ..nio import CharBuffer
|
||||
cb = CharBuffer.allocate(len(decoded))
|
||||
cb.put(decoded)
|
||||
cb.flip()
|
||||
return cb
|
||||
|
||||
def decode(self, input: "ByteBuffer", output: "CharBuffer", end_of_input: bool) -> CoderResult:
|
||||
"""Decodes as much as possible from input to output."""
|
||||
arr = bytearray()
|
||||
for i in range(input.position(), input.limit()):
|
||||
arr.append(input.get(i))
|
||||
try:
|
||||
decoded = arr.decode(self._charset.name())
|
||||
return CoderResult.UNDERFLOW
|
||||
except UnicodeDecodeError:
|
||||
return CoderResult.malformedForLength(1)
|
||||
|
||||
def decodeLoop(self, input: "ByteBuffer", output: "CharBuffer") -> CoderResult:
|
||||
"""The decoding loop (subclass hook)."""
|
||||
return self.decode(input, output, True)
|
||||
|
||||
def implReplaceWith(self, new_replacement: str):
|
||||
"""Hook for subclasses."""
|
||||
pass
|
||||
|
||||
def implOnMalformedInput(self, new_action: CodingErrorAction):
|
||||
"""Hook for subclasses."""
|
||||
pass
|
||||
|
||||
def implOnUnmappableCharacter(self, new_action: CodingErrorAction):
|
||||
"""Hook for subclasses."""
|
||||
pass
|
||||
|
||||
def implReset(self):
|
||||
"""Hook for subclasses."""
|
||||
pass
|
||||
|
||||
def averageCharsPerByte(self) -> float:
|
||||
return self._average_chars_per_byte
|
||||
|
||||
def maxCharsPerByte(self) -> float:
|
||||
return self._max_chars_per_byte
|
||||
|
||||
def isCharsetDetected(self) -> bool:
|
||||
return self._detected_charset is not None
|
||||
|
||||
def isAutoDetect(self) -> bool:
|
||||
return self._auto_detect
|
||||
|
||||
def detectedCharset(self) -> Charset:
|
||||
if self._detected_charset is None:
|
||||
raise AndroidOnlyError("No charset detected")
|
||||
return self._detected_charset
|
||||
|
||||
def malformedInputAction(self) -> CodingErrorAction:
|
||||
return self._malformed_input_action
|
||||
|
||||
def unmappableCharacterAction(self) -> CodingErrorAction:
|
||||
return self._unmappable_action
|
||||
|
||||
def onMalformedInput(self, action: CodingErrorAction) -> "CharsetDecoder":
|
||||
self._malformed_input_action = action
|
||||
return self
|
||||
|
||||
def onUnmappableCharacter(self, action: CodingErrorAction) -> "CharsetDecoder":
|
||||
self._unmappable_action = action
|
||||
return self
|
||||
|
||||
def reset(self) -> "CharsetDecoder":
|
||||
self.implReset()
|
||||
return self
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"CharsetDecoder@{hex(id(self))}[charset={self._charset.name()}]"
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
if not isinstance(other, CharsetDecoder):
|
||||
return False
|
||||
return self._charset == other._charset
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash(self._charset.name()) & 0x7FFFFFFF
|
||||
|
||||
|
||||
# ============================================================
|
||||
# StandardCharsets
|
||||
# ============================================================
|
||||
|
||||
class StandardCharsets(Stub):
|
||||
"""
|
||||
java.nio.charset.StandardCharsets
|
||||
Constant definitions for the standard charsets.
|
||||
"""
|
||||
US_ASCII: Charset = Charset.US_ASCII
|
||||
ISO_8859_1: Charset = Charset.ISO_8859_1
|
||||
UTF_8: Charset = Charset.UTF_8
|
||||
UTF_16: Charset = Charset.UTF_16
|
||||
UTF_16BE: Charset = Charset.UTF_16BE
|
||||
UTF_16LE: Charset = Charset.UTF_16LE
|
||||
Reference in new issue
Block a user