summaryrefslogtreecommitdiff
path: root/update-mime-database.c
diff options
context:
space:
mode:
authorThomas Leonard <tal@ecs.soton.ac.uk>2003-02-27 21:53:21 +0000
committerThomas Leonard <tal@ecs.soton.ac.uk>2003-02-27 21:53:21 +0000
commit3b52b9cdd68b54ac5434a685afb7d3fe3dcef6be (patch)
treee7a7cb9431527c7e9020adb67833d27bfb0afcef /update-mime-database.c
parent1696b934e13e03581752fb48033d128f167d0995 (diff)
downloadshared-mime-info-3b52b9cdd68b54ac5434a685afb7d3fe3dcef6be.tar.gz
Updated to new spec (work-in-progress).
Diffstat (limited to 'update-mime-database.c')
-rw-r--r--update-mime-database.c267
1 files changed, 241 insertions, 26 deletions
diff --git a/update-mime-database.c b/update-mime-database.c
index 685018bd..ae4fdf17 100644
--- a/update-mime-database.c
+++ b/update-mime-database.c
@@ -4,6 +4,7 @@
#define _(x) (x)
#include <string.h>
+#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
@@ -40,7 +41,6 @@ const char *media_types[] = {
};
typedef struct _Type Type;
-typedef struct _Magic Magic;
struct _Type {
char *media;
@@ -58,7 +58,7 @@ static GHashTable *globs_hash = NULL;
/* 'magic' nodes */
static GPtrArray *magic = NULL;
-
+
static void usage(const char *name)
{
fprintf(stderr, _("Usage: %s [-hv] MIME-DIR\n"), name);
@@ -407,19 +407,25 @@ static void write_out_type(gpointer key, gpointer value, gpointer data)
{
Type *type = (Type *) value;
const char *mime_dir = (char *) data;
- char *media, *filename;
+ char *media, *filename, *new_name;
media = g_strconcat(mime_dir, "/", type->media, NULL);
mkdir(media, 0755);
- filename = g_strconcat(media, "/", type->subtype, ".xml", NULL);
+ filename = g_strconcat(media, "/", type->subtype, ".xml.new", NULL);
g_free(media);
media = NULL;
if (save_xml_file(type->output, filename) != 0)
g_warning("Failed to write out '%s'\n", filename);
+ new_name = g_strndup(filename, strlen(filename) - 4);
+ if (rename(filename, new_name))
+ g_warning("Failed to rename %s as %s\n",
+ filename, new_name);
+
g_free(filename);
+ g_free(new_name);
}
static int get_priority(xmlNode *node)
@@ -432,6 +438,7 @@ static int get_priority(xmlNode *node)
{
p = atoi(prio_string);
g_free(prio_string);
+ g_return_val_if_fail(p >= 0 && p <= 100, 50);
return p;
}
else
@@ -454,9 +461,9 @@ static gint cmp_magic(gconstpointer a, gconstpointer b)
pb = get_priority(bb);
if (pa > pb)
- return 1;
- else if (pa < pb)
return -1;
+ else if (pa < pb)
+ return 1;
type_a = xmlGetNsProp(aa, "type", NULL);
type_b = xmlGetNsProp(bb, "type", NULL);
@@ -471,14 +478,181 @@ static gint cmp_magic(gconstpointer a, gconstpointer b)
return retval;
}
+static void write32(FILE *stream, guint32 n)
+{
+ guint32 big = GUINT32_TO_BE(n);
+
+ fwrite(&big, sizeof(big), 1, stream);
+}
+
+static void write16(FILE *stream, guint32 n)
+{
+ guint16 big = GUINT16_TO_BE(n);
+
+ g_return_if_fail(n <= 0xffff);
+
+ fwrite(&big, sizeof(big), 1, stream);
+}
+
+/* Single hex char to int; -1 if not a hex char.
+ * From file(1).
+ */
+static int hextoint(int c)
+{
+ if (!isascii((unsigned char) c))
+ return -1;
+ if (isdigit((unsigned char) c))
+ return c - '0';
+ if ((c >= 'a')&&(c <= 'f'))
+ return c + 10 - 'a';
+ if (( c>= 'A')&&(c <= 'F'))
+ return c + 10 - 'A';
+ return -1;
+}
+
+/*
+ * Convert a string containing C character escapes. Stop at an unescaped
+ * space or tab.
+ * Copy the converted version to "p", returning its length in *slen.
+ * Return updated scan pointer as function result.
+ * Stolen from file(1) and heavily modified.
+ */
+static void getstr(const char *s, GString *out)
+{
+ int c;
+ int val;
+
+ while ((c = *s++) != '\0') {
+ if(c == '\\') {
+ switch(c = *s++) {
+
+ case '\0':
+ return;
+
+ default:
+ g_string_append_c(out, (char) c);
+ break;
+
+ case 'n':
+ g_string_append_c(out, '\n');
+ break;
+
+ case 'r':
+ g_string_append_c(out, '\r');
+ break;
+
+ case 'b':
+ g_string_append_c(out, '\b');
+ break;
+
+ case 't':
+ g_string_append_c(out, '\t');
+ break;
+
+ case 'f':
+ g_string_append_c(out, '\f');
+ break;
+
+ case 'v':
+ g_string_append_c(out, '\v');
+ break;
+
+ /* \ and up to 3 octal digits */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ val = c - '0';
+ c = *s++; /* try for 2 */
+ if(c >= '0' && c <= '7') {
+ val = (val<<3) | (c - '0');
+ c = *s++; /* try for 3 */
+ if(c >= '0' && c <= '7')
+ val = (val<<3) | (c-'0');
+ else
+ --s;
+ }
+ else
+ --s;
+ g_string_append_c(out, (char)val);
+ break;
+
+ /* \x and up to 2 hex digits */
+ case 'x':
+ val = 'x'; /* Default if no digits */
+ c = hextoint(*s++); /* Get next char */
+ if (c >= 0) {
+ val = c;
+ c = hextoint(*s++);
+ if (c >= 0)
+ val = (val << 4) + c;
+ else
+ --s;
+ } else
+ --s;
+ g_string_append_c(out, (char)val);
+ break;
+ }
+ } else
+ g_string_append_c(out, (char)c);
+ }
+}
+
+static void parse_value(const char *type, const char *in, GString *parsed_value)
+{
+ char *end;
+ long value;
+
+ g_return_if_fail(*in != '\0');
+
+ if (strstr(type, "16"))
+ {
+ value = strtol(in, &end, 0);
+ g_return_if_fail(*end == '\0');
+ g_string_append_c(parsed_value, (value >> 8) & 0xff);
+ g_string_append_c(parsed_value, value & 0xff);
+ }
+ else if (strstr(type, "32"))
+ {
+ value = strtol(in, &end, 0);
+ g_return_if_fail(*end == '\0');
+ g_string_append_c(parsed_value, (value >> 24) & 0xff);
+ g_string_append_c(parsed_value, (value >> 16)& 0xff);
+ g_string_append_c(parsed_value, (value >> 8) & 0xff);
+ g_string_append_c(parsed_value, value & 0xff);
+ }
+ else if (strcmp(type, "byte") == 0)
+ {
+ value = strtol(in, &end, 0);
+ g_return_if_fail(*end == '\0');
+ g_string_append_c(parsed_value, value & 0xff);
+ }
+ else if (strcmp(type, "string") == 0)
+ getstr(in, parsed_value);
+ else
+ g_assert_not_reached();
+}
+
static void write_magic_children(FILE *stream, xmlNode *parent, int indent)
{
- int i;
+ GString *parsed_value;
xmlNode *node;
+ parsed_value = g_string_new(NULL);
+
for (node = parent->xmlChildrenNode; node; node = node->next)
{
- char *offset, *mask, *value;
+ char *offset, *mask, *value, *type;
+ char *parsed_mask = NULL;
+ const char *colon;
+ int word_size = 1;
+ long range_start;
+ int range_length = 1;
+ int i;
if (node->type != XML_ELEMENT_NODE)
continue;
@@ -489,23 +663,62 @@ static void write_magic_children(FILE *stream, xmlNode *parent, int indent)
offset = xmlGetNsProp(node, "offset", NULL);
mask = xmlGetNsProp(node, "mask", NULL);
value = xmlGetNsProp(node, "value", NULL);
+ type = xmlGetNsProp(node, "type", NULL);
+
+ g_return_if_fail(offset != NULL);
+ g_return_if_fail(value != NULL);
+ g_return_if_fail(type != NULL);
+
+ range_start = atol(offset);
+ colon = strchr(offset, ':');
+ if (colon)
+ range_length = atol(colon + 1) - range_start + 1;
+
+ if (strcmp(type, "host16") == 0)
+ word_size = 2;
+ else if (strcmp(type, "host32") == 0)
+ word_size = 4;
+ else if (strcmp(type, "big16") && strcmp(type, "big32") &&
+ strcmp(type, "little16") && strcmp(type, "little32") &&
+ strcmp(type, "string") && strcmp(type, "byte"))
+ g_warning("Unknown magic type '%s'\n", type);
+
+ g_string_truncate(parsed_value, 0);
+ parse_value(type, value, parsed_value);
if (mask)
- fprintf(stream, "%s\t%s&%s\t%s",
- offset,
- node->name,
- mask,
- value);
- else
- fprintf(stream, "%s\t%s\t%s",
- offset,
- node->name,
- value);
- g_free(offset);
+ {
+ int i;
+ parsed_mask = g_malloc(parsed_value->len);
+ for (i = 0; i < parsed_value->len; i++)
+ parsed_mask[i] = 0xff;
+ /* TODO: Actually read the mask! */
+ }
+
+ write32(stream, range_start);
+ write16(stream, parsed_value->len);
+ fwrite(parsed_value->str, parsed_value->len, 1, stream);
+ if (parsed_mask)
+ {
+ fputc('&', stream);
+ fwrite(parsed_mask, parsed_value->len, 1, stream);
+ }
+ if (word_size != 1)
+ fprintf(stream, "~%d", word_size);
+ if (range_length != 1)
+ fprintf(stream, "+%d", range_length);
fputc('\n', stream);
+
+ g_free(offset);
+ g_free(mask);
+ g_free(value);
+ g_free(type);
+
write_magic_children(stream, node, indent + 1);
}
+
+ g_string_free(parsed_value, TRUE);
}
static void write_magic(FILE *stream, xmlNode *node)
@@ -547,13 +760,16 @@ static void delete_old_types(const gchar *mime_dir)
if (l < 4 || strcmp(ent->d_name + l - 4, ".xml") != 0)
continue;
- type_name = g_strconcat(media_types[i], "/", ent->d_name, NULL);
+ type_name = g_strconcat(media_types[i], "/",
+ ent->d_name, NULL);
type_name[strlen(type_name) - 4] = '\0';
if (!g_hash_table_lookup(types, type_name))
{
char *path;
- path = g_strconcat(mime_dir, "/", type_name, ".xml", NULL);
- g_print("* Removing old info for type %s\n", path);
+ path = g_strconcat(mime_dir, "/",
+ type_name, ".xml", NULL);
+ g_print("* Removing old info for type %s\n",
+ path);
unlink(path);
g_free(path);
}
@@ -641,15 +857,14 @@ int main(int argc, char **argv)
{
FILE *stream;
char *magic_path;
- int i;
+ int i;
magic_path = g_strconcat(mime_dir, "/magic", NULL);
stream = fopen(magic_path, "wb");
if (!stream)
g_error("Failed to open '%s' for writing\n", magic_path);
g_free(magic_path);
- fprintf(stream,
- "# This file was automatically generated by the\n"
- "# update-mime-database command. DO NOT EDIT!\n");
+ fwrite("MIME-Magic\0\n", 1, 12, stream);
+
if (magic->len)
g_ptr_array_sort(magic, cmp_magic);
for (i = 0; i < magic->len; i++)