From b13037fad0905c5933d1ff579122ba1357b02eea Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 12 May 2016 19:13:05 -0700 Subject: [PATCH] altoslib: Store common frequencies in library version-independent form Serializable Objects in java are very specific to the class being serialized. As we bump the name of the library on a regular basis to note API/ABI issues, this mean a saved a Serializable object in the preferences database will fail to load across library version upgrades. The saved tracker state and saved common frequencies were the only objects saved in this form; this patch adds infrastructure for writing objects in a version-independent form, and then adds support for saving frequencies in that form. Signed-off-by: Keith Packard --- altoslib/AltosFrequency.java | 13 +++ altoslib/AltosHashSet.java | 173 +++++++++++++++++++++++++++++++++ altoslib/AltosParse.java | 8 ++ altoslib/AltosPreferences.java | 29 +++++- altoslib/Makefile.am | 1 + 5 files changed, 220 insertions(+), 4 deletions(-) create mode 100644 altoslib/AltosHashSet.java diff --git a/altoslib/AltosFrequency.java b/altoslib/AltosFrequency.java index ef46bd67..88997152 100644 --- a/altoslib/AltosFrequency.java +++ b/altoslib/AltosFrequency.java @@ -58,8 +58,21 @@ public class AltosFrequency implements Serializable { return diff < 0.010; } + public AltosHashSet hashSet() { + AltosHashSet h = new AltosHashSet(); + + h.putDouble("frequency", frequency); + h.putString("description", description); + return h; + } + public AltosFrequency(double f, String d) { frequency = f; description = d; } + + public AltosFrequency(AltosHashSet h) { + frequency = h.getDouble("frequency", 0.0); + description = h.getString("description", ""); + } } diff --git a/altoslib/AltosHashSet.java b/altoslib/AltosHashSet.java new file mode 100644 index 00000000..488d52e8 --- /dev/null +++ b/altoslib/AltosHashSet.java @@ -0,0 +1,173 @@ +/* + * Copyright © 2016 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_11; + +import java.io.*; +import java.util.*; +import java.text.*; + +public class AltosHashSet extends Hashtable { + private StringWriter writer; + + static private int get(StringReader reader) throws IOException { + return reader.read(); + } + + static private String get_token(StringReader reader) throws IOException { + int c = get(reader); + + if (c == -1) + return null; + + ArrayList chars = new ArrayList(); + + for (;;) { + chars.add(c); + c = get(reader); + if (c == -1 || c == ';') + break; + if (c == '\\') + c = get(reader); + } + int[] ch = new int[chars.size()]; + for (int i = 0; i < ch.length; i++) + ch[i] = chars.get(i); + return new String(ch, 0, ch.length); + } + + static private void put(StringWriter writer, int c) throws IOException { + writer.write(c); + } + + static private void put_token(StringWriter writer, String token) throws IOException { + for (int i = 0; i < token.length(); i++) { + int c = token.codePointAt(i); + + switch (c) { + case ';': + case '\\': + put(writer, '\\'); + } + put(writer, c); + } + put(writer, ';'); + } + + public String toString() { + try { + StringWriter writer = new StringWriter(); + + for (String key : keySet()) { + String value = get(key); + put_token(writer, key); + put_token(writer, value); + } + return writer.toString(); + } catch (IOException ie) { + return null; + } + } + + public void putInt(String key, int value) { + put(key, Integer.toString(value)); + } + + public int getInt(String key, int def) { + String value = get(key); + + if (value == null) + return def; + try { + return AltosParse.parse_int(value); + } catch (ParseException pe) { + return def; + } + } + + public void putDouble(String key, double value) { + put(key, AltosParse.format_double_net(value)); + } + + public double getDouble(String key, double def) { + String value = get(key); + + if (value == null) + return def; + try { + return AltosParse.parse_double_net(value); + } catch (ParseException pe) { + return def; + } + } + + public String getString(String key, String def) { + String value = get(key); + + if (value == null) + return def; + return value; + } + + public void putString(String key, String value) { + put(key, value); + } + + public AltosHashSet (String string) throws IOException { + StringReader reader = new StringReader(string); + String key, value; + + for (;;) { + key = get_token(reader); + value = get_token(reader); + if (key == null || value == null) + break; + put(key, value); + } + } + + public AltosHashSet() { + } + + static public AltosHashSet[] array(String string) throws IOException { + + if (string == null) + return null; + + StringReader reader = new StringReader(string); + ArrayList array = new ArrayList(); + String element; + + while ((element = get_token(reader)) != null) + array.add(new AltosHashSet(element)); + return array.toArray(new AltosHashSet[0]); + } + + static public String toString(AltosHashSet[] sets) throws IOException { + + if (sets == null) + return null; + + StringWriter writer = new StringWriter(); + + for (AltosHashSet h : sets) { + String element = h.toString(); + put_token(writer, element); + } + return writer.toString(); + } +} diff --git a/altoslib/AltosParse.java b/altoslib/AltosParse.java index ae88182d..12499b7b 100644 --- a/altoslib/AltosParse.java +++ b/altoslib/AltosParse.java @@ -53,6 +53,10 @@ public class AltosParse { } } + public static String format_double_locale(double number) { + return nf_locale.format(number); + } + public static double parse_double_net(String str) throws ParseException { try { return nf_net.parse(str.trim()).doubleValue(); @@ -61,6 +65,10 @@ public class AltosParse { } } + public static String format_double_net(double number) { + return nf_net.format(number); + } + public static double parse_coord(String coord) throws ParseException { String[] dsf = coord.split("\\D+"); diff --git a/altoslib/AltosPreferences.java b/altoslib/AltosPreferences.java index b853e944..f8101ce6 100644 --- a/altoslib/AltosPreferences.java +++ b/altoslib/AltosPreferences.java @@ -116,7 +116,7 @@ public class AltosPreferences { public final static String frequency_count = "COUNT"; public final static String frequency_format = "FREQUENCY-%d"; public final static String description_format = "DESCRIPTION-%d"; - public final static String frequenciesPreference = "FREQUENCIES"; + public final static String frequenciesPreference = "FREQUENCIES-1"; /* Units preference */ @@ -136,7 +136,17 @@ public class AltosPreferences { AltosFrequency[] frequencies = null; - frequencies = (AltosFrequency[]) backend.getSerializable(frequenciesPreference, null); + try { + AltosHashSet[] sets = AltosHashSet.array(backend.getString(frequenciesPreference,null)); + if (sets != null) { + frequencies = new AltosFrequency[sets.length]; + for (int i = 0; i < frequencies.length; i++) + frequencies[i] = new AltosFrequency(sets[i]); + } + + } catch (IOException ie) { + frequencies = null; + } if (frequencies == null) { if (backend.nodeExists(common_frequencies_node_name)) { @@ -165,6 +175,17 @@ public class AltosPreferences { return frequencies; } + public static void save_common_frequencies() { + try { + AltosHashSet[] sets = new AltosHashSet[common_frequencies.length]; + for (int i = 0; i < sets.length; i++) + sets[i] = common_frequencies[i].hashSet(); + backend.putString(frequenciesPreference, AltosHashSet.toString(sets)); + } catch (IOException ie) { + } + flush_preferences(); + } + public static int launcher_serial; public static int launcher_channel; @@ -512,8 +533,8 @@ public class AltosPreferences { public static void set_common_frequencies(AltosFrequency[] frequencies) { synchronized(backend) { common_frequencies = frequencies; - backend.putSerializable(frequenciesPreference, frequencies); - flush_preferences(); + + save_common_frequencies(); } } diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index f3219839..512e1cca 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -160,6 +160,7 @@ altoslib_JAVA = \ AltosMapLoaderListener.java \ AltosMapLoader.java \ AltosMapTypeListener.java \ + AltosHashSet.java \ AltosVersion.java JAR=altoslib_$(ALTOSLIB_VERSION).jar -- 2.30.2