ref: f6a0362e0845888acf03cac6a6fd8e98ffae42d2
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 [file.mkv]\n", argv0); exits("usage"); } void main(int argc, char **argv) { int n, sti, i, hxsz, lacing, fd; vlong sz, off, x; uchar *b, t[3]; Biobuf in, out; Elspec s; double d; Tm tm; hxsz = 32; ARGBEGIN{ 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 %#zx (size %zd)", off, sz); goto err; } 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(s.type == Emaster && sti < nelem(stack)) stack[sti++] = off+n+sz; }else{ Bprint(&out, "%#llx ", s.id); } 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) ", x); 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] (%zd 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", argv0); exits("error"); }