Refactor language preference parsing
authorDenis Kenzior <denkenz@gmail.com>
Thu, 17 Sep 2009 18:41:52 +0000 (13:41 -0500)
committerDenis Kenzior <denkenz@gmail.com>
Thu, 17 Sep 2009 19:10:12 +0000 (14:10 -0500)
- Make sure to handle capital / lower case ISO639 strings
- Properly handle the case where files are empty / unused
- Don't emit the signal unless the preferences are useable
- Simplify the logic and be a bit more readable

src/sim.c

index 6ff76d2..1669d94 100644 (file)
--- a/src/sim.c
+++ b/src/sim.c
@@ -654,53 +654,76 @@ static gboolean sim_efli_format(const unsigned char *ef, int length)
        return TRUE;
 }
 
-static void parse_language_list(char **out_list, int *count,
-                               const unsigned char *ef, int length)
+static GSList *parse_language_list(const unsigned char *ef, int length)
 {
-       int i, j;
-
-       length--;
+       int i;
+       GSList *ret = NULL;
 
        for (i = 0; i < length; i += 2) {
-               if (ef[i] == 0xff || ef[i + 1] == 0xff)
-                       continue;
-
-               for (j = 0; j < *count; j++)
-                       if (!memcmp(out_list[j], ef + i, 2))
-                               break;
-               if (j < *count)
+               if (ef[i] > 0x7f || ef[i+1] > 0x7f)
                        continue;
 
                /* ISO 639 codes contain only characters that are coded
                 * identically in SMS 7 bit charset, ASCII or UTF8 so
                 * no conversion.
                 */
-               out_list[(*count)++] = g_strndup((char *) ef + i, 2);
+               ret = g_slist_prepend(ret, g_ascii_strdown((char *)ef + i, 2));
        }
+
+       if (ret)
+               ret = g_slist_reverse(ret);
+
+       return ret;
 }
 
-static void parse_eflp(char **out_list, int *count,
-                       const unsigned char *eflp, int length)
+static GSList *parse_eflp(const unsigned char *eflp, int length)
 {
-       int i, j;
+       int i;
        char code[3];
+       GSList *ret = NULL;
 
        for (i = 0; i < length; i++) {
-               if (eflp[i] >= 0x30)
-                       continue;
-
                if (iso639_2_from_language(eflp[i], code) == FALSE)
                        continue;
 
-               for (j = 0; j < *count; j ++)
-                       if (!memcmp(out_list[j], code, 2))
-                               break;
+               ret = g_slist_prepend(ret, g_strdup(code));
+       }
+
+       if (ret)
+               ret = g_slist_reverse(ret);
+
+       return ret;
+}
+
+static char **concat_lang_prefs(GSList *a, GSList *b)
+{
+       GSList *l, *k;
+       char **ret;
+       int i = 0;
+       int total = g_slist_length(a) + g_slist_length(b);
+
+       if (total == 0)
+               return NULL;
+
+       ret = g_new0(char *, total + 1);
+
+       for (l = a; l; l = l->next)
+               ret[i++] = g_strdup(l->data);
+
+       for (l = b; l; l = l->next) {
+               gboolean duplicate = FALSE;
 
-               if (j < *count)
+               for (k = a; k; k = k->next)
+                       if (!strcmp(k->data, l->data))
+                               duplicate = TRUE;
+
+               if (duplicate)
                        continue;
 
-               out_list[*count++] = g_strdup(code);
+               ret[i++] = g_strdup(l->data);
        }
+
+       return ret;
 }
 
 static void sim_efpl_read_cb(int ok,
@@ -710,66 +733,57 @@ static void sim_efpl_read_cb(int ok,
                                int record_length, void *userdata)
 {
        struct ofono_sim *sim = userdata;
-       unsigned char *efli = sim->efli;
-       const unsigned char *efpl = data;
-       int efli_length = sim->efli_length;
-       int efpl_length = length;
-       int count;
-       int maxcount;
        const char *path = __ofono_atom_get_path(sim->atom);
        DBusConnection *conn = ofono_dbus_get_connection();
+       gboolean eflp_format = TRUE;
+       GSList *efli = NULL;
+       GSList *efpl = NULL;
 
        if (!ok || structure != OFONO_SIM_FILE_STRUCTURE_TRANSPARENT ||
-                       length < 2) {
-               efpl = NULL;
-               efpl_length = 0;
-       }
-
-       if (!efli || sim_efli_format(efli, efli_length)) {
-               maxcount = (efli_length + efpl_length) / 2;
-               sim->language_prefs = g_new0(char *, maxcount + 1);
-
-               count = 0;
+                       length < 2)
+               goto skip_efpl;
 
-               /* Make a list of languages in both files in order of
-                * preference following TS 31.102.
-                */
-
-               if (efli && efpl && efli[0] == 0xff && efli[1] == 0xff) {
-                       parse_language_list(sim->language_prefs, &count,
-                                               efpl, efpl_length);
-                       efpl = NULL;
-               }
+       efpl = parse_language_list(data, length);
 
-               if (efli) {
-                       parse_language_list(sim->language_prefs, &count,
-                                               efli, efli_length);
-                       g_free(efli);
-                       sim->efli = NULL;
-               }
+skip_efpl:
+       if (sim->efli && sim->efli_length > 0) {
+               eflp_format = sim_efli_format(sim->efli, sim->efli_length);
 
-               if (efpl)
-                       parse_language_list(sim->language_prefs, &count,
-                                               efpl, efpl_length);
-       } else {
-               maxcount = efpl_length / 2 + efli_length;
-               sim->language_prefs = g_new0(char *, maxcount + 1);
+               if (eflp_format)
+                       efli = parse_language_list(sim->efli, sim->efli_length);
+               else
+                       efli = parse_eflp(sim->efli, sim->efli_length);
 
-               count = 0;
+               g_free(sim->efli);
+               sim->efli = NULL;
+               sim->efli_length = 0;
+       }
 
-               /* Make a list of languages in both files in order of
-                * preference following TS 51.011.
-                */
+       /* If efli_format is TRUE, make a list of languages in both files in
+        * order of preference following TS 31.102.
+        * Quoting 31.102 Section 5.1.1.2:
+        * The preferred language selection shall always use the EFLI in
+        * preference to the EFPL at the MF unless...
+        * Otherwise in order of preference according to TS 51.011
+        */
+       if (eflp_format)
+               sim->language_prefs = concat_lang_prefs(efli, efpl);
+       else
+               sim->language_prefs = concat_lang_prefs(efpl, efli);
 
-               if (efpl)
-                       parse_language_list(sim->language_prefs, &count,
-                                               efpl, efpl_length);
+       if (efli) {
+               g_slist_foreach(efli, (GFunc)g_free, NULL);
+               g_slist_free(efli);
+       }
 
-               parse_eflp(sim->language_prefs, &count, efli, efli_length);
-               g_free(efli);
-               sim->efli = NULL;
+       if (efpl) {
+               g_slist_foreach(efpl, (GFunc)g_free, NULL);
+               g_slist_free(efpl);
        }
 
+       if (sim->language_prefs == NULL)
+               return;
+
        ofono_dbus_signal_array_property_changed(conn, path,
                                                        SIM_MANAGER_INTERFACE,
                                                        "PreferredLanguages",