mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-09-19 10:30:30 +00:00
239 lines
6.8 KiB
C
239 lines
6.8 KiB
C
/* GStreamer Language Tag Utility Functions
|
|
* Copyright (C) 2009 Tim-Philipp Müller <tim centricular net>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
/* mklangtables.c:
|
|
* little program that reads iso_639.xml and outputs tables for us as fallback
|
|
* for when iso-codes are not available or we fail to read the file for some
|
|
* reason, and so we don't have to parse the xml file just to map codes.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <glib.h>
|
|
#include <string.h>
|
|
|
|
#define ISO_639_XML_PATH ISO_CODES_PREFIX "/share/xml/iso-codes/iso_639.xml"
|
|
|
|
typedef struct
|
|
{
|
|
gchar code_1[3]; /* de */
|
|
gchar code_2t[4]; /* deu */
|
|
gchar code_2b[4]; /* ger */
|
|
const gchar *name; /* German */
|
|
guint name_offset; /* offset into string table */
|
|
} IsoLang;
|
|
|
|
static GArray *languages = NULL;
|
|
|
|
static void
|
|
dump_languages (void)
|
|
{
|
|
GString *names;
|
|
const char *s;
|
|
int i, num_escaped;
|
|
|
|
g_assert (languages != NULL);
|
|
|
|
names = g_string_new ("");
|
|
|
|
g_print ("/* generated by " __FILE__ " iso-codes " ISO_CODES_VERSION " */\n");
|
|
g_print ("\n");
|
|
g_print ("#include <glib.h>\n");
|
|
g_print ("\n");
|
|
g_print ("#define ISO_639_FLAG_2T (1 << 0)\n");
|
|
g_print ("#define ISO_639_FLAG_2B (1 << 1)\n");
|
|
g_print ("\n");
|
|
g_print ("/* *INDENT-OFF* */\n");
|
|
g_print ("\n");
|
|
g_print ("static const struct\n");
|
|
g_print ("{\n");
|
|
g_print (" const gchar iso_639_1[3];\n");
|
|
g_print (" const gchar iso_639_2[4];\n");
|
|
g_print (" guint8 flags;\n");
|
|
g_print (" guint16 name_offset;\n");
|
|
g_print ("} iso_639_codes[] = {\n");
|
|
|
|
for (i = 0, num_escaped = 0; i < languages->len; ++i) {
|
|
IsoLang *lang = &g_array_index (languages, IsoLang, i);
|
|
|
|
/* For now just print those where there's both a ISO-639-1 and -2 code */
|
|
if (lang->code_1[0] == '\0')
|
|
continue;
|
|
|
|
/* save current offset */
|
|
lang->name_offset = names->len;
|
|
|
|
/* adjust for fact that \000 is 4 chars now but will take up only 1 later */
|
|
lang->name_offset -= num_escaped * 3;
|
|
|
|
/* append one char at a time, making sure to escape UTF-8 characters */
|
|
for (s = lang->name; s != NULL && *s != '\0'; ++s) {
|
|
if (g_ascii_isprint (*s) && *s != '"' && *s != '\\') {
|
|
g_string_append_c (names, *s);
|
|
} else {
|
|
g_string_append_printf (names, "\\%03o", (unsigned char) *s);
|
|
++num_escaped;
|
|
}
|
|
}
|
|
g_string_append (names, "\\000");
|
|
++num_escaped;
|
|
|
|
g_print (" /* %s */\n", lang->name);
|
|
if (strcmp (lang->code_2b, lang->code_2t) == 0) {
|
|
g_print (" { \"%s\", \"%s\", ISO_639_FLAG_2T | ISO_639_FLAG_2B, %u },\n",
|
|
lang->code_1, lang->code_2t, lang->name_offset);
|
|
} else {
|
|
/* if 639-2T and 639-2B differ, put 639-2T first */
|
|
g_print (" { \"%s\", \"%s\", ISO_639_FLAG_2T, %u },\n",
|
|
lang->code_1, lang->code_2t, lang->name_offset);
|
|
g_print (" { \"%s\", \"%s\", ISO_639_FLAG_2B, %u },\n",
|
|
lang->code_1, lang->code_2b, lang->name_offset);
|
|
}
|
|
}
|
|
|
|
g_print ("};\n");
|
|
g_print ("\n");
|
|
g_print ("static const gchar iso_639_names[] =\n");
|
|
s = names->str;
|
|
while (s != NULL && *s != '\0') {
|
|
gchar line[74], *lastesc;
|
|
guint left;
|
|
|
|
left = strlen (s);
|
|
g_strlcpy (line, s, MIN (left, sizeof (line)));
|
|
s += sizeof (line) - 1;
|
|
/* avoid partial escaped codes at the end of a line */
|
|
if ((lastesc = strrchr (line, '\\')) && strlen (lastesc) < 4) {
|
|
s -= strlen (lastesc);
|
|
*lastesc = '\0';
|
|
}
|
|
g_print (" \"%s\"", line);
|
|
if (left < 74)
|
|
break;
|
|
g_print ("\n");
|
|
}
|
|
g_print (";\n");
|
|
g_print ("\n");
|
|
g_print ("/* *INDENT-ON* */\n");
|
|
|
|
g_string_free (names, TRUE);
|
|
}
|
|
|
|
static gboolean
|
|
copy_attribute (gchar * dest, guint dest_len, const gchar ** attr_names,
|
|
const gchar ** attr_vals, const gchar * needle)
|
|
{
|
|
while (attr_names != NULL && *attr_names != NULL) {
|
|
if (strcmp (*attr_names, needle) == 0) {
|
|
g_strlcpy (dest, *attr_vals, dest_len);
|
|
return TRUE;
|
|
}
|
|
++attr_names;
|
|
++attr_vals;
|
|
}
|
|
dest[0] = '\0';
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
xml_start_element (GMarkupParseContext * ctx, const gchar * element_name,
|
|
const gchar ** attr_names, const gchar ** attr_vals,
|
|
gpointer user_data, GError ** error)
|
|
{
|
|
gchar name[256];
|
|
IsoLang lang;
|
|
|
|
if (strcmp (element_name, "iso_639_entry") != 0)
|
|
return;
|
|
|
|
copy_attribute (lang.code_1, 3, attr_names, attr_vals, "iso_639_1_code");
|
|
copy_attribute (lang.code_2t, 4, attr_names, attr_vals, "iso_639_2T_code");
|
|
copy_attribute (lang.code_2b, 4, attr_names, attr_vals, "iso_639_2B_code");
|
|
|
|
copy_attribute (name, sizeof (name), attr_names, attr_vals, "name");
|
|
lang.name = g_intern_string (name);
|
|
|
|
g_array_append_val (languages, lang);
|
|
}
|
|
|
|
static void
|
|
parse_iso_639_xml (const gchar * data, gsize len)
|
|
{
|
|
GMarkupParser xml_parser = { xml_start_element, NULL, NULL, NULL, NULL };
|
|
GMarkupParseContext *ctx;
|
|
GError *err = NULL;
|
|
|
|
g_return_if_fail (g_utf8_validate (data, len, NULL));
|
|
|
|
ctx = g_markup_parse_context_new (&xml_parser, 0, NULL, NULL);
|
|
if (!g_markup_parse_context_parse (ctx, data, len, &err))
|
|
g_error ("Parsing failed: %s", err->message);
|
|
|
|
g_markup_parse_context_free (ctx);
|
|
}
|
|
|
|
static gint
|
|
languages_sort_func (IsoLang * l1, IsoLang * l2)
|
|
{
|
|
if (l1 == l2)
|
|
return 0;
|
|
|
|
if (l1->code_1[0] == '\0' && l2->code_1[0] != '\0')
|
|
return -1;
|
|
|
|
return strcmp (l1->code_1, l2->code_1);
|
|
}
|
|
|
|
int
|
|
main (int argc, char **argv)
|
|
{
|
|
GMappedFile *f;
|
|
gchar *xml_data;
|
|
gsize xml_len;
|
|
|
|
f = g_mapped_file_new (ISO_639_XML_PATH, FALSE, NULL);
|
|
if (f != NULL) {
|
|
xml_data = (gchar *) g_mapped_file_get_contents (f);
|
|
xml_len = g_mapped_file_get_length (f);
|
|
} else {
|
|
GError *err = NULL;
|
|
|
|
if (!g_file_get_contents (ISO_639_XML_PATH, &xml_data, &xml_len, &err))
|
|
g_error ("Could not read %s: %s", ISO_639_XML_PATH, err->message);
|
|
}
|
|
|
|
languages = g_array_new (FALSE, TRUE, sizeof (IsoLang));
|
|
|
|
parse_iso_639_xml (xml_data, xml_len);
|
|
|
|
g_array_sort (languages, (GCompareFunc) languages_sort_func);
|
|
|
|
dump_languages ();
|
|
|
|
g_array_free (languages, TRUE);
|
|
|
|
if (f != NULL)
|
|
g_mapped_file_unref (f);
|
|
else
|
|
g_free (xml_data);
|
|
|
|
return 0;
|
|
}
|