chiark / gitweb /
@@@ dvdrip-upload: change settings while i'm stealing someone else's internet
[dvdrip] / lib.h
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
26 #ifndef LIB_H
27 #define LIB_H
28
29 /*----- Preliminaries -----------------------------------------------------*/
30
31 #define _GNU_SOURCE
32 #define _FILE_OFFSET_BITS 64
33
34 /*----- Header files ------------------------------------------------------*/
35
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
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  */
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
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  */
83 #define STRCMP(a, op, b) (strcmp((a), (b)) op 0)
84 #define STRNCMP(a, op, b, n) (strncmp((a), (b), (n)) op 0)
85 #define MEMCMP(a, op, b, n) (memcmp((a), (b), (n)) op 0)
86
87 /* Suppress some code unless we're debugging. */
88 #ifdef DEBUG
89 #  define D(x) x
90 #else
91 #  define D(x)
92 #endif
93
94 /* Count the number of elements in an array. */
95 #define N(v) (sizeof(v)/sizeof((v)[0]))
96
97 /* Function attributes.  If you're not using GCC to build then you'll need to
98  * say something different here.
99  */
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
110
111 /*----- Definitions for low-level DVD access ------------------------------*/
112
113 #define SECTORSZ 2048                   /* the DVD sector size */
114 #define SECTORS(n) (((n) + (SECTORSZ - 1))/SECTORSZ)
115                                 /* convert bytes to * sectors, rounding up */
116 typedef 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 -------------------------------------------------------*/
121
122 extern const char *prog;          /* the program name; set with `set_prog' */
123
124 extern void set_prog(const char *p);
125         /* Set the program name to P, stripping any directory names. */
126
127 extern void vmoan(const char *fmt, va_list ap);
128 extern void vmoan_syserr(int err, const char *fmt, va_list ap);
129         /* Low-level warning reporting.  See `moan' and `moan_syserr'. */
130
131 extern PRINTF_LIKE(1, 2) void moan(const char *fmt, ...);
132 extern PRINTF_LIKE(2, 3) void moan_syserr(int err, const char *fmt, ...);
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
139 extern PRINTF_LIKE(1, 2) NORETURN void bail(const char *fmt, ...);
140 extern PRINTF_LIKE(2, 3) NORETURN
141   void bail_syserr(int err, const char *fmt, ...);
142         /* Like the corresponding `moan' functions, except that they also
143          * exit with status code 2.
144          */
145
146 /*----- Resizing buffers --------------------------------------------------*/
147
148 struct 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
156 static 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
161 static 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
167 extern 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
172 static 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
176 static 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
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
199 extern 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
206 #define VEC_PUSH(p, vv) do {                                            \
207   if ((vv)->n >= (vv)->sz)                                              \
208     (vv)->v = vec__grow((vv)->v, sizeof(*(vv)->v), &(vv)->sz);          \
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
215 /*----- Parsing utilities -------------------------------------------------*/
216
217 #define PNF_JUNK 1u
218 extern double parse_float(const char **p_inout, unsigned f,
219                           double min, double max, const char *what);
220 extern long parse_int(const char **p_inout, unsigned f,
221                       long min, long max, const char *what);
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 --------------------------------------------------*/
231
232 extern 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
238 extern void sit(double t);
239         /* Do nothing for T seconds.  As implied by the type, T may be
240          * fractional.
241          */
242
243 extern 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
250 extern void carefully_write(int fd, const void *buf, size_t sz);
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
256 extern void open_file_on_demand(const char *file, FILE **fp_inout,
257                                 const char *what);
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
264 extern void check_write(FILE *fp, const char *what);
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
270 extern void carefully_fclose(FILE *fp, const char *what);
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
275 extern off_t device_size(int fd, const char *file, int *blksz_out);
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
283          * fatal error quoting FILE as the name of the device.
284          */
285
286 /*----- Progress utilities ------------------------------------------------*/
287
288 struct banner_progress_item {
289         /* A progress item which simply shows a banner message. */
290   struct progress_item _base;
291   const char *msg;
292 };
293
294 extern struct progress_state progress;  /* the shared progress reporter */
295
296 extern void show_banner(const char *msg);
297 extern void hide_banner(void);
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 -----------------------------------------------------*/
303
304 extern int open_dvd(const char *device, int mode,
305                     int *fd_out, dvd_reader_t **dvd_out);
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
311          * function?  Returns 0 on success or -1 on failure.
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
315          * wait for a medium to be inserted.  Other problems are reported to
316          * stderr.
317          */
318
319 enum { RAW, IFO, VOB, BUP };
320 typedef uint_least32_t ident;
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          */
342
343 static inline ident mkident(unsigned kind, unsigned title, unsigned part)
344   { return (((ident)kind << 0) | ((ident)title << 8) | ((ident)part << 16)); }
345 static inline unsigned id_kind(ident id) { return ((id >> 0)&0x0ff); }
346 static inline unsigned id_title(ident id) { return ((id >> 8)&0x0ff); }
347 static inline unsigned id_part(ident id) { return ((id >> 16)&0x0ff); }
348         /* Functions for constructing and picking apart the fields of an
349          * ident.
350          */
351
352 #define MAXFNSZ (1 + 8 + 1 + 12 + 1)
353 extern void store_filename(char *buf, ident id);
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          */
358
359 #define DIF_MUSTVOLINF 1u
360 #define DIF_MUSTIFOHASH 2u
361 #define MAXIDSZ (32 + 1 + 32 + 1 + 32 + 1)
362 extern int dvd_id(char *p, dvd_reader_t *dvd, unsigned f, const char *file);
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 -------------------------------------------------*/
390
391 #endif