Import miniabs 1.0 source

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
xockoandClaude Opus 5.5 committed 2026-10-14 19:26:04 +02:00
commit 4fe9eed870
78 files changed
+5800

No files matched your search

+252
View File
@@ -0,0 +1,252 @@
package com.miniabs;
import java.io.IOException;
import java.io.Reader;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Small streaming JSON parser that builds org.json objects straight from the
* socket. Very long strings (episode show notes) are cut short and bulky keys
* are dropped while reading, so a podcast with hundreds of episodes still fits
* in the Galaxy Mini's small heap.
*/
final class Json {
/** Keys never kept, at any depth. */
private static final String[] ALWAYS_SKIP = {"chapters", "libraryFiles", "metaTags", "rssFeed"};
private final Reader in;
private final char[] buf = new char[8192];
private int pos, len;
private final int maxString;
private final String[] deepSkip;
private int depth;
private Json(Reader in, int maxString, String[] deepSkip) {
this.in = in;
this.maxString = maxString;
this.deepSkip = deepSkip;
}
static Object parse(Reader r) throws IOException {
return parse(r, 2000, null);
}
/**
* @param maxString longest string kept (longer ones end with an ellipsis)
* @param deepSkip keys dropped inside objects nested three or more levels deep
*/
static Object parse(Reader r, int maxString, String[] deepSkip) throws IOException {
Json j = new Json(r, maxString, deepSkip);
int c = j.skipWs();
if (c == -1) return null;
return j.value(c);
}
private int read() throws IOException {
if (pos >= len) {
len = in.read(buf, 0, buf.length);
pos = 0;
if (len <= 0) {
len = 0;
return -1;
}
}
return buf[pos++];
}
private void unread() {
pos--;
}
private int skipWs() throws IOException {
int c;
do {
c = read();
} while (c == ' ' || c == '\n' || c == '\r' || c == '\t');
return c;
}
private Object value(int c) throws IOException {
switch (c) {
case '{':
return object();
case '[':
return array();
case '"':
return string(maxString);
case 't':
expect("rue");
return Boolean.TRUE;
case 'f':
expect("alse");
return Boolean.FALSE;
case 'n':
expect("ull");
return JSONObject.NULL;
default:
if (c == '-' || (c >= '0' && c <= '9')) return number(c);
throw new IOException("Unexpected reply from server");
}
}
private void expect(String rest) throws IOException {
for (int i = 0; i < rest.length(); i++) {
if (read() != rest.charAt(i)) throw new IOException("Unexpected reply from server");
}
}
private Object number(int first) throws IOException {
StringBuilder sb = new StringBuilder(16);
sb.append((char) first);
boolean dbl = false;
int c;
while (true) {
c = read();
if ((c >= '0' && c <= '9') || c == '-' || c == '+') {
sb.append((char) c);
} else if (c == '.' || c == 'e' || c == 'E') {
dbl = true;
sb.append((char) c);
} else {
break;
}
}
if (c != -1) unread();
String s = sb.toString();
try {
if (!dbl) {
long l = Long.parseLong(s);
if (l >= Integer.MIN_VALUE && l <= Integer.MAX_VALUE) return Integer.valueOf((int) l);
return Long.valueOf(l);
}
return Double.valueOf(s);
} catch (NumberFormatException e) {
try {
return Double.valueOf(s);
} catch (NumberFormatException e2) {
return Integer.valueOf(0);
}
}
}
private boolean skipKey(String key) {
for (String k : ALWAYS_SKIP) if (k.equals(key)) return true;
if (deepSkip != null && depth >= 3) {
for (String k : deepSkip) if (k.equals(key)) return true;
}
return false;
}
private JSONObject object() throws IOException {
depth++;
JSONObject o = new JSONObject();
int c = skipWs();
if (c == '}') {
depth--;
return o;
}
while (true) {
if (c != '"') throw new IOException("Unexpected reply from server");
String key = string(512);
c = skipWs();
if (c != ':') throw new IOException("Unexpected reply from server");
c = skipWs();
if (skipKey(key)) {
skipValue(c);
} else {
Object v = value(c);
try {
o.put(key, v);
} catch (JSONException ignored) {
// NaN or similar; drop it
}
}
c = skipWs();
if (c == ',') {
c = skipWs();
continue;
}
if (c == '}') {
depth--;
return o;
}
throw new IOException("Unexpected reply from server");
}
}
private JSONArray array() throws IOException {
JSONArray a = new JSONArray();
int c = skipWs();
if (c == ']') return a;
while (true) {
a.put(value(c));
c = skipWs();
if (c == ',') {
c = skipWs();
continue;
}
if (c == ']') return a;
throw new IOException("Unexpected reply from server");
}
}
private void skipValue(int c) throws IOException {
if (c == '"') {
string(0);
return;
}
if (c == '{' || c == '[') {
int d = 1;
while (d > 0) {
int ch = read();
if (ch == -1) throw new IOException("Reply was cut off");
if (ch == '"') string(0);
else if (ch == '{' || ch == '[') d++;
else if (ch == '}' || ch == ']') d--;
}
return;
}
value(c);
}
private String string(int max) throws IOException {
StringBuilder sb = new StringBuilder(max > 0 ? Math.min(max, 32) : 0);
boolean cut = false;
while (true) {
int c = read();
if (c == -1) throw new IOException("Reply was cut off");
if (c == '"') break;
if (c == '\\') {
c = read();
switch (c) {
case 'n': c = '\n'; break;
case 't': c = '\t'; break;
case 'r': c = '\r'; break;
case 'b': c = '\b'; break;
case 'f': c = '\f'; break;
case 'u': {
int v = 0;
for (int i = 0; i < 4; i++) {
int d = Character.digit(read(), 16);
if (d < 0) throw new IOException("Unexpected reply from server");
v = v * 16 + d;
}
c = v;
break;
}
case -1:
throw new IOException("Reply was cut off");
default:
break; // \" \\ \/
}
}
if (sb.length() < max) sb.append((char) c);
else cut = true;
}
if (cut && max > 0) sb.append('…');
return sb.toString();
}
}