registry: skip over invalid ISO639 or ISO3166 entries

If the XML file is somehow off, don't load entries that are against the spec.
master
Peter Hutterer 2022-01-20 13:08:36 +10:00
parent 34ef11d9c9
commit 9b05825e53
2 changed files with 157 additions and 7 deletions

View File

@ -808,6 +808,11 @@ parse_language_list(xmlNode *language_list, struct rxkb_layout *layout)
char *str = extract_text(node); char *str = extract_text(node);
struct rxkb_object *parent; struct rxkb_object *parent;
if (!str || strlen(str) != 3) {
free(str);
continue;
}
parent = &layout->base; parent = &layout->base;
code = rxkb_iso639_code_create(parent); code = rxkb_iso639_code_create(parent);
code->code = str; code->code = str;
@ -827,6 +832,11 @@ parse_country_list(xmlNode *country_list, struct rxkb_layout *layout)
char *str = extract_text(node); char *str = extract_text(node);
struct rxkb_object *parent; struct rxkb_object *parent;
if (!str || strlen(str) != 2) {
free(str);
continue;
}
parent = &layout->base; parent = &layout->base;
code = rxkb_iso3166_code_create(parent); code = rxkb_iso3166_code_create(parent);
code->code = str; code->code = str;

View File

@ -56,6 +56,8 @@ struct test_layout {
const char *variant; const char *variant;
const char *brief; const char *brief;
const char *description; const char *description;
const char *iso639[3]; /* language list (iso639 three letter codes), 3 is enough for our test */
const char *iso3166[3]; /* country list (iso3166 two letter codes), 3 is enough for our tests */
}; };
struct test_option { struct test_option {
@ -76,7 +78,9 @@ fprint_config_item(FILE *fp,
const char *name, const char *name,
const char *vendor, const char *vendor,
const char *brief, const char *brief,
const char *description) const char *description,
const char * const iso639[3],
const char * const iso3166[3])
{ {
fprintf(fp, " <configItem>\n" fprintf(fp, " <configItem>\n"
" <name>%s</name>\n", name); " <name>%s</name>\n", name);
@ -86,6 +90,27 @@ fprint_config_item(FILE *fp,
fprintf(fp, " <description>%s</description>\n", description); fprintf(fp, " <description>%s</description>\n", description);
if (vendor) if (vendor)
fprintf(fp, " <vendor>%s</vendor>\n", vendor); fprintf(fp, " <vendor>%s</vendor>\n", vendor);
if (iso3166 && iso3166[0]) {
fprintf(fp, " <countryList>\n");
for (int i = 0; i < 3; i++) {
const char *iso = iso3166[i];
if (!iso)
break;
fprintf(fp, " <iso3166Id>%s</iso3166Id>\n", iso);
}
fprintf(fp, " </countryList>\n");
}
if (iso639 && iso639[0]) {
fprintf(fp, " <languageList>\n");
for (int i = 0; i < 3; i++) {
const char *iso = iso639[i];
if (!iso)
break;
fprintf(fp, " <iso639Id>%s</iso639Id>\n", iso);
}
fprintf(fp, " </languageList>\n");
}
fprintf(fp, " </configItem>\n"); fprintf(fp, " </configItem>\n");
} }
@ -131,7 +156,7 @@ test_create_rules(const char *ruleset,
for (const struct test_model *m = test_models; m->name; m++) { for (const struct test_model *m = test_models; m->name; m++) {
fprintf(fp, "<model>\n"); fprintf(fp, "<model>\n");
fprint_config_item(fp, m->name, m->vendor, NULL, m->description); fprint_config_item(fp, m->name, m->vendor, NULL, m->description, NULL, NULL);
fprintf(fp, "</model>\n"); fprintf(fp, "</model>\n");
} }
fprintf(fp, "</modelList>\n"); fprintf(fp, "</modelList>\n");
@ -149,14 +174,13 @@ test_create_rules(const char *ruleset,
while (l->name) { while (l->name) {
fprintf(fp, "<layout>\n"); fprintf(fp, "<layout>\n");
fprint_config_item(fp, l->name, NULL, l->brief, l->description); fprint_config_item(fp, l->name, NULL, l->brief, l->description, l->iso639, l->iso3166);
if (next->name && streq(next->name, l->name)) { if (next->name && streq(next->name, l->name)) {
fprintf(fp, "<variantList>\n"); fprintf(fp, "<variantList>\n");
do { do {
fprintf(fp, "<variant>\n"); fprintf(fp, "<variant>\n");
fprint_config_item(fp, next->variant, NULL, next->brief, fprint_config_item(fp, next->variant, NULL, next->brief, next->description, next->iso639, next->iso3166);
next->description);
fprintf(fp, "</variant>\n"); fprintf(fp, "</variant>\n");
l = next; l = next;
next++; next++;
@ -175,10 +199,10 @@ test_create_rules(const char *ruleset,
for (const struct test_option_group *g = test_groups; g->name; g++) { for (const struct test_option_group *g = test_groups; g->name; g++) {
fprintf(fp, "<group allowMultipleSelection=\"%s\">\n", fprintf(fp, "<group allowMultipleSelection=\"%s\">\n",
g->allow_multiple_selection ? "true" : "false"); g->allow_multiple_selection ? "true" : "false");
fprint_config_item(fp, g->name, NULL, NULL, g->description); fprint_config_item(fp, g->name, NULL, NULL, g->description, NULL, NULL);
for (const struct test_option *o = g->options; o->name; o++) { for (const struct test_option *o = g->options; o->name; o++) {
fprintf(fp, " <option>\n"); fprintf(fp, " <option>\n");
fprint_config_item(fp, o->name, NULL, NULL, o->description); fprint_config_item(fp, o->name, NULL, NULL, o->description, NULL, NULL);
fprintf(fp, "</option>\n"); fprintf(fp, "</option>\n");
} }
fprintf(fp, "</group>\n"); fprintf(fp, "</group>\n");
@ -443,6 +467,9 @@ cmp_models(struct test_model *tm, struct rxkb_model *m)
static bool static bool
cmp_layouts(struct test_layout *tl, struct rxkb_layout *l) cmp_layouts(struct test_layout *tl, struct rxkb_layout *l)
{ {
struct rxkb_iso3166_code *iso3166 = NULL;
struct rxkb_iso639_code *iso639 = NULL;
if (!tl || !l) if (!tl || !l)
return false; return false;
@ -458,6 +485,36 @@ cmp_layouts(struct test_layout *tl, struct rxkb_layout *l)
if (!streq_null(tl->description, rxkb_layout_get_description(l))) if (!streq_null(tl->description, rxkb_layout_get_description(l)))
return false; return false;
iso3166 = rxkb_layout_get_iso3166_first(l);
for (size_t i = 0; i < sizeof(tl->iso3166); i++) {
const char *iso = tl->iso3166[i];
if (iso == NULL && iso3166 == NULL)
break;
if (!streq_null(iso, rxkb_iso3166_code_get_code(iso3166)))
return false;
iso3166 = rxkb_iso3166_code_next(iso3166);
}
if (iso3166 != NULL)
return false;
iso639 = rxkb_layout_get_iso639_first(l);
for (size_t i = 0; i < sizeof(tl->iso639); i++) {
const char *iso = tl->iso639[i];
if (iso == NULL && iso639 == NULL)
break;
if (!streq_null(iso, rxkb_iso639_code_get_code(iso639)))
return false;
iso639 = rxkb_iso639_code_next(iso639);
}
if (iso639 != NULL)
return false;
return true; return true;
} }
@ -608,6 +665,87 @@ test_load_full(void)
rxkb_context_unref(ctx); rxkb_context_unref(ctx);
} }
static void
test_load_languages(void)
{
struct test_model system_models[] = {
{"m1", "vendor1", "desc1"},
{NULL},
};
struct test_layout system_layouts[] = {
{"l1", NO_VARIANT, "lbrief1", "ldesc1",
.iso639 = { "abc", "def" },
.iso3166 = { "uv", "wx" }},
{"l1", "v1", "vbrief1", "vdesc1",
.iso639 = {"efg"},
.iso3166 = {"yz"}},
{NULL},
};
struct test_option_group system_groups[] = {
{"grp1", "gdesc1", true,
{ {"grp1:1", "odesc11"}, {"grp1:2", "odesc12"} } },
{ NULL },
};
struct rxkb_context *ctx;
struct rxkb_layout *l;
ctx = test_setup_context(system_models, NULL,
system_layouts, NULL,
system_groups, NULL);
l = fetch_layout(ctx, "l1", NO_VARIANT);
assert(cmp_layouts(&system_layouts[0], l));
rxkb_layout_unref(l);
l = fetch_layout(ctx, "l1", "v1");
assert(cmp_layouts(&system_layouts[1], l));
rxkb_layout_unref(l);
rxkb_context_unref(ctx);
}
static void
test_load_invalid_languages(void)
{
struct test_model system_models[] = {
{"m1", "vendor1", "desc1"},
{NULL},
};
struct test_layout system_layouts[] = {
{"l1", NO_VARIANT, "lbrief1", "ldesc1",
.iso639 = { "ab", "def" },
.iso3166 = { "uvw", "xz" }},
{NULL},
};
struct test_option_group system_groups[] = {
{"grp1", "gdesc1", true,
{ {"grp1:1", "odesc11"}, {"grp1:2", "odesc12"} } },
{ NULL },
};
struct rxkb_context *ctx;
struct rxkb_layout *l;
struct rxkb_iso3166_code *iso3166;
struct rxkb_iso639_code *iso639;
ctx = test_setup_context(system_models, NULL,
system_layouts, NULL,
system_groups, NULL);
l = fetch_layout(ctx, "l1", NO_VARIANT);
/* uvw is invalid, we expect 2 letters, verify it was ignored */
iso3166 = rxkb_layout_get_iso3166_first(l);
assert(streq(rxkb_iso3166_code_get_code(iso3166), "xz"));
assert(rxkb_iso3166_code_next(iso3166) == NULL);
/* ab is invalid, we expect 3 letters, verify it was ignored */
iso639 = rxkb_layout_get_iso639_first(l);
assert(streq(rxkb_iso639_code_get_code(iso639), "def"));
assert(rxkb_iso639_code_next(iso639) == NULL);
rxkb_layout_unref(l);
rxkb_context_unref(ctx);
}
static void static void
test_popularity(void) test_popularity(void)
{ {
@ -849,6 +987,8 @@ main(void)
test_load_full(); test_load_full();
test_load_merge(); test_load_merge();
test_load_merge_no_overwrite(); test_load_merge_no_overwrite();
test_load_languages();
test_load_invalid_languages();
test_popularity(); test_popularity();
return 0; return 0;