From d660d652eceefefd641c699c0e97334ce97e5ee5 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 10 Dec 2023 21:21:32 -0500 Subject: [PATCH] Fix two crash bugs (grmbl): * `null` deref in `EventDialog` with events without fulltext description. * Undo `StandardCharsets` change in places where it depends on API 33+ :-/ Android Studio used to explicitly warn about uses like that! :< --- .../java/net/gaast/giggity/EventDialog.java | 4 +-- .../main/java/net/gaast/giggity/Schedule.java | 12 ++++--- .../gaast/giggity/ScheduleViewActivity.java | 36 +++++++++++-------- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/net/gaast/giggity/EventDialog.java b/app/src/main/java/net/gaast/giggity/EventDialog.java index 5a964b69..1e4e3bbd 100644 --- a/app/src/main/java/net/gaast/giggity/EventDialog.java +++ b/app/src/main/java/net/gaast/giggity/EventDialog.java @@ -161,8 +161,8 @@ public EventDialog(Context ctx, Schedule.Item item, String searchQuery) { v.setVisibility(View.GONE); } - Spannable desc = new SpannableString(item.getDescriptionSpanned(ctx)); - if (searchQuery != null && !searchQuery.isEmpty()) { + Spannable desc = item.getDescriptionSpanned(ctx); + if (desc != null && searchQuery != null && !searchQuery.isEmpty()) { String raw = desc.toString().toLowerCase(); Matcher m = Pattern.compile("(\"([^\"]*)\"|'([^']*)'|(\\S+))").matcher(searchQuery.toLowerCase()); while (m.find()) { diff --git a/app/src/main/java/net/gaast/giggity/Schedule.java b/app/src/main/java/net/gaast/giggity/Schedule.java index 71dd3cbe..0f94b5da 100644 --- a/app/src/main/java/net/gaast/giggity/Schedule.java +++ b/app/src/main/java/net/gaast/giggity/Schedule.java @@ -20,6 +20,7 @@ package net.gaast.giggity; import android.content.Context; +import android.text.SpannableString; import android.text.Spanned; import android.util.Log; @@ -38,6 +39,7 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.Serializable; +import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; @@ -493,7 +495,7 @@ protected void addMetadata(String md_json) { JSONArray latlon = jroom.getJSONArray("latlon"); room.location = ("geo:0,0?q=" + latlon.optDouble(0, 0) + "," + latlon.optDouble(1, 0) + "(" + - URLEncoder.encode(name, StandardCharsets.UTF_8) + ")"); + URLEncoder.encode(name, "utf-8") + ")"); } } } @@ -504,6 +506,8 @@ protected void addMetadata(String md_json) { } catch (JSONException e) { e.printStackTrace(); return; + } catch (UnsupportedEncodingException e) { + // TODO: Once I'm on API 33+ I can use StandardCharsets.UTF_8 here again. } } @@ -1305,7 +1309,7 @@ public String getLanguage() { return language; } - public Spanned getDescriptionSpanned(Context ctx) { + public SpannableString getDescriptionSpanned(Context ctx) { if (description == null) { return null; } @@ -1320,7 +1324,7 @@ public Spanned getDescriptionSpanned(Context ctx) { description = description.replaceAll("(?is)(\\s*\\s*)+", "

").trim(); description = description.replaceAll("(?i)(<[^/p][^>]+>)(

)+", "$1"); final Markwon mw = Markwon.builder(ctx).usePlugin(HtmlPlugin.create()).build(); - return mw.toMarkdown(description); + return new SpannableString(mw.toMarkdown(description)); } // Seen in the FOSDEM schedule: Markdown-ish but with paragraphs marked with both // whitespace and

tags. Well let's make it markdown then... @@ -1329,7 +1333,7 @@ public Spanned getDescriptionSpanned(Context ctx) { final Markwon mw = Markwon.builder(ctx) .usePlugin(LinkifyPlugin.create()).build(); - return mw.toMarkdown(description); + return new SpannableString(mw.toMarkdown(description)); } public AbstractList getSpeakers() { diff --git a/app/src/main/java/net/gaast/giggity/ScheduleViewActivity.java b/app/src/main/java/net/gaast/giggity/ScheduleViewActivity.java index 87124b04..14e6bfe1 100644 --- a/app/src/main/java/net/gaast/giggity/ScheduleViewActivity.java +++ b/app/src/main/java/net/gaast/giggity/ScheduleViewActivity.java @@ -66,6 +66,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.time.ZonedDateTime; @@ -247,22 +248,27 @@ public void onReceive(Context arg0, Intent arg1) { // style arguments but not when that syntax is used after the #. (Using # instead of // ? to avoid the data hitting the server, should the query fall through.) for (String param : parsed.getEncodedFragment().split("&")) { - if (param.startsWith("url=")) { - url = URLDecoder.decode(param.substring(4), StandardCharsets.UTF_8); - } else if (param.startsWith("json=")) { - String jsonb64 = URLDecoder.decode(param.substring(5), StandardCharsets.UTF_8); - byte[] json; - try { - json = Base64.decode(jsonb64, Base64.URL_SAFE); - } catch (IllegalArgumentException e) { - json = new byte[0]; - } - url = app.getDb().refreshSingleSchedule(json); - if (url == null) { - Toast.makeText(this, R.string.no_json_data, Toast.LENGTH_SHORT).show(); - finish(); - return; + try { + if (param.startsWith("url=")) { + url = URLDecoder.decode(param.substring(4), "utf-8"); + } else if (param.startsWith("json=")) { + String jsonb64 = null; + jsonb64 = URLDecoder.decode(param.substring(5), "utf-8"); + byte[] json; + try { + json = Base64.decode(jsonb64, Base64.URL_SAFE); + } catch (IllegalArgumentException e) { + json = new byte[0]; + } + url = app.getDb().refreshSingleSchedule(json); + if (url == null) { + Toast.makeText(this, R.string.no_json_data, Toast.LENGTH_SHORT).show(); + finish(); + return; + } } + } catch (UnsupportedEncodingException e) { + // TODO: Once I'm on API 33+ I can use StandardCharsets.UTF_8 here again. } } parsed = Uri.parse(url);