ref: 74533c8ff1ab84ff0949d52c3726ccfcfc1bf76a
dir: /extra/mkvdump.c/
#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"); }