1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-07-17 02:44:04 +02:00

Improve JSON stringification for Bangle.js - much more compact, and now handles non-ASCII chars correctly

This commit is contained in:
Gordon Williams 2022-05-23 15:38:06 +01:00
parent 9dbdb3da93
commit 5211540e03

View File

@ -231,9 +231,8 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport {
/// Write a string of data, and chunk it up /// Write a string of data, and chunk it up
private void uartTx(TransactionBuilder builder, String str) { private void uartTx(TransactionBuilder builder, String str) {
byte[] bytes = str.getBytes(StandardCharsets.ISO_8859_1);
LOG.info("UART TX: " + str); LOG.info("UART TX: " + str);
byte[] bytes;
bytes = str.getBytes(StandardCharsets.ISO_8859_1);
// FIXME: somehow this is still giving us UTF8 data when we put images in strings. Maybe JSON.stringify is converting to UTF-8? // FIXME: somehow this is still giving us UTF8 data when we put images in strings. Maybe JSON.stringify is converting to UTF-8?
for (int i=0;i<bytes.length;i+=mtuSize) { for (int i=0;i<bytes.length;i+=mtuSize) {
int l = bytes.length-i; int l = bytes.length-i;
@ -244,26 +243,70 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport {
} }
} }
/// Converts an object to a JSON string. see jsonToString
/// Write a string of data, and chunk it up private String jsonToStringInternal(Object v) {
public String jsonToString(JSONObject jsonObj) { if (v instanceof String) {
String json = jsonObj.toString(); /* Convert a string, escaping chars we can't send over out UART connection */
// toString creates '\u0000' instead of '\0' String s = (String)v;
// FIXME: there have got to be nicer ways of handling this - maybe we just make our own JSON.toString (see below) String json = "\"";
json = json.replaceAll("\\\\u000([01234567])", "\\\\$1"); for (int i=0;i<s.length();i++) {
json = json.replaceAll("\\\\u00([0123456789abcdef][0123456789abcdef])", "\\\\x$1"); int ch = (int)s.charAt(i);
return json; if (ch<8) json += "\\"+ch;
/*String json = "{"; else if (ch==8) json += "\\b";
Iterator<String> iter = jsonObj.keys(); else if (ch==9) json += "\\t";
while (iter.hasNext()) { else if (ch==10) json += "\\n";
String key = iter.next(); else if (ch==11) json += "\\v";
Object v = jsonObj.get(key); else if (ch==12) json += "\\f";
if (v instanceof Integer) { else if (ch==34) json += "\\\""; // quote
// ... else if (ch==92) json += "\\\\"; // slash
} else // .. else if (ch<32 || ch==26 || ch==27 || ch==127 || ch==173) json += "\\x"+Integer.toHexString((ch&255)|256).substring(1);
if (iter.hasNext()) json+=","; else json += s.charAt(i);
}
json += "\"";
} else if (v instanceof JSONArray) {
JSONArray a = (JSONArray)v;
String json = "[";
for (int i=0;i<a.length();i++) {
if (i>0) json += ",";
Object o = null;
try {
o = a.get(i);
} catch (JSONException e) {
LOG.warn("jsonToString array error: " + e.getLocalizedMessage());
}
json += jsonToStringInternal(o));
}
return json+"]";
} else if (v instanceof JSONObject) {
JSONObject obj = (JSONObject)v;
String json = "{";
Iterator<String> iter = obj.keys();
while (iter.hasNext()) {
String key = iter.next();
Object o = null;
try {
o = obj.get(key);
} catch (JSONException e) {
LOG.warn("jsonToString object error: " + e.getLocalizedMessage());
}
json += key+":"+jsonToStringInternal(o);
if (iter.hasNext()) json+=",";
}
return json+"}";
} else { // int/double/null
return v.toString();
} }
return json+"}";*/ }
/// Convert a JSON object to a JSON String (NOT 100% JSON compliant)
public String jsonToString(JSONObject jsonObj) {
/* jsonObj.toString() works but breaks char codes>128 (encodes as UTF8?) and also uses
\u0000 when just \0 would do (and so on).
So we do it manually, which can be more compact anyway.
This is JSON-ish, so not exactly as per JSON1 spec but good enough for Espruino.
*/
return jsonToStringInternal(jsonObj);
} }
/// Write a JSON object of data /// Write a JSON object of data
@ -291,10 +334,10 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport {
private void handleUartRxLine(String line) { private void handleUartRxLine(String line) {
LOG.info("UART RX LINE: " + line); LOG.info("UART RX LINE: " + line);
if (line.length()==0) return;
if (">Uncaught ReferenceError: \"GB\" is not defined".equals(line)) if (">Uncaught ReferenceError: \"GB\" is not defined".equals(line))
GB.toast(getContext(), "Gadgetbridge plugin not installed on Bangle.js", Toast.LENGTH_LONG, GB.ERROR); GB.toast(getContext(), "Gadgetbridge plugin not installed on Bangle.js", Toast.LENGTH_LONG, GB.ERROR);
else if (line.length() > 0 && line.charAt(0)=='{') { else if (line.charAt(0)=='{') {
// JSON - we hope! // JSON - we hope!
try { try {
JSONObject json = new JSONObject(line); JSONObject json = new JSONObject(line);