Enlightenment CVS committal Author : raster Project : e17 Module : libs/imlib2
Dir : e17/libs/imlib2/src/modules/loaders Modified Files: loader_id3.c Log Message: ramkumar's id3 updates =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/imlib2/src/modules/loaders/loader_id3.c,v retrieving revision 1.2 retrieving revision 1.3 diff -u -3 -r1.2 -r1.3 --- loader_id3.c 24 Jul 2005 16:35:17 -0000 1.2 +++ loader_id3.c 9 Aug 2005 09:11:02 -0000 1.3 @@ -9,31 +9,286 @@ #include <fcntl.h> #include <assert.h> #include <errno.h> +#include <limits.h> #include "image.h" #include <id3tag.h> -int extract_pic (struct id3_frame* frame, int dest, char* ext, int extlen) +#if ! defined (__STDC_VERSION__) || __STDC_VERSION__ < 199901L +# if __GNUC__ >= 2 +# define inline __inline__ +# else +# define inline +# endif +#endif + +#ifdef __GNUC__ +# define UNLIKELY(exp) __builtin_expect ((exp), 0) +#else +# define UNLIKELY(exp) (exp) +#endif + +typedef struct context +{ + int id; + char* filename; + struct id3_tag* tag; + int refcount; + struct context* next; +} context; + +static context* id3_ctxs = NULL; + +static inline struct id3_frame* +id3_tag_get_frame (struct id3_tag* tag, size_t index) +{ + return tag->frames[index]; +} + +static inline size_t id3_tag_get_numframes (struct id3_tag* tag) +{ + return tag->nframes; +} + +static inline char const* id3_frame_id (struct id3_frame* frame) +{ + return frame->id; +} + +static context* context_create (const char* filename) +{ + context* node = (context*) malloc (sizeof (context)); + context *ptr, *last; + int last_id = INT_MAX; + node->refcount = 1; + { + struct id3_file* file; + struct id3_tag* tag; + unsigned int i; + file = id3_file_open (filename, ID3_FILE_MODE_READONLY); + if (! file) { + fprintf (stderr, "Unable to open tagged file %s: %s\n", + filename, strerror (errno)); + id3_file_close (file); + goto fail_free; + } + tag = id3_file_tag (file); + if (! tag) { + fprintf (stderr, + "Unable to find ID3v2 tags in file %s\n", + filename); + id3_file_close (file); + goto fail_free; + } + node->tag = id3_tag_new (); + for (i = 0; i < id3_tag_get_numframes (tag); i ++) + if (! strcmp (id3_frame_id + (id3_tag_get_frame (tag, i)), "APIC")) + id3_tag_attachframe (node->tag, + id3_tag_get_frame (tag, i)); + id3_file_close (file); + } + node->filename = strdup (filename); + if (! id3_ctxs) { + node->id = 1; + node->next = NULL; + id3_ctxs = node; + return node; + } + ptr = id3_ctxs; + last = NULL; + while (UNLIKELY (ptr && (ptr->id + 1) >= last_id)) { + last_id = ptr->id; + last = ptr; + ptr = ptr->next; + } + /* Paranoid! this can occur only if there are INT_MAX contexts :) */ + if (UNLIKELY (ptr == NULL)) { + fprintf (stderr, "Too many open ID3 contexts\n"); + goto fail_close; + } + node->id = ptr->id + 1; + if (UNLIKELY (last != NULL)) { + node->next = last->next; + last->next = node; + } else { + node->next = id3_ctxs; + id3_ctxs = node; + } + return node; + +fail_close: + free (node->filename); + id3_tag_delete (node->tag); +fail_free: + free (node); + return NULL; +} + +static void context_destroy (context* ctx) +{ + id3_tag_delete (ctx->tag); + free (ctx->filename); + free (ctx); +} + +static inline void context_addref (context* ctx) +{ + ctx->refcount ++; +} + +static context* context_get (int id) +{ + context* ptr = id3_ctxs; + while (ptr) { + if (ptr->id == id) { + context_addref (ptr); + return ptr; + } + ptr = ptr->next; + } + fprintf (stderr, "No context by handle %d found\n", id); + return NULL; +} + +static context* context_get_by_name (const char* name) +{ + context* ptr = id3_ctxs; + while (ptr) { + if (! strcmp (name, ptr->filename)) { + context_addref (ptr); + return ptr; + } + ptr = ptr->next; + } + return NULL; +} + +static void context_delref (context* ctx) +{ + ctx->refcount --; + if (ctx->refcount <= 0) { + context *last = NULL, *ptr = id3_ctxs; + while (ptr) { + if (ptr == ctx) { + if (last) + last->next = ctx->next; + else + id3_ctxs = ctx->next; + context_destroy (ctx); + return; + } + last = ptr; + ptr = ptr->next; + } + } +} + +static int str2int (char* str, int old) +{ + long index; + errno = 0; + index = strtol (str, NULL, 10); + return ((errno || index > INT_MAX) ? old : (int)index); +} + +static size_t str2uint (char* str, size_t old) +{ + unsigned long index; + errno = 0; + index = strtoul (str, NULL, 10); + return ((errno || index > UINT_MAX) ? old : (size_t)index); +} + +static void destructor_data (ImlibImage* im, void* data) +{ + free (data); +} + +static void destructor_context (ImlibImage* im, void* data) +{ + context_delref ((context*)data); +} + +typedef struct lopt +{ + context* ctx; + size_t index; + int traverse; + char cache_level; +} lopt; + +static char get_options (lopt* opt, ImlibImage* im) +{ + size_t handle = 0, index = 0, traverse = 0; + context* ctx; + + if (im->key) { + char* key = strdup (im->key); + char* tok = strtok (key, ","); + traverse = 0; + while (tok) { + char* value = strchr (tok, '='); + if (! value) { + value = tok; + tok = "index"; + } else { + *value = '\0'; + value ++; + } + if (! strcasecmp (tok, "index")) + index = str2uint (value, index); + else if (! strcasecmp (tok, "context")) + handle = str2uint (value, handle); + else if (! strcasecmp (tok, "traverse")) + traverse = str2int (value, traverse); + tok = strtok (NULL, ","); + } + free (key); + } else + traverse = 1; + + if (! handle) { + ImlibImageTag* htag = __imlib_GetTag (im, "context"); + if (htag && htag->val) + handle = htag->val; + } + if (handle) + ctx = context_get (handle); + else if (! (ctx = context_get_by_name (im->real_file)) && + ! (ctx = context_create (im->real_file))) + return 0; + + if (! index) { + ImlibImageTag* htag = __imlib_GetTag (im, "index"); + if (htag && htag->val) + index = htag->val; + } + if (index < 0 || index > id3_tag_get_numframes (ctx->tag) || + (index == 0 && id3_tag_get_numframes (ctx->tag) < 1)) { + if (index) + fprintf (stderr, "No picture frame # %d found\n", index); + context_delref (ctx); + return 0; + } + if (! index) + index = 1; + + opt->ctx = ctx; + opt->index = index; + opt->traverse = traverse; + opt->cache_level = (id3_tag_get_numframes (ctx->tag) > 1 ? 1 : 0); + return 1; +} + +static int extract_pic (struct id3_frame* frame, int dest) { union id3_field* field; unsigned char const * data; long length; int done = 0; - field = id3_frame_field (frame, 1); - data = id3_field_getlatin1 (field); - if (! data) { - fprintf (stderr, "No mime type data found for image frame\n"); - return 0; - } - if (strncmp (data, "image/", 6)) { - fprintf (stderr, - "Picture frame with unknown mime-type %s found\n", - data); - return 0; - } - strncpy (ext, data + 6, extlen); field = id3_frame_field (frame, 4); data = id3_field_getbinarydata (field, &length); if (! data) { @@ -54,85 +309,229 @@ return 1; } -/* Loader for ID3v2 tags in audio files. - * ID3v2 allows for 'Attached Picture' frames to be embedded in the file. - * A numeric key is supported, and indicates the zero-based frame index - * to be extracted, in case more than one such frame is found. - * Defaults to 0, or the first picture frame. - */ -char load (ImlibImage *im, ImlibProgressFunction progress, - char progress_granularity, char immediate_load) -{ - ImlibLoader *loader; - char *file, tmp[] = "/tmp/imlib2_loader_id3-XXXXXX", *p; - char real_ext[16]; - int res, dest, pic_index = 0; - struct id3_file* tagfile; - struct id3_tag* tag; - struct id3_frame* frame; - - assert (im); +#define EXT_LEN 14 - p = strrchr(im->real_file, '.'); - if (! (p && p != im->real_file && !strcmp (p + 1, "mp3"))) { - return 0; - } +static char get_loader (lopt* opt, ImlibLoader** loader) +{ + union id3_field* field; + unsigned char const * data; + char ext[EXT_LEN + 2]; - if (im->key) - pic_index = atoi (im->key); + ext[EXT_LEN + 1] = '\0'; + ext[0] = '.'; - tagfile = id3_file_open (im->real_file, ID3_FILE_MODE_READONLY); - if (! tagfile) { - fprintf (stderr, "Unable to open tagged file %s: %s", - im->real_file, strerror (errno)); + field = id3_frame_field (id3_tag_get_frame (opt->ctx->tag, + opt->index - 1), 1); + data = id3_field_getlatin1 (field); + if (! data) { + fprintf (stderr, "No mime type data found for image frame\n"); return 0; } - tag = id3_file_tag (tagfile); - if (! tag) { - fprintf (stderr, "Unable to find ID3v2 tags in file\n"); + if (strncasecmp (data, "image/", 6)) { + if (! strcmp (data, "-->")) { + *loader = NULL; + return 1; + } + fprintf (stderr, + "Picture frame with unknown mime-type \'%s\' found\n", + data); return 0; } - frame = id3_tag_findframe (tag, "APIC", pic_index); - if (! frame) { - fprintf (stderr, "No picture frame # %d found\n", pic_index); + strncpy (ext + 1, data + 6, EXT_LEN); + if (! (*loader = __imlib_FindBestLoaderForFile (ext, 0))) { + fprintf (stderr, "No loader found for extension %s\n", ext); return 0; } + return 1; +} - if ((dest = mkstemp (tmp)) < 0) { - fprintf (stderr, "Unable to create a temporary file\n"); - id3_file_close (tagfile); - return 0; +static char* id3_pic_types [] = { + /* $00 */ "Other", + /* $01 */ "32x32 pixels file icon", + /* $02 */ "Other file icon", + /* $03 */ "Cover (front)", + /* $04 */ "Cover (back)", + /* $05 */ "Leaflet page", + /* $06 */ "Media", + /* $07 */ "Lead artist/lead performer/soloist", + /* $08 */ "Artist/performer", + /* $09 */ "Conductor", + /* $0A */ "Band/Orchestra", + /* $0B */ "Composer", + /* $0C */ "Lyricist/text writer", + /* $0D */ "Recording Location", + /* $0E */ "During recording", + /* $0F */ "During performance", + /* $10 */ "Movie/video screen capture", + /* $11 */ "A bright coloured fish", + /* $12 */ "Illustration", + /* $13 */ "Band/artist logotype", + /* $14 */ "Publisher/Studio logotype" +}; + +static char* id3_text_encodings [] = { + /* $00 */ "ISO-8859-1", + /* $01 */ "UTF-16 encoded Unicode with BOM", + /* $02 */ "UTF-16BE encoded Unicode without BOM", + /* $03 */ "UTF-8 encoded Unicode" +}; + +static void write_tags (ImlibImage* im, lopt* opt) +{ + struct id3_frame* frame + = id3_tag_get_frame (opt->ctx->tag, opt->index - 1); + union id3_field* field; + int num_data; + char* data; + + if ((field = id3_frame_field (frame, 1)) && + (data = (char*) id3_field_getlatin1 (field))) + __imlib_AttachTag (im, "mime-type", 0, + strdup (data), destructor_data); + if ((field = id3_frame_field (frame, 3)) && + (data = (char*) id3_field_getstring (field))) { + size_t length; + char* dup; + id3_ucs4_t* ptr = (id3_ucs4_t*)data; + while (*ptr) + ptr ++; + length = (ptr - (id3_ucs4_t*)data + 1) * sizeof (id3_ucs4_t); + dup = (char*) malloc (length); + memcpy (dup, data, length); + __imlib_AttachTag (im, "id3-description", 0, + dup, destructor_data); + } + if (field = id3_frame_field (frame, 0)) + __imlib_AttachTag (im, "id3-description-text-encoding", + (num_data = (int) + id3_field_gettextencoding (field)), + num_data < sizeof (id3_text_encodings) ? + id3_text_encodings[num_data] : NULL, NULL); + if (field = id3_frame_field (frame, 2)) + __imlib_AttachTag (im, "id3-picture-type", + (num_data = id3_field_getint (field)), + num_data < sizeof (id3_pic_types) ? + id3_pic_types[num_data] : NULL, NULL); + __imlib_AttachTag (im, "count", id3_tag_get_numframes (opt->ctx->tag), + NULL, NULL); + if (opt->cache_level) { + context_addref (opt->ctx); + __imlib_AttachTag (im, "context", opt->ctx->id, + opt->ctx, destructor_context); + } + __imlib_AttachTag (im, "index", opt->index, NULL, NULL); + if (opt->traverse) { + char* buf = NULL; + if ((opt->index + opt->traverse) + <= id3_tag_get_numframes (opt->ctx->tag) + && (opt->index + opt->traverse) > 0) { + buf = (char*) malloc + ((strlen (im->real_file) + 50) * sizeof (char)); + sprintf (buf, "%s:index=%d,traverse=%d", im->real_file, + opt->index + opt->traverse, opt->traverse); + } + __imlib_AttachTag (im, "next", 0, buf, destructor_data); } +} - real_ext[15] = '\0'; - real_ext[0] = '.'; - res = extract_pic (frame, dest, real_ext + 1, 14); - close (dest); - id3_file_close (tagfile); +char load (ImlibImage *im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load) +{ + ImlibLoader *loader; + lopt opt; + int res; - if (!res) { - unlink (tmp); + assert (im); + if (! get_options (&opt, im)) return 0; - } - if (!(loader = __imlib_FindBestLoaderForFile (real_ext, 0))) { - fprintf (stderr, "No loader found for extension %s\n", real_ext); + if (! get_loader (&opt, &loader)) + goto fail_context; + + if (loader) { + char *ofile, tmp[] = "/tmp/imlib2_loader_id3-XXXXXX"; + int dest; + + if ((dest = mkstemp (tmp)) < 0) { + fprintf (stderr, "Unable to create a temporary file\n"); + goto fail_context; + } + res = extract_pic (id3_tag_get_frame (opt.ctx->tag, + opt.index - 1), dest); + close (dest); + + if (! res) { + unlink (tmp); + goto fail_context; + } + + ofile = im->real_file; + im->real_file = strdup (tmp); + res = loader->load (im, progress, + progress_granularity, immediate_load); + free (im->real_file); + im->real_file = ofile; + unlink (tmp); - return 0; + } else { + /* The tag actually provides a image url rather than image data. + * Practically, dunno if such a tag exists on earth :) + * Here's the code anyway... + */ + union id3_field* field; + long length; + char const* data; + char *url, *file, *ofile; + + field = id3_frame_field + (id3_tag_get_frame (opt.ctx->tag, opt.index - 1), 4); + data = (char const*) id3_field_getbinarydata (field, &length); + if (! data || ! length) { + fprintf (stderr, "No link image URL present\n"); + goto fail_context; + } + url = (char*) malloc ((length + 1) * sizeof (char)); + strncpy (url, data, length); + url[length] = '\0'; + file = (strncmp (url, "file://", 7) ? url : url + 7); + if (! (loader = __imlib_FindBestLoaderForFile (file, 0))) { + fprintf (stderr, "No loader found for file %s\n", file); + free (url); + goto fail_context; + } + ofile = im->real_file; + im->real_file = file; + res = loader->load (im, progress, + progress_granularity, immediate_load); + if (! im->loader) + __imlib_AttachTag (im, "id3-link-url", 0, + url, destructor_data); + else + free (url); + im->real_file = ofile; + } + + if (! im->loader) + write_tags (im, &opt); + +#ifdef DEBUG + if (! im->loader) { + ImlibImageTag* cur = im->tags; + fprintf (stderr, "Tags for file %s:\n", im->file); + while (cur) { + fprintf (stderr, "\t%s: (%d) %s\n", cur->key, + cur->val, (char*) cur->data); + cur = cur->next; + } } +#endif - /* remember the original filename */ - file = strdup (im->real_file); - - free (im->real_file); - im->real_file = strdup (tmp); - loader->load (im, progress, progress_granularity, immediate_load); - - free (im->real_file); - im->real_file = file; - unlink (tmp); + context_delref (opt.ctx); + return res; - return 1; +fail_context: + context_delref (opt.ctx); + return 0; } void formats (ImlibLoader *l) ------------------------------------------------------- SF.Net email is Sponsored by the Better Software Conference & EXPO September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf _______________________________________________ enlightenment-cvs mailing list enlightenment-cvs@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/enlightenment-cvs