shithub: libtags

ref: 4a7f42e378e27bf70c928b411ac859c870c23f24
dir: /examples/readtags.c/

View raw version
#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;
}