ref: 5d5b02ab50f08d12ad930e18c69ba2a2b852e547
parent: d8185e7273233384dcf32da043c28446082df1d2
author: Sigrid Solveig Haflínudóttir <ftrvxmtrx@gmail.com>
date: Wed Dec 18 15:20:24 EST 2019
change callback api to include raw "key" of the tag, add Tunknown type. this allows programs to read ALL text tags
--- a/README.md
+++ b/README.md
@@ -38,4 +38,4 @@
Just compile it to an archive (`.a`) and link to your program. Use it in your code
by including `tags.h`, that's the API. Documentation is in the header.
-See `examples/readtags.c`.
+See `examples/readtags.c`. You can compile like so: `gcc examples/readtags.c src/*.c -Isrc -o readtags`.
--- a/default.nix
+++ /dev/null
@@ -1,22 +1,0 @@
-{ stdenv, mk, pkgconfig, fetchgitLocal }:
-
-stdenv.mkDerivation rec {
- name = "libtags";
- src = ./.;#fetchgitLocal ./.;
-
- buildInputs = [ mk ];
- propagatedBuildInputs = [ pkgconfig ];
- enableParallelBuilding = true;
-
- installPhase = ''
- cd src && mk -f mkfile.nix install && cd ..
- cd examples && mk -f mkfile.nix install INCLUDES=-I$out/include LIBS="-L$out/lib -ltags"
- '';
-
- meta = {
- description = "A cross-platform library for reading tags, designed for highly constrained environments";
- maintainers = with stdenv.lib.maintainers; [ ftrvxmtrx ];
- platforms = stdenv.lib.platforms.unix;
- license = stdenv.lib.licenses.mit;
- };
-}
--- a/examples/readtags.c
+++ b/examples/readtags.c
@@ -38,12 +38,12 @@
};
static void
-cb(Tagctx *ctx, int t, const char *v, int offset, int size, Tagread f)
+cb(Tagctx *ctx, int t, const char *k, const char *v, int offset, int size, Tagread f)
{
- USED(ctx); USED(offset); USED(size); USED(f);
+ USED(ctx); USED(k); USED(f);
if(t == Timage)
print("%-12s %s %d %d\n", t2s[t], v, offset, size);
- else
+ else if(t != Tunknown)
print("%-12s %s\n", t2s[t], v);
}
--- a/src/flac.c
+++ b/src/flac.c
@@ -51,7 +51,7 @@
offset = beuint(d) + ctx->seek(ctx, 0, 1) + 20;
ctx->read(ctx, d, 20);
n = beuint(&d[16]);
- tagscallcb(ctx, Timage, mime, offset, n, nil);
+ tagscallcb(ctx, Timage, "", mime, offset, n, nil);
}else if((d[0] & 0x7f) == 4){ /* 4 = vorbis comment */
int i, numtags, tagsz, vensz;
char *k, *v;
--- a/src/id3v1.c
+++ b/src/id3v1.c
@@ -26,23 +26,23 @@
return -1;
if((ctx->found & 1<<Ttitle) == 0 && iso88591toutf8(out, Outsz, &in[3], 30) > 0)
- txtcb(ctx, Ttitle, out);
+ txtcb(ctx, Ttitle, "", out);
if((ctx->found & 1<<Tartist) == 0 && iso88591toutf8(out, Outsz, &in[33], 30) > 0)
- txtcb(ctx, Tartist, out);
+ txtcb(ctx, Tartist, "", out);
if((ctx->found & 1<<Talbum) == 0 && iso88591toutf8(out, Outsz, &in[63], 30) > 0)
- txtcb(ctx, Talbum, out);
+ txtcb(ctx, Talbum, "", out);
in[93+4] = 0;
if((ctx->found & 1<<Tdate) == 0 && in[93] != 0)
- txtcb(ctx, Tdate, &in[93]);
+ txtcb(ctx, Tdate, "", &in[93]);
if((ctx->found & 1<<Ttrack) == 0 && in[125] == 0 && in[126] > 0){
snprint((char*)out, Outsz, "%d", in[126]);
- txtcb(ctx, Ttrack, out);
+ txtcb(ctx, Ttrack, "", out);
}
if((ctx->found & 1<<Tgenre) == 0 && in[127] < Numgenre)
- txtcb(ctx, Tgenre, id3genres[in[127]]);
+ txtcb(ctx, Tgenre, "", id3genres[in[127]]);
return 0;
}
--- a/src/id3v2.c
+++ b/src/id3v2.c
@@ -19,25 +19,25 @@
{
k++;
if(strcmp(k, "AL") == 0 || strcmp(k, "ALB") == 0)
- txtcb(ctx, Talbum, v);
+ txtcb(ctx, Talbum, k-1, v);
else if(strcmp(k, "PE1") == 0 || strcmp(k, "PE2") == 0 || strcmp(k, "P1") == 0 || strcmp(k, "P2") == 0)
- txtcb(ctx, Tartist, v);
+ txtcb(ctx, Tartist, k-1, v);
else if(strcmp(k, "IT2") == 0 || strcmp(k, "T2") == 0)
- txtcb(ctx, Ttitle, v);
+ txtcb(ctx, Ttitle, k-1, v);
else if(strcmp(k, "YE") == 0 || strcmp(k, "YER") == 0 || strcmp(k, "DRC") == 0)
- txtcb(ctx, Tdate, v);
+ txtcb(ctx, Tdate, k-1, v);
else if(strcmp(k, "RK") == 0 || strcmp(k, "RCK") == 0)
- txtcb(ctx, Ttrack, v);
+ txtcb(ctx, Ttrack, k-1, v);
else if(strcmp(k, "CO") == 0 || strcmp(k, "CON") == 0){
for(; v[0]; v++){
if(v[0] == '(' && v[1] <= '9' && v[1] >= '0'){
int i = atoi(&v[1]);
if(i < Numgenre)
- txtcb(ctx, Tgenre, id3genres[i]);
+ txtcb(ctx, Tgenre, k-1, id3genres[i]);
for(v++; v[0] && v[0] != ')'; v++);
v--;
}else if(v[0] != '(' && v[0] != ')'){
- txtcb(ctx, Tgenre, v);
+ txtcb(ctx, Tgenre, k-1, v);
break;
}
}
@@ -58,11 +58,12 @@
type = Talbumpeak;
}
if(type >= 0)
- txtcb(ctx, type, v+5);
+ txtcb(ctx, type, k-1, v+5);
else
return 0;
- }else
- return 0;
+ }else{
+ txtcb(ctx, Tunknown, k-1, v);
+ }
return 1;
}
@@ -98,11 +99,11 @@
peaks[sizeof(peaks)-1] = 0;
if(strcmp((char*)tag, "track") == 0){
- txtcb(ctx, Ttrackgain, vas);
- txtcb(ctx, Ttrackpeak, peaks);
+ txtcb(ctx, Ttrackgain, "RVA2", vas);
+ txtcb(ctx, Ttrackpeak, "RVA2", peaks);
}else if(strcmp((char*)tag, "album") == 0){
- txtcb(ctx, Talbumgain, vas);
- txtcb(ctx, Talbumpeak, peaks);
+ txtcb(ctx, Talbumgain, "RVA2", vas);
+ txtcb(ctx, Talbumpeak, "RVA2", peaks);
}
break;
}
@@ -171,7 +172,7 @@
break;
}
}
- tagscallcb(ctx, Timage, b, offset+n, tsz-n, f);
+ tagscallcb(ctx, Timage, "APIC", b, offset+n, tsz-n, f);
n = 256;
}
}else if(strcmp((char*)d, "PIC") == 0){
@@ -189,7 +190,7 @@
break;
}
}
- tagscallcb(ctx, Timage, strcmp(b, "JPG") == 0 ? "image/jpeg" : "image/png", offset+n, tsz-n, f);
+ tagscallcb(ctx, Timage, "PIC", strcmp(b, "JPG") == 0 ? "image/jpeg" : "image/png", offset+n, tsz-n, f);
n = 256;
}
}else if(strcmp((char*)d, "RVA2") == 0 && tsz >= 6+5){
--- a/src/m4a.c
+++ b/src/m4a.c
@@ -128,13 +128,13 @@
return -1;
sz -= 4;
snprint((char*)d, ctx->bufsz, "%d", beuint(d));
- txtcb(ctx, type, d);
+ txtcb(ctx, type, "", d);
}else if(type == Tgenre){
if(ctx->read(ctx, d, 2) != 2)
return -1;
sz -= 2;
if((i = d[1]-1) >= 0 && i < Numgenre)
- txtcb(ctx, type, id3genres[i]);
+ txtcb(ctx, type, "", id3genres[i]);
}else if(dtype == 1){ /* text */
if(sz >= ctx->bufsz) /* skip tags that can't fit into memory. ">=" because of '\0' */
continue;
@@ -141,12 +141,12 @@
if(ctx->read(ctx, d, sz) != sz)
return -1;
d[sz] = 0;
- txtcb(ctx, type, d);
+ txtcb(ctx, type, "", d);
sz = 0;
}else if(type == Timage && dtype == 13) /* jpeg cover image */
- tagscallcb(ctx, Timage, "image/jpeg", ctx->seek(ctx, 0, 1), sz, nil);
+ tagscallcb(ctx, Timage, "", "image/jpeg", ctx->seek(ctx, 0, 1), sz, nil);
else if(type == Timage && dtype == 14) /* png cover image */
- tagscallcb(ctx, Timage, "image/png", ctx->seek(ctx, 0, 1), sz, nil);
+ tagscallcb(ctx, Timage, "", "image/png", ctx->seek(ctx, 0, 1), sz, nil);
}
return 0;
--- a/src/tags.c
+++ b/src/tags.c
@@ -26,11 +26,13 @@
};
void
-tagscallcb(Tagctx *ctx, int type, const char *s, int offset, int size, Tagread f)
+tagscallcb(Tagctx *ctx, int type, const char *k, const char *s, int offset, int size, Tagread f)
{
- ctx->found |= 1<<type;
- ctx->tag(ctx, type, s, offset, size, f);
- ctx->num++;
+ if(type != Tunknown){
+ ctx->found |= 1<<type;
+ ctx->num++;
+ }
+ ctx->tag(ctx, type, k, s, offset, size, f);
}
int
--- a/src/tags.h
+++ b/src/tags.h
@@ -8,6 +8,7 @@
/* Tag type. */
enum
{
+ Tunknown = -1,
Tartist,
Talbum,
Ttitle,
@@ -43,13 +44,14 @@
int (*seek)(Tagctx *ctx, int offset, int whence);
/* Callback that is used by libtags to inform about the tags of a file.
- * "type" is the tag's type (Tartist, ...). "s" is the null-terminated string unless "type" is
+ * "type" is the tag's type (Tartist, ...) or Tunknown if libtags doesn't know how to map a tag kind to
+ * any of these. "k" is the raw key like "TPE1", "TPE2", etc. "s" is the null-terminated string unless "type" is
* Timage. "offset" and "size" define the placement and size of the image cover ("type" = Timage)
* inside the file, and "f" is not NULL in case reading the image cover requires additional
* operations on the data, in which case you need to read the image cover as a stream and call this
* function to apply these operations on the contents read.
*/
- void (*tag)(Tagctx *ctx, int type, const char *s, int offset, int size, Tagread f);
+ void (*tag)(Tagctx *ctx, int type, const char *k, const char *s, int offset, int size, Tagread f);
/* Auxiliary data. Not used by libtags. */
void *aux;
--- a/src/tagspriv.h
+++ b/src/tagspriv.h
@@ -44,6 +44,6 @@
*/
void cbvorbiscomment(Tagctx *ctx, char *k, char *v);
-void tagscallcb(Tagctx *ctx, int type, const char *s, int offset, int size, Tagread f);
+void tagscallcb(Tagctx *ctx, int type, const char *k, const char *s, int offset, int size, Tagread f);
-#define txtcb(ctx, type, s) tagscallcb(ctx, type, (const char*)s, 0, 0, nil)
+#define txtcb(ctx, type, k, s) tagscallcb(ctx, type, k, (const char*)s, 0, 0, nil)
--- a/src/vorbis.c
+++ b/src/vorbis.c
@@ -11,25 +11,27 @@
if(*v == 0)
return;
if(cistrcmp(k, "album") == 0)
- txtcb(ctx, Talbum, v);
+ txtcb(ctx, Talbum, k, v);
else if(cistrcmp(k, "title") == 0)
- txtcb(ctx, Ttitle, v);
+ txtcb(ctx, Ttitle, k, v);
else if(cistrcmp(k, "artist") == 0 || cistrcmp(k, "performer") == 0)
- txtcb(ctx, Tartist, v);
+ txtcb(ctx, Tartist, k, v);
else if(cistrcmp(k, "tracknumber") == 0)
- txtcb(ctx, Ttrack, v);
+ txtcb(ctx, Ttrack, k, v);
else if(cistrcmp(k, "date") == 0)
- txtcb(ctx, Tdate, v);
+ txtcb(ctx, Tdate, k, v);
else if(cistrcmp(k, "replaygain_track_peak") == 0)
- txtcb(ctx, Ttrackpeak, v);
+ txtcb(ctx, Ttrackpeak, k, v);
else if(cistrcmp(k, "replaygain_track_gain") == 0)
- txtcb(ctx, Ttrackgain, v);
+ txtcb(ctx, Ttrackgain, k, v);
else if(cistrcmp(k, "replaygain_album_peak") == 0)
- txtcb(ctx, Talbumpeak, v);
+ txtcb(ctx, Talbumpeak, k, v);
else if(cistrcmp(k, "replaygain_album_gain") == 0)
- txtcb(ctx, Talbumgain, v);
+ txtcb(ctx, Talbumgain, k, v);
else if(cistrcmp(k, "genre") == 0)
- txtcb(ctx, Tgenre, v);
+ txtcb(ctx, Tgenre, k, v);
+ else
+ txtcb(ctx, Tunknown, k, v);
}
int