// Copyright 2007-2019 David Robillard // SPDX-License-Identifier: ISC #include "lilv_internal.h" #include "lilv/lilv.h" #include "sord/sord.h" #include "zix/tree.h" #include #include typedef enum { LILV_LANG_MATCH_NONE, ///< Language does not match at all LILV_LANG_MATCH_PARTIAL, ///< Partial (language, but not country) match LILV_LANG_MATCH_EXACT ///< Exact (language and country) match } LilvLangMatch; static LilvLangMatch lilv_lang_matches(const char* a, const char* b) { if (!a || !b) { return LILV_LANG_MATCH_NONE; } if (!strcmp(a, b)) { return LILV_LANG_MATCH_EXACT; } const char* a_dash = strchr(a, '-'); const size_t a_lang_len = a_dash ? (size_t)(a_dash - a) : strlen(a); const char* b_dash = strchr(b, '-'); const size_t b_lang_len = b_dash ? (size_t)(b_dash - b) : strlen(b); if (a_lang_len == b_lang_len && !strncmp(a, b, a_lang_len)) { return LILV_LANG_MATCH_PARTIAL; } return LILV_LANG_MATCH_NONE; } static LilvNodes* lilv_nodes_from_stream_objects_i18n(LilvWorld* world, SordIter* stream, SordQuadIndex field) { LilvNodes* values = lilv_nodes_new(); const SordNode* nolang = NULL; // Untranslated value const SordNode* partial = NULL; // Partial language match char* syslang = lilv_get_lang(); FOREACH_MATCH (stream) { const SordNode* value = sord_iter_get_node(stream, field); if (sord_node_get_type(value) == SORD_LITERAL) { const char* lang = sord_node_get_language(value); if (!lang) { nolang = value; } else { switch (lilv_lang_matches(lang, syslang)) { case LILV_LANG_MATCH_EXACT: // Exact language match, add to results zix_tree_insert( (ZixTree*)values, lilv_node_new_from_node(world, value), NULL); break; case LILV_LANG_MATCH_PARTIAL: // Partial language match, save in case we find no exact partial = value; break; case LILV_LANG_MATCH_NONE: break; } } } else { zix_tree_insert( (ZixTree*)values, lilv_node_new_from_node(world, value), NULL); } } sord_iter_free(stream); free(syslang); if (lilv_nodes_size(values) > 0) { return values; } const SordNode* best = nolang; if ((syslang && partial) || !best) { best = partial; } if (best) { zix_tree_insert( (ZixTree*)values, lilv_node_new_from_node(world, best), NULL); } else { // No matches whatsoever lilv_nodes_free(values); values = NULL; } return values; } LilvNodes* lilv_nodes_from_stream_objects(LilvWorld* world, SordIter* stream, SordQuadIndex field) { if (sord_iter_end(stream)) { sord_iter_free(stream); return NULL; } if (world->opt.filter_language) { return lilv_nodes_from_stream_objects_i18n(world, stream, field); } LilvNodes* values = lilv_nodes_new(); FOREACH_MATCH (stream) { const SordNode* value = sord_iter_get_node(stream, field); LilvNode* node = lilv_node_new_from_node(world, value); if (node) { zix_tree_insert((ZixTree*)values, node, NULL); } } sord_iter_free(stream); return values; }