+#include "lib.h"
+#include "dvdcss/dvdcss.h"
+
+static void usage(FILE *fp)
+ { fprintf(fp, "usage: %s [-b BADFILE] DEVICE\n", prog); }
+
+static dvd_reader_t *dvd;
+static dvdcss_t css;
+
+static FILE *badfp;
+static const char *badfile;
+
+static int check_vob(unsigned index, unsigned titlep)
+{
+ secaddr start, end, pos, len;
+ char fn[MAXFNSZ], fn2[MAXFNSZ];
+ unsigned j;
+ int rc = 0;
+
+ store_filename(fn, mkident(VOB, index, titlep));
+ start = UDFFindFile(dvd, fn, &len);
+ if (!start) return (0);
+ end = start + SECTORS(len);
+
+ if (dvdcss_seek(css, start, DVDCSS_SEEK_KEY) < 0) {
+ if (titlep)
+ for (j = 2; j < 10; j++) {
+ store_filename(fn2, mkident(VOB, index, j));
+ pos = UDFFindFile(dvd, fn2, &len);
+ if (!pos) break;
+ assert(pos == end);
+ end += SECTORS(len);
+ }
+ open_file_on_demand(badfile, &badfp, "uncracked video objects");
+ fprintf(badfp, "%"PRIuSEC" %"PRIuSEC" # %s\n", start, end, fn);
+ rc = -1;
+ }
+
+ return (rc);
+}
+
+int main(int argc, char *argv[])
+{
+ int opt, rc = 0;
+ unsigned j, f = 0;
+#define f_bogus 1u
+
+ set_prog(argv[0]);
+ for (;;) {
+ opt = getopt(argc, argv, "hb:"); if (opt < 0) break;
+ switch (opt) {
+ case 'h': usage(stderr); exit(0);
+ case 'b': badfile = optarg; break;
+ default: f |= f_bogus; break;
+ }
+ }
+ if (argc - optind != 1) f |= f_bogus;
+ if (f&f_bogus) { usage(stderr); exit(2); }
+
+ if (!badfile) badfp = stdout;
+
+ setlocale(LC_ALL, "");
+ progress_init(&progress);
+
+ open_dvd(argv[optind], 0, &dvd);
+ css = dvdcss_open(argv[optind]);
+ if (!css)
+ bail_syserr(errno, "failed to attach CSS machinery to `%s'",
+ argv[optind]);
+
+ for (j = 0; j < 100; j++) {
+ if (check_vob(j, 0)) rc = 1;
+ if (j && check_vob(j, 1)) rc = 1;
+ }
+
+ dvdcss_close(css);
+ DVDClose(dvd);
+ progress_free(&progress);
+ carefully_fclose(badfp, "uncracked objects file");
+ return (rc);
+}