Files
Android-pyApi/android_pyapi/org/json.py
T
shuiyu1123 fbb8263b13 feat: 第三轮深度完善 — SQLite/JSON/网络/媒体/文本 真实实现
SQLite真实数据库:
- SQLiteDatabase: execSQL/insert/insertOrThrow/replace/update/delete/query 用sqlite3
- 修复getVersion/setVersion用PRAGMA user_version
- 修复getMaximumSize/getPageSize/setMaximumSize/setPageSize用PRAGMA
- SQLiteStatement: execute/simpleQueryForLong/simpleQueryForString/execQuery
- SQLiteOpenHelper: onCreate/onUpgrade/onDowngrade回调正确触发
- 修复SQLiteCursor.moveToPosition越界处理
- 修复ContentValues值对提取bug

JSON真实实现:
- JSONObject: isNull/append/putOnce/putOpt/getNames
- JSONArray: 完整put/get/opt/length/toString

网络真实实现:
- NetworkInterface: getByName/getNetworkInterfaces/getHardwareAddress 用/sys/class/net+fcntl.ioctl
- InterfaceAddress: 新增类
- ConnectivityManager: getActiveNetwork/getAllNetworks 用LinuxNetwork
- WifiManager: getScanResults用nmcli, setWifiEnabled用nmcli/rfkill
- BluetoothAdapter: getAddress/getName 用bluetoothctl

媒体真实实现:
- MediaPlayer: prepare检查文件, getCurrentPosition实时计算, getDuration/getVideoWidth用ffprobe
- MediaRecorder: setVideoSize/setVideoFrameRate/setVideoEncodingBitRate配置存储
- MediaMetadataRetriever: extractMetadata用ffprobe, getFrameAtTime用ffmpeg, getEmbeddedPicture用ffmpeg

文本真实实现:
- TextUtils: split用re.split, concat/indexOf/lastIndexOf/urlEncode/urlDecode
- SpannableString: setSpan/getSpans/getSpanFlags/nextSpanTransition 真实实现
- SpannableStringBuilder: 修复append重载bug

Provider增强:
- Settings: putBoolean/getBoolean
- MediaStore: getContentUri/VOLUME常量
- ContactsContract: 补全常量和CommonDataKinds

Util增强:
- Log: w/e/wtf支持Throwable参数, 修复wtf重复定义bug
- TypedValue: 修复complexToDimension/complexToFloat/getFloat实现

修复:
- __init__.py: 补全NetworkInterface/InetAddress/MediaMetadataRetriever/SpannableStringBuilder导出

统计: 221模块, 3666类, 31005方法, 183529行
2026-06-25 00:40:59 +00:00

910 lines
27 KiB
Python

