+/* -*-c-*-
+ *
+ * Common functions for the DVDrip C utilities.
+ *
+ * (c) 2022 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the DVD ripping toolset.
+ *
+ * DVDrip is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * DVDrip is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DVDrip. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
#include "lib.h"
+/*----- Diagnostics -------------------------------------------------------*/
+
const char *prog = "<unset>";
void set_prog(const char *p)
exit(2);
}
+/*----- Parsing utilities -------------------------------------------------*/
+
+double parse_float(const char **p_inout, unsigned f,
+ double min, double max, const char *what)
+{
+ const char *p;
+ char *q;
+ double x;
+ int err;
+
+ err = errno; errno = 0;
+ p = *p_inout;
+ x = strtod(p, &q);
+ if (errno || x < min || x > max || (!(f&PNF_JUNK) && *q))
+ bail("bad %s `%s'", what, p);
+ *p_inout = q; errno = err;
+ return (x);
+}
+
+long parse_int(const char **p_inout, unsigned f,
+ long min, long max, const char *what)
+{
+ const char *p;
+ char *q;
+ long x;
+ int err;
+
+ err = errno; errno = 0;
+ p = *p_inout;
+ x = strtoul(p, &q, 0);
+ if (errno || x < min || x > max || (!(f&PNF_JUNK) && *q))
+ bail("bad %s `%s'", what, p);
+ *p_inout = q; errno = err;
+ return (x);
+}
+
+/*----- Resizing buffers and arrays ---------------------------------------*/
+
+void buf__grow(struct buf *b)
+{
+ b->sz = b->sz ? 2*b->sz : 32;
+ b->p = realloc(b->p, b->sz);
+ if (!b->p) bail("out of memory allocating %zu bytes", b->sz);
+}
+
+void *vec__grow(void *p, size_t esz, size_t *sz_inout)
+{
+ size_t sz = *sz_inout, want;
+
+ sz = sz ? 2*sz : 32;
+ want = sz*esz;
+ p = realloc(p, want);
+ if (!p) bail("out of memory allocating %zu bytes", want);
+ *sz_inout = sz; return (p);
+}
+
+/*----- System utilities --------------------------------------------------*/
+
void sit(double t)
{
struct timeval tv;
}
}
+double tvdiff(const struct timeval *tv_lo, const struct timeval *tv_hi)
+{
+ return ((tv_hi->tv_sec - tv_lo->tv_sec) +
+ (tv_hi->tv_usec - tv_lo->tv_usec)/1.0e6);
+}
+
+int read_line(FILE *fp, struct buf *b)
+{
+ int ch;
+
+ ch = getc(fp);
+ if (ch == EOF)
+ return (-1);
+ else if (ch != '\n')
+ do { buf_putc(b, ch); ch = getc(fp); } while (ch != EOF && ch != '\n');
+ buf_putz(b);
+ return (0);
+}
+
void carefully_write(int fd, const void *buf, size_t sz)
{
const unsigned char *p = buf;
bail_syserr(errno, "error writing %s file", what);
}
-void store_filename(char *buf, ident id)
+off_t device_size(int fd, const char *file, int *blksz_out)
{
- switch (id_kind(id)) {
- case RAW:
- sprintf(buf, "#<raw device>");
- break;
- case IFO:
- if (!id_title(id)) sprintf(buf, "/VIDEO_TS/VIDEO_TS.IFO");
- else sprintf(buf, "/VIDEO_TS/VTS_%02u_0.IFO", id_title(id));
- break;
- case BUP:
- if (!id_title(id)) sprintf(buf, "/VIDEO_TS/VIDEO_TS.BUP");
- else sprintf(buf, "/VIDEO_TS/VTS_%02u_0.BUP", id_title(id));
- break;
- case VOB:
- if (!id_title(id)) sprintf(buf, "/VIDEO_TS/VIDEO_TS.VOB");
- else
- sprintf(buf, "/VIDEO_TS/VTS_%02u_%u.VOB", id_title(id), id_part(id));
- break;
- default:
- abort();
- }
+ struct stat st;
+ uint64_t volsz;
+
+ if (fstat(fd, &st))
+ bail_syserr(errno, "failed to obtain status for `%s'", file);
+ if (S_ISREG(st.st_mode))
+ volsz = st.st_size;
+ else if (S_ISBLK(st.st_mode)) {
+ if (ioctl(fd, BLKGETSIZE64, &volsz))
+ bail_syserr(errno, "failed to get volume size for `%s'", file);
+ if (ioctl(fd, BLKSSZGET, blksz_out))
+ bail_syserr(errno, "failed to get block size for `%s'", file);
+ } else
+ bail("can't read size for `%s': expected file or block device", file);
+ return ((off_t)volsz);
}
+/*----- Progress utilities ------------------------------------------------*/
+
struct progress_state progress = PROGRESS_STATE_INIT;
static struct banner_progress_item banner_progress;
progress_update(&progress);
}
+/*----- DVD utilities -----------------------------------------------------*/
+
#ifdef notdef
static void logfn(void *p, dvd_logger_level_t lev,
const char *fmt, va_list ap)
static const dvd_logger_cb logger = { logfn };
#endif
-void open_dvd(const char *device, int *fd_out, dvd_reader_t **dvd_out)
+int open_dvd(const char *device, int mode,
+ int *fd_out, dvd_reader_t **dvd_out)
{
- int fd;
- dvd_reader_t *dvd;
- int bannerp = 0;
+ int fd = -1;
+ dvd_reader_t *dvd = 0;
+ int bannerp = 0, rc;
for (;;) {
- fd = open(device, O_RDONLY);
+ fd = open(device, mode);
if (fd >= 0 || errno != ENOMEDIUM) break;
if (!bannerp) {
show_banner("Waiting for disc to be inserted...");
sit(0.2);
}
if (bannerp) hide_banner();
- if (fd < 0) bail_syserr(errno, "failed to open device `%s'", device);
+
+ if (fd < 0) {
+ moan_syserr(errno, "failed to open device `%s'", device);
+ rc = -1; goto end;
+ }
+
if (dvd_out) {
#ifdef notdef
dvd = DVDOpen2(0, &logger, device);
#else
dvd = DVDOpen(device);
#endif
- if (!dvd) bail("failed to open DVD on `%s'", device);
- *dvd_out = dvd;
+ if (!dvd) {
+ moan("failed to open DVD on `%s'", device);
+ rc = -1; goto end;
+ }
}
- if (fd_out) *fd_out = fd;
- else close(fd);
+
+ if (fd_out) { *fd_out = fd; fd = -1; }
+ if (dvd_out) { *dvd_out = dvd; dvd = 0; }
+ rc = 0;
+
+end:
+ if (fd >= 0) close(fd);
+ DVDClose(dvd);
+ return (rc);
}
+
+void store_filename(char *buf, ident id)
+{
+ switch (id_kind(id)) {
+ case RAW:
+ sprintf(buf, "#<raw device>");
+ break;
+ case IFO:
+ if (!id_title(id)) sprintf(buf, "/VIDEO_TS/VIDEO_TS.IFO");
+ else sprintf(buf, "/VIDEO_TS/VTS_%02u_0.IFO", id_title(id));
+ break;
+ case BUP:
+ if (!id_title(id)) sprintf(buf, "/VIDEO_TS/VIDEO_TS.BUP");
+ else sprintf(buf, "/VIDEO_TS/VTS_%02u_0.BUP", id_title(id));
+ break;
+ case VOB:
+ if (!id_title(id)) sprintf(buf, "/VIDEO_TS/VIDEO_TS.VOB");
+ else
+ sprintf(buf, "/VIDEO_TS/VTS_%02u_%u.VOB", id_title(id), id_part(id));
+ break;
+ default:
+ abort();
+ }
+}
+
+static char *copy_string(char *p, const char *q)
+{
+ while (*q) *p++ = *q++;
+ *p = 0; return (p);
+}
+
+static char *copy_hex(char *p, const unsigned char *q, size_t sz)
+{
+ while (sz) {
+ sprintf(p, "%02x", *q);
+ p += 2; q++; sz--;
+ }
+ return (p);
+}
+
+int dvd_id(char *p, dvd_reader_t *dvd, unsigned f, const char *file)
+{
+ char volid[33];
+ unsigned char volsetid[16], discid[16];
+ int rc;
+ size_t n;
+
+ rc = DVDUDFVolumeInfo(dvd,
+ volid, sizeof(volid),
+ volsetid, sizeof(volsetid));
+ if (!rc) {
+ p = copy_string(p, volid);
+ *p++ = '-';
+ for (n = sizeof(volsetid); n && !volsetid[n - 1]; n--);
+ p = copy_hex(p, volsetid, n);
+ } else if (f&DIF_MUSTVOLINF) {
+ if (file) moan("failed to read volume info for `%s'", file);
+ else moan("failed to read volume info");
+ return (-1);
+ } else
+ p = copy_string(p, "<error reading volume info>");
+
+ *p++ = ':';
+ rc = DVDDiscID(dvd, discid);
+ if (!rc)
+ p = copy_hex(p, discid, sizeof(discid));
+ else if (f&DIF_MUSTIFOHASH) {
+ if (file) moan("failed to determine disc id of `%s'", file);
+ else moan("failed to determine disc id");
+ return (-1);
+ } else
+ p = copy_string(p, "<error reading disc-id>");
+
+ return (0);
+}
+
+/*----- That's all, folks -------------------------------------------------*/