#include "../ebml.c" #define min(a,b) ((a)<=(b)?(a):(b)) static vlong stack[128]; static voidusage(void){ fprint(2, "usage: %s [-d] [-h hxsz] [file.mkv]\n", argv0); exits("usage");} voidmain(int argc, char **argv){ int n, sti, i, hxsz, lacing, fd, debug; vlong sz, off, x; uchar *b, t[3]; Biobuf in, out; Elspec s; double d; Tm tm; debug = 0; hxsz = 32; ARGBEGIN{ case 'd': debug++; break; case 'h': if((hxsz = atoi(EARGF(usage()))) > 0) break; default: usage(); }ARGEND fd = 0; if(argc == 1){ if((fd = open(*argv, OREAD)) < 0) sysfatal("%r"); }else if(argc != 0) usage(); if((b = malloc(hxsz)) == nil) sysfatal("memory"); quotefmtinstall(); fmtinstall('H', encodefmt); tmfmtinstall(); Binit(&in, fd, OREAD); Binit(&out, 1, OWRITE); sti = 0; for(;;){ off = Boffset(&in); if((n = ebmlel(&in, 0x7fffffffffffffffLL, &s, &sz)) < 0){ werrstr("invalid ebml: %r at %#llx (size %lld)", off, sz); goto err; } if(s.type < 0) continue; if(n == 0) /* eof */ break; while(sti > 0 && off >= stack[sti-1]) sti--; if(s.name){ for(i = 0; i < sti; i++) Bputc(&out, '\t'); Bprint(&out, "%s ", s.name); if(debug) Bprint(&out, " (id %#llx) ", s.id); if(s.type == Emaster && sti < nelem(stack)) stack[sti++] = off+n+sz; }else{ Bprint(&out, "%#llx ", s.id); } if(debug) Bprint(&out, "(%lld bytes) ", sz); switch(s.type){ case Ebinary: if(s.id == ESimpleBlock || s.id == EBlock){ if((n = ebmluint(&in, sz, &x)) < 0){ werrstr("block: %r"); goto err; } sz -= n; if(Bread(&in, t, 3) != 3){ werrstr("block: %r"); goto err; } sz -= 3; lacing = (t[2] >> 1) & 3; Bprint(&out, "(track %lld, timecode %d) ", x, (s16int)(t[0]<<8 | t[1])); if(s.id == ESimpleBlock){ if(t[2] & 0x80) Bprint(&out, "(key) "); if(t[2] & 0x01) Bprint(&out, "(discard) "); } if(t[2] & 0x08) Bprint(&out, "(hidden) "); if(lacing != 0) Bprint(&out, "(lacing %d) ", lacing); } n = min(hxsz, sz); if(Bread(&in, b, n) != n){ werrstr("binary: %r"); goto err; } Bprint(&out, "[%.*H%s] (%lld bytes)", n, b, sz > n ? "..." : "", sz); sz -= n; break; case Efloat: if(ebmlfloat(&in, sz, &d) < 0) goto err; Bprint(&out, "%g", d); sz = 0; break; case Eunsigned: if(ebmlrawuint(&in, sz, &x) < 0) goto err; Bprint(&out, "%llud", (uvlong)x); sz = 0; break; case Esigned: if(ebmlrawsint(&in, sz, &x) < 0) goto err; Bprint(&out, "%lld", x); sz = 0; break; case Eunicode: case Eascii: n = min(hxsz, sz); if(Bread(&in, b, n) != n){ werrstr("string: %r"); goto err; } Bprint(&out, "%#.*q%s", n, (char*)b, sz > n ? "..." : ""); sz -= n; break; case Etimestamp: if(ebmlrawsint(&in, sz, &x) < 0) goto err; x /= 1000000000LL; x += 978307200LL; Bprint(&out, "%τ", tmfmt(tmtime(&tm, x, nil), nil)); sz = 0; break; case Emaster: break; default: Bprint(&out, "???"); } if(s.id == ETrackType) Bprint(&out, " (%s)", ebmltracktype(x)); if(Bputc(&out, '\n') < 0) break; if(s.type != Emaster && sz > 0 && Bseek(&in, sz, 1) < 0) goto err; } Bterm(&out); Bterm(&in); exits(nil);err: fprint(2, "%s: %r\n", fd == 0 ? "stdin" : *argv); exits("error");}
#include "../ebml.c"
#define min(a,b) ((a)<=(b)?(a):(b))
static vlong stack[128];
static void
usage(void)
{
fprint(2, "usage: %s [-d] [-h hxsz] [file.mkv]\n", argv0);
exits("usage");
}
void
main(int argc, char **argv)
{
int n, sti, i, hxsz, lacing, fd, debug;
vlong sz, off, x;
uchar *b, t[3];
Biobuf in, out;
Elspec s;
double d;
Tm tm;
debug = 0;
hxsz = 32;
ARGBEGIN{
case 'd':
debug++;
break;
case 'h':
if((hxsz = atoi(EARGF(usage()))) > 0)
break;
default:
usage();
}ARGEND
fd = 0;
if(argc == 1){
if((fd = open(*argv, OREAD)) < 0)
sysfatal("%r");
}else if(argc != 0)
usage();
if((b = malloc(hxsz)) == nil)
sysfatal("memory");
quotefmtinstall();
fmtinstall('H', encodefmt);
tmfmtinstall();
Binit(&in, fd, OREAD);
Binit(&out, 1, OWRITE);
sti = 0;
for(;;){
off = Boffset(&in);
if((n = ebmlel(&in, 0x7fffffffffffffffLL, &s, &sz)) < 0){
werrstr("invalid ebml: %r at %#llx (size %lld)", off, sz);
goto err;
}
if(s.type < 0)
continue;
if(n == 0) /* eof */
break;
while(sti > 0 && off >= stack[sti-1])
sti--;
if(s.name){
for(i = 0; i < sti; i++)
Bputc(&out, '\t');
Bprint(&out, "%s ", s.name);
if(debug)
Bprint(&out, " (id %#llx) ", s.id);
if(s.type == Emaster && sti < nelem(stack))
stack[sti++] = off+n+sz;
}else{
Bprint(&out, "%#llx ", s.id);
}
if(debug)
Bprint(&out, "(%lld bytes) ", sz);
switch(s.type){
case Ebinary:
if(s.id == ESimpleBlock || s.id == EBlock){
if((n = ebmluint(&in, sz, &x)) < 0){
werrstr("block: %r");
goto err;
}
sz -= n;
if(Bread(&in, t, 3) != 3){
werrstr("block: %r");
goto err;
}
sz -= 3;
lacing = (t[2] >> 1) & 3;
Bprint(&out, "(track %lld, timecode %d) ", x, (s16int)(t[0]<<8 | t[1]));
if(s.id == ESimpleBlock){
if(t[2] & 0x80)
Bprint(&out, "(key) ");
if(t[2] & 0x01)
Bprint(&out, "(discard) ");
}
if(t[2] & 0x08)
Bprint(&out, "(hidden) ");
if(lacing != 0)
Bprint(&out, "(lacing %d) ", lacing);
}
n = min(hxsz, sz);
if(Bread(&in, b, n) != n){
werrstr("binary: %r");
goto err;
}
Bprint(&out, "[%.*H%s] (%lld bytes)", n, b, sz > n ? "..." : "", sz);
sz -= n;
break;
case Efloat:
if(ebmlfloat(&in, sz, &d) < 0)
goto err;
Bprint(&out, "%g", d);
sz = 0;
break;
case Eunsigned:
if(ebmlrawuint(&in, sz, &x) < 0)
goto err;
Bprint(&out, "%llud", (uvlong)x);
sz = 0;
break;
case Esigned:
if(ebmlrawsint(&in, sz, &x) < 0)
goto err;
Bprint(&out, "%lld", x);
sz = 0;
break;
case Eunicode:
case Eascii:
n = min(hxsz, sz);
if(Bread(&in, b, n) != n){
werrstr("string: %r");
goto err;
}
Bprint(&out, "%#.*q%s", n, (char*)b, sz > n ? "..." : "");
sz -= n;
break;
case Etimestamp:
if(ebmlrawsint(&in, sz, &x) < 0)
goto err;
x /= 1000000000LL;
x += 978307200LL;
Bprint(&out, "%τ", tmfmt(tmtime(&tm, x, nil), nil));
sz = 0;
break;
case Emaster:
break;
default:
Bprint(&out, "???");
}
if(s.id == ETrackType)
Bprint(&out, " (%s)", ebmltracktype(x));
if(Bputc(&out, '\n') < 0)
break;
if(s.type != Emaster && sz > 0 && Bseek(&in, sz, 1) < 0)
goto err;
}
Bterm(&out);
Bterm(&in);
exits(nil);
err:
fprint(2, "%s: %r\n", fd == 0 ? "stdin" : *argv);
exits("error");
}