"""
Java JSON standard library APIs implemented in Python.
org.json package - JSONObject, JSONArray, JSONTokener, JSONStringer, JSONWriter, etc.
"""
from .._core import Stub
import json as _json
__all__ = [
"JSONObject", "JSONArray", "JSONTokener",
"JSONStringer", "JSONWriter", "JSONException", "JSONPointer",
"JSONPointerBuilder",
]
# ============================================================
# JSONException
# ============================================================
class JSONException(Exception):
def __init__(self, *args):
if len(args) == 1 and isinstance(args[0], Exception):
super().__init__(str(args[0]))
self._cause = args[0]
else:
super().__init__(*args)
self._cause = None
def getCause(self):
return self._cause
# ============================================================
# JSONObject.NULL
# ============================================================
class _JSONNull(Stub):
def __init__(self):
super().__init__()
def equals(self, other):
return other is None or isinstance(other, _JSONNull)
def hashCode(self):
return 0
def toString(self):
return "null"
# ============================================================
# JSONObject
# ============================================================
class JSONObject(Stub):
NULL = _JSONNull()
def __init__(self, *args):
super().__init__()
self._map = {}
if len(args) == 1:
arg = args[0]
if isinstance(arg, str):
tokener = JSONTokener(arg)
obj = tokener.nextValue()
if isinstance(obj, JSONObject):
self._map = obj._map
else:
raise JSONException("String is not a JSONObject")
elif isinstance(arg, dict):
for k, v in arg.items():
self._map[str(k)] = JSONObject._wrap(v)
elif isinstance(arg, JSONObject):
names = None
self._map = dict(arg._map)
def _wrap(val):
if val is None:
return JSONObject.NULL
if isinstance(val, (bool, int, float)):
return val
if isinstance(val, str):
return val
if isinstance(val, (list, tuple)):
arr = JSONArray()
for item in val:
arr.put(JSONObject._wrap(item))
return arr
if isinstance(val, dict):
obj = JSONObject()
for k, v in val.items():
obj.put(str(k), JSONObject._wrap(v))
return obj
if isinstance(val, JSONObject) or isinstance(val, JSONArray):
return val
return val
def put(self, key, value):
self._map[str(key)] = JSONObject._wrap(value)
return self
def accumulate(self, key, value):
k = str(key)
current = self._map.get(k)
if current is None:
arr = JSONArray()
arr.put(value)
self._map[k] = arr
elif isinstance(current, JSONArray):
current.put(value)
else:
arr = JSONArray()
arr.put(current)
arr.put(value)
self._map[k] = arr
return self
def append(self, key, value):
"""Append value to the JSONArray under key.
If the key is not present a new JSONArray containing value is created.
If the key maps to a JSONArray the value is appended to it.
Otherwise the existing value and the new value are placed into a new
JSONArray.
"""
k = str(key)
current = self._map.get(k)
if isinstance(current, JSONArray):
current.put(value)
else:
arr = JSONArray()
if current is not None and current is not JSONObject.NULL:
arr.put(current)
arr.put(value)
self._map[k] = arr
return self
def putOnce(self, key, value):
"""Put a key/value pair only if the key is not already present."""
if key is None:
raise JSONException("Null key.")
k = str(key)
if k not in self._map:
self._map[k] = JSONObject._wrap(value)
return self
def putOpt(self, key, value):
"""Put a key/value pair, but only if key and value are both non-null."""
if key is not None and value is not None:
return self.put(key, value)
return self
def get(self, key):
k = str(key)
if k not in self._map:
raise JSONException(f"JSONObject[\"{k}\"] not found")
val = self._map[k]
if val is JSONObject.NULL:
raise JSONException(f"JSONObject[\"{k}\"] is null")
return val
def opt(self, key, default=None):
k = str(key)
val = self._map.get(k)
if val is None or val is JSONObject.NULL:
return default
return val
def getString(self, key):
val = self.get(key)
if isinstance(val, str):
return val
raise JSONException(f"JSONObject[\"{key}\"] is not a string")
def getInt(self, key):
val = self.get(key)
if isinstance(val, int):
return val
if isinstance(val, float):
return int(val)
raise JSONException(f"JSONObject[\"{key}\"] is not an int")
def getLong(self, key):
val = self.get(key)
if isinstance(val, int):
return val
if isinstance(val, float):
return int(val)
raise JSONException(f"JSONObject[\"{key}\"] is not a long")
def getDouble(self, key):
val = self.get(key)
if isinstance(val, (int, float)):
return float(val)
raise JSONException(f"JSONObject[\"{key}\"] is not a double")
def getBoolean(self, key):
val = self.get(key)
if isinstance(val, bool):
return val
if val == "true":
return True
if val == "false":
return False
raise JSONException(f"JSONObject[\"{key}\"] is not a boolean")
def getJSONArray(self, key):
val = self.get(key)
if isinstance(val, JSONArray):
return val
raise JSONException(f"JSONObject[\"{key}\"] is not a JSONArray")
def getJSONObject(self, key):
val = self.get(key)
if isinstance(val, JSONObject):
return val
raise JSONException(f"JSONObject[\"{key}\"] is not a JSONObject")
def optString(self, key, default=""):
val = self.opt(key)
if val is None or val is JSONObject.NULL:
return default
return str(val)
def optInt(self, key, default=0):
val = self.opt(key)
if val is None or val is JSONObject.NULL:
return default
if isinstance(val, int):
return val
if isinstance(val, float):
return int(val)
try:
return int(val)
except (ValueError, TypeError):
return default
def optLong(self, key, default=0):
return self.optInt(key, default)
def optDouble(self, key, default=0.0):
val = self.opt(key)
if val is None or val is JSONObject.NULL:
return default
if isinstance(val, (int, float)):
return float(val)
try:
return float(val)
except (ValueError, TypeError):
return default
def optBoolean(self, key, default=False):
val = self.opt(key)
if val is None or val is JSONObject.NULL:
return default
if isinstance(val, bool):
return val
if isinstance(val, str):
return val.lower() == "true"
return default
def optJSONArray(self, key):
val = self.opt(key)
if isinstance(val, JSONArray):
return val
return None
def optJSONObject(self, key):
val = self.opt(key)
if isinstance(val, JSONObject):
return val
return None
def has(self, key):
return str(key) in self._map
def isNull(self, key):
"""Returns true if this object has no mapping for key or if it has a
mapping whose value is JSONObject.NULL."""
k = str(key)
if k not in self._map:
return True
return self._map[k] is JSONObject.NULL
def remove(self, key):
k = str(key)
if k in self._map:
del self._map[k]
def keys(self):
return iter(self._map.keys())
def names(self):
if not self._map:
return None
arr = JSONArray()
for k in self._map:
arr.put(k)
return arr
@staticmethod
def getNames(jsonObject):
"""Returns an array of field names, or None if the object is None/empty."""
if jsonObject is None:
return None
if not jsonObject._map:
return None
return [str(k) for k in jsonObject._map.keys()]
def length(self):
return len(self._map)
def toString(self, indent_factor=None):
if indent_factor is None:
return self._to_json_string()
return self._to_json_pretty(indent_factor)
def _to_json_string(self):
parts = ["{"]
for i, (k, v) in enumerate(self._map.items()):
parts.append('"' + k + '": ' + JSONObject._value_to_string(v))
if i < len(self._map) - 1:
parts.append(", ")
parts.append("}")
return "".join(parts)
def _to_json_pretty(self, indent):
parts = ["{"]
for i, (k, v) in enumerate(self._map.items()):
parts.append("\n" + " " * indent + '"' + k + '": ' + JSONObject._value_to_string(v))
if i < len(self._map) - 1:
parts.append(",")
parts.append("\n}")
return "".join(parts)
def _value_to_string(val):
if val is None or val is JSONObject.NULL:
return "null"
if isinstance(val, bool):
return "true" if val else "false"
if isinstance(val, (int, float)):
return str(val)
if isinstance(val, str):
return _json.dumps(val)
if isinstance(val, JSONObject):
return val._to_json_string()
if isinstance(val, JSONArray):
return val._to_json_string()
return str(val)
def toMap(self):
result = {}
for k, v in self._map.items():
if isinstance(v, JSONObject):
result[k] = v.toMap()
elif isinstance(v, JSONArray):
result[k] = v.toList()
elif v is JSONObject.NULL:
result[k] = None
else:
result[k] = v
return result
def write(self, writer):
writer._write(self._to_json_string())
def toJSONArray(self, names):
if names is None or names.length() == 0:
return None
arr = JSONArray()
for i in range(names.length()):
arr.put(self.opt(names.getString(i)))
return arr
def hashCode(self):
return hash(frozenset(self._map.items()))
def equals(self, other):
if isinstance(other, JSONObject):
return self._map == other._map
return False
# ============================================================
# JSONArray
# ============================================================
class JSONArray(Stub):
def __init__(self, *args):
super().__init__()
self._list = []
if len(args) == 1:
arg = args[0]
if isinstance(arg, str):
tokener = JSONTokener(arg)
val = tokener.nextValue()
if isinstance(val, JSONArray):
self._list = val._list
else:
raise JSONException("String is not a JSONArray")
elif isinstance(arg, (list, tuple)):
for item in arg:
self.put(JSONObject._wrap(item))
def put(self, *args):
if len(args) == 1:
self._list.append(JSONObject._wrap(args[0]))
elif len(args) == 2:
index, value = args
while len(self._list) <= index:
self._list.append(None)
self._list[index] = JSONObject._wrap(value)
return self
def get(self, index):
if index < 0 or index >= len(self._list):
raise JSONException(f"JSONArray[{index}] not found")
val = self._list[index]
if val is JSONObject.NULL:
raise JSONException(f"JSONArray[{index}] is null")
return val
def getString(self, index):
val = self.get(index)
if isinstance(val, str):
return val
raise JSONException(f"JSONArray[{index}] is not a string")
def getInt(self, index):
val = self.get(index)
if isinstance(val, int):
return val
if isinstance(val, float):
return int(val)
raise JSONException(f"JSONArray[{index}] is not an int")
def getLong(self, index):
val = self.get(index)
if isinstance(val, int):
return val
if isinstance(val, float):
return int(val)
raise JSONException(f"JSONArray[{index}] is not a long")
def getDouble(self, index):
val = self.get(index)
if isinstance(val, (int, float)):
return float(val)
raise JSONException(f"JSONArray[{index}] is not a double")
def getBoolean(self, index):
val = self.get(index)
if isinstance(val, bool):
return val
if val == "true":
return True
if val == "false":
return False
raise JSONException(f"JSONArray[{index}] is not a boolean")
def getJSONArray(self, index):
val = self.get(index)
if isinstance(val, JSONArray):
return val
raise JSONException(f"JSONArray[{index}] is not a JSONArray")
def getJSONObject(self, index):
val = self.get(index)
if isinstance(val, JSONObject):
return val
raise JSONException(f"JSONArray[{index}] is not a JSONObject")
def opt(self, index, default=None):
if index < 0 or index >= len(self._list):
return default
val = self._list[index]
if val is JSONObject.NULL:
return default
return val
def optString(self, index, default=""):
val = self.opt(index)
if val is None:
return default
return str(val)
def optInt(self, index, default=0):
val = self.opt(index)
if val is None:
return default
if isinstance(val, int):
return val
if isinstance(val, float):
return int(val)
try:
return int(val)
except (ValueError, TypeError):
return default
def optLong(self, index, default=0):
return self.optInt(index, default)
def optDouble(self, index, default=0.0):
val = self.opt(index)
if val is None:
return default
if isinstance(val, (int, float)):
return float(val)
try:
return float(val)
except (ValueError, TypeError):
return default
def optBoolean(self, index, default=False):
val = self.opt(index)
if val is None:
return default
if isinstance(val, bool):
return val
if isinstance(val, str):
return val.lower() == "true"
return default
def optJSONArray(self, index):
val = self.opt(index)
if isinstance(val, JSONArray):
return val
return None
def optJSONObject(self, index):
val = self.opt(index)
if isinstance(val, JSONObject):
return val
return None
def remove(self, index):
if 0 <= index < len(self._list):
return self._list.pop(index)
return None
def length(self):
return len(self._list)
def isNull(self, index):
if 0 <= index < len(self._list):
return self._list[index] is JSONObject.NULL or self._list[index] is None
return True
def toString(self, indent_factor=None):
if indent_factor is None:
return self._to_json_string()
return self._to_json_pretty(indent_factor)
def _to_json_string(self):
parts = ["["]
for i, v in enumerate(self._list):
parts.append(JSONObject._value_to_string(v))
if i < len(self._list) - 1:
parts.append(", ")
parts.append("]")
return "".join(parts)
def _to_json_pretty(self, indent):
parts = ["["]
for i, v in enumerate(self._list):
parts.append("\n" + " " * indent + JSONObject._value_to_string(v))
if i < len(self._list) - 1:
parts.append(",")
parts.append("\n]")
return "".join(parts)
def toList(self):
result = []
for v in self._list:
if isinstance(v, JSONObject):
result.append(v.toMap())
elif isinstance(v, JSONArray):
result.append(v.toList())
elif v is JSONObject.NULL:
result.append(None)
else:
result.append(v)
return result
def join(self, separator):
parts = []
for v in self._list:
parts.append(JSONObject._value_to_string(v))
return separator.join(parts)
# ============================================================
# JSONTokener
# ============================================================
class JSONTokener(Stub):
def __init__(self, source):
super().__init__()
if hasattr(source, "read"):
self._source = source.read()
else:
self._source = str(source)
self._index = 0
def nextValue(self):
self._skipWhitespace()
if self._index >= len(self._source):
raise JSONException("Unexpected end of input")
ch = self._source[self._index]
if ch == "{":
return self._readObject()
if ch == "[":
return self._readArray()
if ch == '"':
return self._readString()
if ch == "'":
return self._readString("'")
if ch == "t" or ch == "f":
return self._readLiteral()
if ch == "n":
return self._readNull()
return self._readNumber()
def _skipWhitespace(self):
while self._index < len(self._source) and self._source[self._index] in " \t\n\r":
self._index += 1
def _readObject(self):
self._index += 1 # skip {
obj = JSONObject()
self._skipWhitespace()
if self._index < len(self._source) and self._source[self._index] == "}":
self._index += 1
return obj
while True:
self._skipWhitespace()
key = self.nextValue()
self._skipWhitespace()
if self._index < len(self._source) and self._source[self._index] == ":":
self._index += 1
self._skipWhitespace()
val = self.nextValue()
obj.put(str(key), val)
self._skipWhitespace()
if self._index < len(self._source) and self._source[self._index] == ",":
self._index += 1
elif self._index < len(self._source) and self._source[self._index] == "}":
self._index += 1
return obj
else:
raise JSONException("Expected ',' or '}' in object")
def _readArray(self):
self._index += 1 # skip [
arr = JSONArray()
self._skipWhitespace()
if self._index < len(self._source) and self._source[self._index] == "]":
self._index += 1
return arr
while True:
self._skipWhitespace()
val = self.nextValue()
arr.put(val)
self._skipWhitespace()
if self._index < len(self._source) and self._source[self._index] == ",":
self._index += 1
elif self._index < len(self._source) and self._source[self._index] == "]":
self._index += 1
return arr
else:
raise JSONException("Expected ',' or ']' in array")
def _readString(self, quote='"'):
self._index += 1 # skip quote
result = []
while self._index < len(self._source):
ch = self._source[self._index]
if ch == "\\":
self._index += 1
if self._index >= len(self._source):
raise JSONException("Unterminated string escape")
esc = self._source[self._index]
if esc == '"':
result.append('"')
elif esc == "\\":
result.append("\\")
elif esc == "/":
result.append("/")
elif esc == "b":
result.append("\b")
elif esc == "f":
result.append("\f")
elif esc == "n":
result.append("\n")
elif esc == "r":
result.append("\r")
elif esc == "t":
result.append("\t")
elif esc == "u":
hex_str = self._source[self._index+1:self._index+5]
result.append(chr(int(hex_str, 16)))
self._index += 4
else:
result.append(esc)
self._index += 1
elif ch == quote:
self._index += 1
return "".join(result)
else:
result.append(ch)
self._index += 1
raise JSONException("Unterminated string")
def _readLiteral(self):
for lit in ("true", "false"):
if self._source[self._index:self._index+len(lit)] == lit:
self._index += len(lit)
return lit == "true"
raise JSONException(f"Unexpected literal at {self._index}")
def _readNull(self):
if self._source[self._index:self._index+4] == "null":
self._index += 4
return JSONObject.NULL
raise JSONException(f"Unexpected token at {self._index}")
def _readNumber(self):
start = self._index
while self._index < len(self._source) and self._source[self._index] in "-+0123456789.eE":
self._index += 1
num_str = self._source[start:self._index]
if "." in num_str or "e" in num_str or "E" in num_str:
return float(num_str)
return int(num_str)
def nextString(self, quote='"'):
return self._readString(quote)
def nextChar(self, c):
self._skipWhitespace()
if self._index < len(self._source) and self._source[self._index] == c:
self._index += 1
return c
raise JSONException(f"Expected '{c}'")
def nextTo(self, delimiter):
start = self._index
while self._index < len(self._source) and self._source[self._index] not in delimiter:
self._index += 1
return self._source[start:self._index]
def skipPast(self, text):
idx = self._source.find(text, self._index)
if idx >= 0:
self._index = idx + len(text)
def skipTo(self, c):
idx = self._source.find(c, self._index)
if idx >= 0:
self._index = idx
return idx
return -1
def back(self):
self._index -= 1
def more(self):
self._skipWhitespace()
return self._index < len(self._source)
def readString(self):
return self._readString()
# ============================================================
# JSONWriter
# ============================================================
class JSONWriter(Stub):
def __init__(self, writer):
super().__init__()
self._writer = writer
self._stack = []
self._in_object = False
self._need_comma = False
def _write(self, s):
self._writer.write(s)
def array(self):
self._beforeValue()
self._stack.append(("array", False))
self._write("[")
return self
def endArray(self):
self._write("]")
self._stack.pop()
return self
def object(self):
self._beforeValue()
self._stack.append(("object", False))
self._write("{")
return self
def endObject(self):
self._write("}")
self._stack.pop()
return self
def key(self, s):
if not self._stack or self._stack[-1][0] != "object":
raise JSONException("Can't set key outside object")
self._beforeKey()
self._write('"' + s + '":')
return self
def value(self, v):
self._beforeValue()
self._write(JSONObject._value_to_string(v))
return self
def _beforeValue(self):
if self._stack and self._stack[-1][0] == "object":
raise JSONException("Expected key in object")
def _beforeKey(self):
if self._stack and self._stack[-1][1]:
self._write(",")
self._stack[-1] = (self._stack[-1][0], True)
# ============================================================
# JSONStringer
# ============================================================
class JSONStringer(JSONWriter):
def __init__(self):
from io import StringIO
super().__init__(StringIO())
def toString(self):
return self._writer.getvalue()
# ============================================================
# JSONPointer
# ============================================================
class JSONPointer(Stub):
def __init__(self, pointer):
super().__init__()
if not pointer or pointer == "":
self._tokens = []
elif pointer.startswith("#"):
pointer = pointer[1:]
pointer = pointer.replace("~1", "/").replace("~0", "~")
import urllib.parse
pointer = urllib.parse.unquote(pointer)
self._tokens = pointer.split("/")[1:] if len(pointer) > 1 else []
else:
self._tokens = pointer.split("/")[1:] if len(pointer) > 0 else []
def query(self, root):
current = root
for token in self._tokens:
token = token.replace("~1", "/").replace("~0", "~")
if isinstance(current, JSONObject):
current = current.get(token)
elif isinstance(current, JSONArray):
try:
idx = int(token)
current = current.get(idx)
except (ValueError, IndexError):
raise JSONException(f"Invalid index: {token}")
else:
raise JSONException(f"Cannot index into {type(current)}")
return current
def queryFrom(self, root):
return self.query(root)
def toString(self):
return "#/" + "/".join(t.replace("~", "~0").replace("/", "~1") for t in self._tokens)
def hashCode(self):
return hash(tuple(self._tokens))
def equals(self, other):
if isinstance(other, JSONPointer):
return self._tokens == other._tokens
return False
# ============================================================
# JSONPointerBuilder
# ============================================================
class JSONPointerBuilder(Stub):
def __init__(self):
super().__init__()
self._tokens = []
def append(self, token):
self._tokens.append(str(token))
return self
def build(self):
return JSONPointer("#/" + "/".join(t.replace("~", "~0").replace("/", "~1") for t in self._tokens))