@@@ dvdrip-upload: change settings while i'm stealing someone else's internet
[dvdrip] / lib.h
CommitLineData
be15bd14
MW
1/* -*-c-*-
2 *
3 * Common functions for the DVDrip C utilities.
4 *
5 * (c) 2022 Mark Wooding
6 */
7
8/*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of the DVD ripping toolset.
11 *
12 * DVDrip is free software: you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 3 of the License, or (at your
15 * option) any later version.
16 *
17 * DVDrip is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with DVDrip. If not, see <https://www.gnu.org/licenses/>.
24 */
25
dc53ebfa
MW
26#ifndef LIB_H
27#define LIB_H
28
be15bd14
MW
29/*----- Preliminaries -----------------------------------------------------*/
30
dc53ebfa
MW
31#define _GNU_SOURCE
32#define _FILE_OFFSET_BITS 64
33
be15bd14
MW
34/*----- Header files ------------------------------------------------------*/
35
dc53ebfa
MW
36#include <assert.h>
37#include <ctype.h>
38#include <errno.h>
39#include <float.h>
40#include <inttypes.h>
41#include <limits.h>
42#include <locale.h>
43#include <math.h>
44#include <stdarg.h>
45#include <stdint.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
49#include <time.h>
50
51#include <unistd.h>
52#include <fcntl.h>
53#include <sys/ioctl.h>
54#include <sys/select.h>
55#include <sys/stat.h>
56#include <sys/time.h>
57
58#include <getopt.h>
59
60#include <linux/fs.h>
61
62#include <dvdread/dvd_reader.h>
63#include <dvdread/dvd_udf.h>
64#include <dvdread/ifo_read.h>
65#include <dvdread/ifo_types.h>
66
67#include "multiprogress.h"
68
be15bd14
MW
69/*----- Various macros with wide applicability ----------------------------*/
70
71/* `ctype.h' functions are troublesome: in particular, they don't handle
72 * negative characters properly, if they're a thing that your platform
73 * believes in. So we have these macros which fix things up properly.
74 */
dc53ebfa
MW
75#define CTYPE_HACK(fn, ch) fn((unsigned char)(ch))
76#define ISDIGIT(ch) CTYPE_HACK(isdigit, ch)
77#define ISSPACE(ch) CTYPE_HACK(isspace, ch)
78
be15bd14
MW
79/* It's easy to screw up the `foocmp' functions by leaving off the comparison
80 * with zero. These macros make it impossible to forget, and put the
81 * relation in the right place syntactically.
82 */
dc53ebfa
MW
83#define STRCMP(a, op, b) (strcmp((a), (b)) op 0)
84#define STRNCMP(a, op, b, n) (strncmp((a), (b), (n)) op 0)
2bbc0426 85#define MEMCMP(a, op, b, n) (memcmp((a), (b), (n)) op 0)
dc53ebfa 86
be15bd14 87/* Suppress some code unless we're debugging. */
dc53ebfa
MW
88#ifdef DEBUG
89# define D(x) x
90#else
91# define D(x)
92#endif
93
be15bd14 94/* Count the number of elements in an array. */
dc53ebfa
MW
95#define N(v) (sizeof(v)/sizeof((v)[0]))
96
be15bd14
MW
97/* Function attributes. If you're not using GCC to build then you'll need to
98 * say something different here.
99 */
33d28756
MW
100#if (defined(__GNUC__) && (__GNUC__ > 2 || \
101 (__GNUC__ == 2 && __GNUC_MINOR__ >= 5))) || \
102 (defined(__clang__) && (__clang_major__ > 3 || \
103 (__clang_major__ == 3 && __clang_minor__ >= 3)))
104# define PRINTF_LIKE(fmt, dots) __attribute__((format(printf, fmt, dots)))
105# define NORETURN __attribute__((noreturn))
106#else
107# define PRINTF_LIKE(fmt, dots)
108# define NORETURN
109#endif
1b77f6d3 110
be15bd14
MW
111/*----- Definitions for low-level DVD access ------------------------------*/
112
113#define SECTORSZ 2048 /* the DVD sector size */
dc53ebfa 114#define SECTORS(n) (((n) + (SECTORSZ - 1))/SECTORSZ)
be15bd14
MW
115 /* convert bytes to * sectors, rounding up */
116typedef uint_least32_t secaddr; /* a type for sector numbers */
117#define PRIuSEC PRIuLEAST32 /* how to print a sector number */
118#define SECLIMIT 0x00400000 /* upper bound on sector numbers */
119
120/*----- Diagnostics -------------------------------------------------------*/
dc53ebfa 121
be15bd14 122extern const char *prog; /* the program name; set with `set_prog' */
dc53ebfa
MW
123
124extern void set_prog(const char *p);
be15bd14
MW
125 /* Set the program name to P, stripping any directory names. */
126
dc53ebfa 127extern void vmoan(const char *fmt, va_list ap);
7ea9ce2b 128extern void vmoan_syserr(int err, const char *fmt, va_list ap);
be15bd14
MW
129 /* Low-level warning reporting. See `moan' and `moan_syserr'. */
130
dc53ebfa 131extern PRINTF_LIKE(1, 2) void moan(const char *fmt, ...);
7ea9ce2b 132extern PRINTF_LIKE(2, 3) void moan_syserr(int err, const char *fmt, ...);
be15bd14
MW
133 /* Print a warning message, given as a `printf'-like format string
134 * FMT and arguments, to standard error. If ERR is nonzero, then
135 * append a colon and the human-readable description of the `errno'
136 * value ERR.
137 */
138
dc53ebfa
MW
139extern PRINTF_LIKE(1, 2) NORETURN void bail(const char *fmt, ...);
140extern PRINTF_LIKE(2, 3) NORETURN
141 void bail_syserr(int err, const char *fmt, ...);
be15bd14
MW
142 /* Like the corresponding `moan' functions, except that they also
143 * exit with status code 2.
144 */
145
c62cd11a
MW
146/*----- Resizing buffers --------------------------------------------------*/
147
148struct buf {
149 /* A buffer for a string which can grow automatically. */
150
151 char *p; /* pointer to the buffer */
152 size_t n, sz; /* string length, buffer size */
153};
154#define BUF_INIT { 0, 0, 0 }
155
156static inline void buf_rewind(struct buf *b) { b->n = 0; }
157 /* Throw away the current contents of B so that new stuff gets added
158 * to the beginning.
159 */
160
161static inline void buf_free(struct buf *b)
162 { free(b->p); b->p = 0; b->n = b->sz = 0; }
163 /* Release the memory allocated for B. The buffer can be reused
164 * immediately and/or freed again safely.
165 */
166
167extern void buf__grow(struct buf *b);
168 /* Make B's buffer larger, so that (at least) one extra byte can be
169 * written to it. (Internal to `buf_putc'.)
170 */
171
172static inline void buf_putc(struct buf *b, int ch)
173 { if (b->n >= b->sz) buf__grow(b); b->p[b->n++] = ch; }
174 /* Append the character CH to the buffer B. */
175
176static inline void buf_putz(struct buf *b)
177 { if (b->n >= b->sz) buf__grow(b); b->p[b->n] = 0; }
178 /* Append a zero byte to B without increasing the string length, so
179 * that a future `buf_putc' will overwrite it.
180 */
181
cd997467
MW
182/*----- Resizing vectors --------------------------------------------------*/
183
184#define DEFVEC(vtype, etype) \
185 typedef struct { etype *v; size_t n, sz; } vtype
186#define VEC_INIT { 0, 0, 0 }
187 /* Define VTYPE as a (structured) type for vectors holding elements
188 * of ETYPE.
189 *
190 * A vector V has `V.n' elements, addressed as `V.v[0]' up to
191 * `V.v[V.n - 1]'.
192 */
193
194#define VEC_FREE(vv) do { \
195 free((vv)->v); (vv)->v 0; (vv)->n = (vv)->sz = 0; \
196} while (0)
197 /* Free the vector VV. It's safe to free a vector multiple times. */
198
42c936a1
MW
199extern void *vec__grow(void *p, size_t esz, size_t *sz_inout);
200 /* Extend the buffer P, which currently has space for *SZ_INOUT
201 * elements, each ESZ bytes in size, so that there's space for at
202 * least one one more; return the new buffer address, and update
203 * *SZ_INOUT with the new size.
204 */
205
cd997467 206#define VEC_PUSH(p, vv) do { \
42c936a1
MW
207 if ((vv)->n >= (vv)->sz) \
208 (vv)->v = vec__grow((vv)->v, sizeof(*(vv)->v), &(vv)->sz); \
cd997467
MW
209 (p) = &(vv)->v[(vv)->n++]; \
210} while (0)
211 /* Add an initialized element to the end of vector VV, storing its
212 * address in P.
213 */
214
be15bd14 215/*----- Parsing utilities -------------------------------------------------*/
dc53ebfa 216
f82e4cd7
MW
217#define PNF_JUNK 1u
218extern double parse_float(const char **p_inout, unsigned f,
219 double min, double max, const char *what);
220extern long parse_int(const char **p_inout, unsigned f,
221 long min, long max, const char *what);
be15bd14
MW
222 /* Parse a number starting at *P_IN OUT, advancing that pointer past
223 * it, and return the resulting value. If no number can be read from
224 * the string, or the resulting number is not between MIN and MAX
225 * inclusive, or the `PNF_JUNK' bit is clear in F and the number is
226 * followed by anything other than whitespace, then report a fatal
227 * error, quoting WHAT as having been expected.
228 */
229
230/*----- System utilities --------------------------------------------------*/
f82e4cd7 231
cd997467
MW
232extern double tvdiff(const struct timeval *tv_lo,
233 const struct timeval *tv_hi);
234 /* Return the (signed) difference from TV_LO to TV_HI, as a floating-
235 * point number of seconds.
236 */
237
dc53ebfa 238extern void sit(double t);
be15bd14
MW
239 /* Do nothing for T seconds. As implied by the type, T may be
240 * fractional.
241 */
dc53ebfa 242
d0a95de5
MW
243extern int read_line(FILE *fp, struct buf *b);
244 /* Read a line from FP, appending it to the buffer B, leaving the
245 * string in B null-terminated (as if by `buf_putz'). Return 0 on
246 * success, or -1 if nothing was read (not even an empty line) before
247 * we encountered end-of-file or a read error.
248 */
249
00a5be1d 250extern void carefully_write(int fd, const void *buf, size_t sz);
be15bd14
MW
251 /* Write SZ bytes to file descriptor FD, starting at BUF. Report a
252 * fatal error if this fails. Correctly handles short writes and
253 * `EINTR'.
254 */
255
00a5be1d
MW
256extern void open_file_on_demand(const char *file, FILE **fp_inout,
257 const char *what);
be15bd14
MW
258 /* If *FP_INOUT is not null, then do nothing. Otherwise, open FILE
259 * for writing, storing the resulting stream handle in *FP_INOUT; if
260 * this can't be done then report a fatal error, quoting WHAT as the
261 * kind of file.
262 */
263
00a5be1d 264extern void check_write(FILE *fp, const char *what);
be15bd14
MW
265 /* Flush any remaining output to FP and check that there were no
266 * errors. If there were problems, report a fatal error quoting WHAT
267 * as the kind of file.
268 */
269
00a5be1d 270extern void carefully_fclose(FILE *fp, const char *what);
be15bd14
MW
271 /* Flush output to FP and close it, reporting fatal errors as for
272 * `check_write'. If FP is null, then do nothing.
273 */
274
4bd4876f 275extern off_t device_size(int fd, const char *file, int *blksz_out);
be15bd14
MW
276 /* Determine the size of the device referred to by FD. Specifically,
277 * if FD is a regular file, then this is simply the size of the file;
278 * if FD is a block device, then this is the size of the block
279 * device. Return the resulting size, and, in the case of a block
280 * device only, store the block size in *BLKSZ_OUT. (Hence,
281 * *BLKSZ_OUT will be left unchanged if FD is open on a regular
282 * file.) If FD refers to any other kind of object then report a
3ff388b0 283 * fatal error quoting FILE as the name of the device.
be15bd14
MW
284 */
285
286/*----- Progress utilities ------------------------------------------------*/
00a5be1d 287
1b77f6d3 288struct banner_progress_item {
be15bd14 289 /* A progress item which simply shows a banner message. */
1b77f6d3
MW
290 struct progress_item _base;
291 const char *msg;
292};
293
be15bd14 294extern struct progress_state progress; /* the shared progress reporter */
1b77f6d3
MW
295
296extern void show_banner(const char *msg);
297extern void hide_banner(void);
be15bd14
MW
298 /* Show or hide a banner reporting a message. If a banner is already
299 * showing, then `show_banner' just changes the message.
300 */
301
302/*----- DVD utilities -----------------------------------------------------*/
1b77f6d3 303
d23998cb
MW
304extern int open_dvd(const char *device, int mode,
305 int *fd_out, dvd_reader_t **dvd_out);
be15bd14
MW
306 /* Open the DEVICE. If FD_OUT is not null, then open a file
307 * descriptor onto the device, with the given open(2)-style MODE,
308 * storing the descriptor in *FD_OUT; if DVD_OUT is not null, then
309 * open a `libdvdread' handle onto the devie and store it in
310 * *DVD_OUT. If both are null, then why are you calling this
d23998cb 311 * function? Returns 0 on success or -1 on failure.
be15bd14
MW
312 *
313 * If DEVICE refers to an actual block device, and no medium is
314 * currently inserted, then put up a banner prompting the user and
d23998cb
MW
315 * wait for a medium to be inserted. Other problems are reported to
316 * stderr.
be15bd14 317 */
1b77f6d3 318
dc53ebfa
MW
319enum { RAW, IFO, VOB, BUP };
320typedef uint_least32_t ident;
be15bd14
MW
321 /* A convenient name for interesting files on a DVD. It consists of
322 * three components:
323 *
324 * * A `kind', which is `RAW', `IFO', `VOB', or `BUP'. `RAW' is a
325 * special token which refers to the whole disc; the other kinds
326 * refer to files in the DVD filesystem with the corresponding
327 * extensions.
328 *
329 * * A `title', which is a number between 0 and 99 inclusive.
330 * Title zero refers to the video management information and its
331 * corresponding menu; nonzero numbers refer to video titlesets.
332 *
333 * * A `part', which is only relevant for `VOB' files; part 0
334 * refers to the menu data, while parts 1 to 9 inclusive refer to
335 * portions of the video titleset itself.
336 *
337 * Components which aren't applicable must be zero, so that idents
338 * can conveniently be compared as integers (so, specifically, the
339 * title, if kind is `RAW', and the part, if kind is not `VOB' or
340 * title is zero.
341 */
dc53ebfa
MW
342
343static inline ident mkident(unsigned kind, unsigned title, unsigned part)
344 { return (((ident)kind << 0) | ((ident)title << 8) | ((ident)part << 16)); }
345static inline unsigned id_kind(ident id) { return ((id >> 0)&0x0ff); }
346static inline unsigned id_title(ident id) { return ((id >> 8)&0x0ff); }
347static inline unsigned id_part(ident id) { return ((id >> 16)&0x0ff); }
be15bd14
MW
348 /* Functions for constructing and picking apart the fields of an
349 * ident.
350 */
dc53ebfa
MW
351
352#define MAXFNSZ (1 + 8 + 1 + 12 + 1)
353extern void store_filename(char *buf, ident id);
be15bd14
MW
354 /* Store in BUF the filename corresponding to the ident ID. The
355 * filename will be at most `MAXFNSZ' bytes long, including the
356 * terminating zero.
357 */
dc53ebfa 358
9b86c33f
MW
359#define DIF_MUSTVOLINF 1u
360#define DIF_MUSTIFOHASH 2u
423a8198 361#define MAXIDSZ (32 + 1 + 32 + 1 + 32 + 1)
9b86c33f 362extern int dvd_id(char *p, dvd_reader_t *dvd, unsigned f, const char *file);
be15bd14
MW
363 /* Determine a (hopefully) unique identifier for DVD. The identifier
364 * consists of two parts:
365 *
366 * * the volume name and serial number, from the volume
367 * information, and
368 *
369 * * a cryptographic hash of the `.IFO' files on the disc.
370 *
371 * The identifier is written, as plain text, at P, and consists of at
372 * most `MAXIDSZ' bytes, including the terminating zero.
373 *
374 * It's possible that determining either, or both, of these might
375 * fail: the behaviour is controlled by the `DIF_MUSTVOLINF' and
376 * `DIF_MUSTIFOHASH' flags in F: if the volume name/serial number, or
377 * `.IFO' hash, respectively, can't be determined, and the
378 * corresponding flag is clear, then a placeholder error message is
379 * written to the output buffer in place of the correct data; if the
380 * flag is set, then a warning message is printed to standard error
381 * and -1 is returned. In practice, the `.IFO' hash is more likely
382 * to be computed successfully, and probably more likely to actually
383 * be unique.
384 *
385 * Returns zero if the identifier was successfully determined, within
386 * the parameters set by the flags.
387 */
388
389/*----- That's all, folks -------------------------------------------------*/
9b86c33f 390
dc53ebfa 391#endif