19 #include <glib/gprintf.h> 26 static GList *magic_list, *ext_list;
28 #define SWAP16(v, endian) \ 29 if (endian == G_LITTLE_ENDIAN) { \ 30 v = GUINT16_TO_LE (v); \ 31 } else if (endian == G_BIG_ENDIAN) { \ 32 v = GUINT16_TO_BE (v); \ 35 #define SWAP32(v, endian) \ 36 if (endian == G_LITTLE_ENDIAN) { \ 37 v = GUINT32_TO_LE (v); \ 38 } else if (endian == G_BIG_ENDIAN) { \ 39 v = GUINT32_TO_BE (v); \ 42 #define CMP(v1, entry, v2) \ 43 if (entry->pre_test_and_op) { \ 44 v1 &= entry->pre_test_and_op; \ 47 switch (entry->oper) { \ 48 case XMMS_MAGIC_ENTRY_OPERATOR_EQUAL: \ 50 case XMMS_MAGIC_ENTRY_OPERATOR_LESS_THAN: \ 52 case XMMS_MAGIC_ENTRY_OPERATOR_GREATER_THAN: \ 54 case XMMS_MAGIC_ENTRY_OPERATOR_AND: \ 55 return (v1 & v2) == v2; \ 56 case XMMS_MAGIC_ENTRY_OPERATOR_NAND: \ 57 return (v1 & v2) != v2; \ 77 typedef struct xmms_magic_entry_St {
82 guint pre_test_and_op;
93 typedef struct xmms_magic_checker_St {
102 typedef struct xmms_magic_ext_data_St {
107 static void xmms_magic_tree_free (GNode *tree);
110 static guint xmms_magic_complexity (GNode *tree);
119 parse_type (gchar **s, gint *endian)
138 for (t = types; t; t++) {
139 int l = t->string ? strlen (t->string) : 0;
141 if (!l || !strncmp (*s, t->string, l)) {
149 g_assert_not_reached ();
154 parse_oper (gchar **s)
169 for (o = opers; o; o++) {
173 }
else if (c == o->c) {
179 g_assert_not_reached ();
185 gboolean ret = FALSE;
192 switch (entry->type) {
198 entry->pre_test_and_op = strtoul (*end, end, 0);
209 parse_entry (
const gchar *s)
215 entry->endian = G_BYTE_ORDER;
217 entry->offset = strtoul (s, &end, 0);
221 entry->type = parse_type (&end, &entry->endian);
227 if (!parse_pre_test_and_op (entry, &end)) {
233 switch (entry->type) {
238 entry->oper = parse_oper (&end);
242 switch (entry->type) {
244 entry->value.i8 = strtoul (end, &end, 0);
248 entry->value.i16 = strtoul (end, &end, 0);
252 entry->value.i32 = strtoul (end, &end, 0);
257 g_strlcpy (entry->value.s, end, sizeof (entry->value.s));
258 entry->len = strlen (entry->value.s);
270 if (G_NODE_IS_ROOT (node)) {
271 gpointer *data = node->data;
278 xmms_magic_entry_free (entry);
285 xmms_magic_tree_free (GNode *tree)
287 g_node_traverse (tree, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
288 (GNodeTraverseFunc) free_node, NULL);
292 xmms_magic_add_node (GNode *tree,
const gchar *s, GNode *prev_node)
295 gpointer *data = tree->data;
296 guint indent = 0, prev_indent;
300 XMMS_DBG (
"adding magic spec to tree '%s'", (gchar *) data[0]);
308 entry = parse_entry (s);
310 XMMS_DBG (
"cannot parse magic entry");
315 return g_node_append_data (tree, entry);
320 xmms_magic_entry_free (entry);
324 prev_indent = g_node_depth (prev_node) - 2;
326 if (indent > prev_indent) {
328 if (indent != prev_indent + 1) {
330 xmms_magic_entry_free (entry);
334 return g_node_append_data (prev_node, entry);
336 while (indent < prev_indent) {
338 prev_node = prev_node->parent;
341 return g_node_insert_after (prev_node->parent, prev_node,
351 if (needed > c->alloc) {
353 c->buf = g_realloc (c->buf, c->alloc);
356 xmms_error_reset (&e);
365 guint needed = c->offset + entry->offset + entry->len;
375 if (c->read < needed) {
376 tmp = read_data (c, needed);
382 if (c->read < needed) {
388 ptr = &c->buf[c->offset + entry->offset];
390 switch (entry->type) {
392 memcpy (&i8, ptr,
sizeof (i8));
393 CMP (i8, entry, entry->value.i8);
395 memcpy (&i16, ptr,
sizeof (i16));
396 SWAP16 (i16, entry->endian);
397 CMP (i16, entry, entry->value.i16);
399 memcpy (&i32, ptr,
sizeof (i32));
400 SWAP32 (i32, entry->endian);
401 CMP (i32, entry, entry->value.i32);
403 return !strncmp (ptr, entry->value.s, entry->len);
405 return !g_ascii_strncasecmp (ptr, entry->value.s, entry->len);
417 if (!tree->children) {
421 for (n = tree->children; n; n = n->next) {
422 if (node_match (c, n) && tree_match (c, n)) {
437 g_return_val_if_fail (c, NULL);
440 for (l = magic_list; l; l = g_list_next (l)) {
441 GNode *tree = l->data;
443 if (tree_match (c, tree)) {
444 gpointer *data = tree->data;
445 XMMS_DBG (
"magic plugin detected '%s' (%s)",
446 (
char *)data[1], (
char *)data[0]);
447 return (
char *) (data[1]);
454 u = g_ascii_strdown (uri, -1);
455 for (l = ext_list; l; l = g_list_next (l)) {
457 if (g_pattern_match_simple (e->pattern, u)) {
458 XMMS_DBG (
"magic plugin detected '%s' (by extension '%s')", e->type, e->pattern);
465 if (c->dumpcount > 0) {
466 dump = g_malloc ((
MIN (c->read, c->dumpcount) * 3) + 1);
469 XMMS_DBG (
"Magic didn't match anything...");
470 for (i = 0; i < c->dumpcount && i < c->read; i++) {
471 g_sprintf (u,
"%02X ", (
unsigned char)c->buf[i]);
483 xmms_magic_complexity (GNode *tree)
485 return g_node_n_nodes (tree, G_TRAVERSE_ALL);
489 cb_sort_magic_list (GNode *a, GNode *b)
493 n1 = xmms_magic_complexity (a);
494 n2 = xmms_magic_complexity (b);
498 }
else if (n1 < n2) {
511 g_return_val_if_fail (mime, FALSE);
512 g_return_val_if_fail (ext, FALSE);
515 e->pattern = g_strdup (ext);
516 e->type = g_strdup (mime);
518 ext_list = g_list_prepend (ext_list, e);
526 GNode *tree, *node = NULL;
529 gpointer *root_props;
532 g_return_val_if_fail (desc, FALSE);
533 g_return_val_if_fail (mime, FALSE);
538 s = va_arg (ap, gchar *);
545 root_props = g_new0 (gpointer, 2);
546 root_props[0] = g_strdup (desc);
547 root_props[1] = g_strdup (mime);
548 tree = g_node_new (root_props);
558 node = xmms_magic_add_node (tree, s, node);
566 }
while ((s = va_arg (ap, gchar *)));
573 g_list_insert_sorted (magic_list, tree,
574 (GCompareFunc) cb_sort_magic_list);
576 xmms_magic_tree_free (tree);
591 c.read = c.offset = 0;
593 c.buf = g_malloc (c.alloc);
600 res = xmms_magic_match (&c, url);
620 methods.
init = xmms_magic_plugin_init;
628 "application/octet-stream",
638 "Magic file identifier",
640 "Magic file identifier",
641 xmms_magic_plugin_setup);
struct xmms_magic_entry_St xmms_magic_entry_t
enum xmms_magic_entry_type_St xmms_magic_entry_type_t
XMMS_XFORM_BUILTIN(magic, "Magic file identifier", XMMS_VERSION, "Magic file identifier", xmms_magic_plugin_setup)
gint xmms_config_property_get_int(const xmms_config_property_t *prop)
Return the value of a config property as an int.
struct xmms_magic_ext_data_St xmms_magic_ext_data_t
#define xmms_log_error(fmt,...)
enum xmms_magic_entry_operator_St xmms_magic_entry_operator_t
#define CMP(v1, entry, v2)
#define SWAP32(v, endian)
#define XMMS_DBG(fmt,...)
struct xmms_magic_checker_St xmms_magic_checker_t
G_BEGIN_DECLS struct xmms_error_St xmms_error_t
struct xmms_config_property_St xmms_config_property_t
xmms_magic_entry_operator_St
#define SWAP16(v, endian)