ref: 4a7f42e378e27bf70c928b411ac859c870c23f24
dir: /examples/readtags.c/
#include <stdio.h> #include <stdbool.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include "tags.h" #define USED(x) (void)x typedef struct Aux Aux; struct Aux { int fd; }; static const char *t2s[] = { [Talbum] = "album", [Talbumartist] = "albumartist", [Talbumgain] = "albumgain", [Talbumpeak] = "albumpeak", [Tartist] = "artist", [Tcomment] = "comment", [Tcomposer] = "composer", [Tdate] = "date", [Tgenre] = "genre", [Timage] = "image", [Ttitle] = "title", [Ttrack] = "track", [Ttrackgain] = "trackgain", [Ttrackpeak] = "trackpeak", }; static bool image; static const char * imagetype(int type) { static const char *types[] = { [ITother] = "Other", [IT32x32_file_icon] = "32x32 pixels 'file icon' (PNG only)", [ITother_file_icon] = "Other file icon", [ITcover_front] = "Cover (front)", [ITcover_back] = "Cover (back)", [ITleaflet] = "Leaflet page", [ITmedia] = "Media (e.g. label side of CD)", [ITlead] = "Lead artist/lead performer/soloist", [ITartist] = "Artist/performer", [ITconductor] = "Conductor", [ITband] = "Band/orchestra", [ITcomposer] = "Composer", [ITlyricist] = "Lyricist/text writer", [ITlocation] = "Recording location", [ITrecording] = "During recording", [ITperformance] = "During performance", [ITmovie_capture] = "Movie/video screen capture", [ITfish] = "A bright coloured fish", [ITillustration] = "Illustration", [ITlogo_band] = "Band/artist logotype", [ITlogo_publisher] = "Publisher/studio logotype", }; return type >= 0 && type < ITnum ? types[type] : "???"; } static void tag(Tagctx *ctx, int type, Tag *tag) { if(image){ if(type != Timage) return; int size = tag->image.size; char *raw = malloc(size); Aux *aux = ctx->aux; int prevoffset = lseek(aux->fd, 0, 1); if(lseek(aux->fd, tag->image.offset, 0) != tag->image.offset || read(aux->fd, raw, size) != size || (tag->image.decode != NULL && tag->image.decode(raw, &size) != 0)){ fprintf(stderr, "failed to read the image\n"); exit(1); } lseek(aux->fd, prevoffset, 0); write(1, raw, size); exit(0); return; } if(type == Timage) printf("%-12s %s %d %d (%s)\n", t2s[type], tag->image.mime, tag->image.offset, tag->image.size, imagetype(tag->image.type)); else printf("%-12s %s\n", type == Tunknown ? tag->text.k : t2s[type], tag->text.v); } static void toc(Tagctx *ctx, int ms, int offset) { USED(ctx); if(!image) printf("toc %-8d %-12d\n", ms, offset); } static int ctxread(Tagctx *ctx, void *buf, int cnt) { Aux *aux = ctx->aux; return read(aux->fd, buf, cnt); } static int ctxseek(Tagctx *ctx, int offset, int whence) { Aux *aux = ctx->aux; return lseek(aux->fd, offset, whence); } int main(int argc, char **argv) { int i; char buf[256], *argv0; Aux aux; Tagctx ctx = { .read = ctxread, .seek = ctxseek, .tag = tag, .toc = toc, .buf = buf, .bufsz = sizeof(buf), .aux = &aux, }; argv0 = argv[0]; if(argc > 1 && strcmp(argv[1], "-i") == 0){ image = true; argc--; argv++; } if(argc < 2){ fprintf(stderr, "usage: %s [-i] FILE...\n", argv0); return 1; } for(i = 1; i < argc; i++){ if(!image) printf("*** %s\n", argv[i]); if((aux.fd = open(argv[i], O_RDONLY)) < 0) perror("failed to open"); else{ if(tagsget(&ctx) != 0){ fprintf(stderr, "no tags or failed to read tags\n"); }else if(image){ fprintf(stderr, "no images found\n"); return 1; }else{ if(ctx.duration > 0) printf("%-12s %d ms\n", "duration", ctx.duration); if(ctx.samplerate > 0) printf("%-12s %d\n", "samplerate", ctx.samplerate); if(ctx.channels > 0) printf("%-12s %d\n", "channels", ctx.channels); if(ctx.bitrate > 0) printf("%-12s %d\n", "bitrate", ctx.bitrate); } close(aux.fd); } if(i+1 < argc) printf("\n"); } return 0; }