dvd-sector-copy.c: Add option to verify source id.
[dvdrip] / lib.c
1 #include "lib.h"
2
3 const char *prog = "<unset>";
4
5 void set_prog(const char *p)
6 { const char *q = strrchr(p, '/'); prog = q ? q + 1 : p; }
7
8 void vmoan(const char *fmt, va_list ap)
9 { vmoan_syserr(0, fmt, ap); }
10
11 void vmoan_syserr(int err, const char *fmt, va_list ap)
12 {
13 fprintf(stderr, "%s: ", prog);
14 vfprintf(stderr, fmt, ap);
15 if (err) fprintf(stderr, ": %s", strerror(errno));
16 fputc('\n', stderr);
17 }
18
19 void moan(const char *fmt, ...)
20 { va_list ap; va_start(ap, fmt); vmoan(fmt, ap); va_end(ap); }
21
22 void moan_syserr(int err, const char *fmt, ...)
23 { va_list ap; va_start(ap, fmt); vmoan_syserr(err, fmt, ap); va_end(ap); }
24
25 void bail(const char *fmt, ...)
26 { va_list ap; va_start(ap, fmt); vmoan(fmt, ap); va_end(ap); exit(2); }
27
28 void bail_syserr(int err, const char *fmt, ...)
29 {
30 va_list ap;
31
32 va_start(ap, fmt); vmoan_syserr(err, fmt, ap); va_end(ap);
33 exit(2);
34 }
35
36 void sit(double t)
37 {
38 struct timeval tv;
39 double whole = floor(t);
40
41 if (t) {
42 tv.tv_sec = whole; tv.tv_usec = floor((t - whole)*1.0e6) + 1;
43 if (select(0, 0, 0, 0, &tv) < 0) bail_syserr(errno, "failed to sleep");
44 }
45 }
46
47 void carefully_write(int fd, const void *buf, size_t sz)
48 {
49 const unsigned char *p = buf;
50 ssize_t n;
51
52 if (fd < 0) return;
53 while (sz) {
54 n = write(fd, p, sz);
55 if (n < 0) {
56 if (errno == EINTR) continue;
57 bail_syserr(errno, "failed to write to output file");
58 }
59 if (!n) bail("unexpected short write to output file");
60 p += n; sz -= n;
61 }
62 }
63
64 void open_file_on_demand(const char *file, FILE **fp_inout, const char *what)
65 {
66 FILE *fp;
67
68 if (!*fp_inout) {
69 fp = fopen(file, "w");
70 if (!fp) bail_syserr(errno, "failed to open %s file `%s'", what, file);
71 fprintf(fp, "## %s\n\n", what);
72 *fp_inout = fp;
73 }
74 }
75
76 void check_write(FILE *fp, const char *what)
77 {
78 fflush(fp);
79 if (ferror(fp)) bail_syserr(errno, "error writing %s file", what);
80 }
81
82 void carefully_fclose(FILE *fp, const char *what)
83 {
84 if (fp && (ferror(fp) || fclose(fp)))
85 bail_syserr(errno, "error writing %s file", what);
86 }
87
88 void store_filename(char *buf, ident id)
89 {
90 switch (id_kind(id)) {
91 case RAW:
92 sprintf(buf, "#<raw device>");
93 break;
94 case IFO:
95 if (!id_title(id)) sprintf(buf, "/VIDEO_TS/VIDEO_TS.IFO");
96 else sprintf(buf, "/VIDEO_TS/VTS_%02u_0.IFO", id_title(id));
97 break;
98 case BUP:
99 if (!id_title(id)) sprintf(buf, "/VIDEO_TS/VIDEO_TS.BUP");
100 else sprintf(buf, "/VIDEO_TS/VTS_%02u_0.BUP", id_title(id));
101 break;
102 case VOB:
103 if (!id_title(id)) sprintf(buf, "/VIDEO_TS/VIDEO_TS.VOB");
104 else
105 sprintf(buf, "/VIDEO_TS/VTS_%02u_%u.VOB", id_title(id), id_part(id));
106 break;
107 default:
108 abort();
109 }
110 }
111
112 static char *copy_string(char *p, const char *q)
113 {
114 while (*q) *p++ = *q++;
115 *p = 0; return (p);
116 }
117
118 static char *copy_hex(char *p, const unsigned char *q, size_t sz)
119 {
120 while (sz) {
121 sprintf(p, "%02x", *q);
122 p += 2; q++; sz--;
123 }
124 return (p);
125 }
126
127 int dvd_id(char *p, dvd_reader_t *dvd, unsigned f, const char *file)
128 {
129 char volid[33];
130 unsigned char volsetid[16], discid[16];
131 int rc;
132 size_t n;
133
134 rc = DVDUDFVolumeInfo(dvd,
135 volid, sizeof(volid),
136 volsetid, sizeof(volsetid));
137 if (!rc) {
138 p = copy_string(p, volid);
139 *p++ = '-';
140 for (n = sizeof(volsetid); n && !volsetid[n - 1]; n--);
141 p = copy_hex(p, volsetid, n);
142 } else if (f&DIF_MUSTVOLINF) {
143 if (file) moan("failed to read volume info for `%s'", file);
144 else moan("failed to read volume info");
145 return (-1);
146 } else
147 p = copy_string(p, "<error reading volume info>");
148
149 *p++ = ':';
150 rc = DVDDiscID(dvd, discid);
151 if (!rc)
152 p = copy_hex(p, discid, sizeof(discid));
153 else if (f&DIF_MUSTIFOHASH) {
154 if (file) moan("failed to determine disc id of `%s'", file);
155 else moan("failed to determine disc id");
156 return (-1);
157 } else
158 p = copy_string(p, "<error reading disc-id>");
159
160 return (0);
161 }
162
163 struct progress_state progress = PROGRESS_STATE_INIT;
164 static struct banner_progress_item banner_progress;
165
166 static void render_banner_progress(struct progress_item *item,
167 struct progress_render_state *render)
168 {
169 struct banner_progress_item *bi = (struct banner_progress_item *)item;
170
171 progress_putleft(render, " %s", bi->msg);
172 progress_shownotice(render, 4, 7);
173 }
174
175 void show_banner(const char *msg)
176 {
177 banner_progress._base.render = render_banner_progress;
178 progress_additem(&progress, &banner_progress._base);
179 banner_progress.msg = msg;
180 progress_update(&progress);
181 }
182
183 void hide_banner(void)
184 {
185 if (!progress_removeitem(&progress, &banner_progress._base))
186 progress_update(&progress);
187 }
188
189 #ifdef notdef
190 static void logfn(void *p, dvd_logger_level_t lev,
191 const char *fmt, va_list ap)
192 {
193 switch (lev) {
194 case DVD_LOGGER_LEVEL_ERROR:
195 fprintf("%s (libdvdread error): ", prog);
196 break;
197 case DVD_LOGGER_LEVEL_WARN:
198 fprintf("%s (libdvdread warning): ", prog);
199 break;
200 default:
201 return;
202 }
203 vfprintf(stderr, fmt, ap);
204 fputc('\n', stderr);
205 }
206 static const dvd_logger_cb logger = { logfn };
207 #endif
208
209 void open_dvd(const char *device, int *fd_out, dvd_reader_t **dvd_out)
210 {
211 int fd;
212 dvd_reader_t *dvd;
213 int bannerp = 0;
214
215 for (;;) {
216 fd = open(device, O_RDONLY);
217 if (fd >= 0 || errno != ENOMEDIUM) break;
218 if (!bannerp) {
219 show_banner("Waiting for disc to be inserted...");
220 bannerp = 1;
221 }
222 sit(0.2);
223 }
224 if (bannerp) hide_banner();
225 if (fd < 0) bail_syserr(errno, "failed to open device `%s'", device);
226 if (dvd_out) {
227 #ifdef notdef
228 dvd = DVDOpen2(0, &logger, device);
229 #else
230 dvd = DVDOpen(device);
231 #endif
232 if (!dvd) bail("failed to open DVD on `%s'", device);
233 *dvd_out = dvd;
234 }
235 if (fd_out) *fd_out = fd;
236 else close(fd);
237 }