Replace uses of the deprecated dvdcss_handle type by dvdcss_t.
[videolan:libdvdread.git] / src / dvd_input.c
1 /*
2  * Copyright (C) 2002 Samuel Hocevar <sam@zoy.org>,
3  *                    HÃ¥kan Hjort <d95hjort@dtek.chalmers.se>
4  *
5  * This file is part of libdvdread.
6  *
7  * libdvdread is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * libdvdread is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with libdvdread; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <fcntl.h>
25 #include <unistd.h>
26
27 #include "config.h" /* Required for MingW */
28 #include "dvdread/dvd_reader.h"
29 #include "dvd_input.h"
30
31
32 /* The function pointers that is the exported interface of this file. */
33 dvd_input_t (*dvdinput_open)  (const char *);
34 int         (*dvdinput_close) (dvd_input_t);
35 int         (*dvdinput_seek)  (dvd_input_t, int);
36 int         (*dvdinput_title) (dvd_input_t, int);
37 int         (*dvdinput_read)  (dvd_input_t, void *, int, int);
38 char *      (*dvdinput_error) (dvd_input_t);
39
40 #ifdef HAVE_DVDCSS_DVDCSS_H
41 /* linking to libdvdcss */
42 #include <dvdcss/dvdcss.h>
43 #define DVDcss_open(a) dvdcss_open((char*)(a))
44 #define DVDcss_close   dvdcss_close
45 #define DVDcss_seek    dvdcss_seek
46 #define DVDcss_title   dvdcss_title
47 #define DVDcss_read    dvdcss_read
48 #define DVDcss_error   dvdcss_error
49 #else
50
51 /* dlopening libdvdcss */
52 #if defined(HAVE_DLFCN_H) && !defined(USING_BUILTIN_DLFCN)
53 #include <dlfcn.h>
54 #else
55 #if defined(WIN32)
56 /* Only needed on MINGW at the moment */
57 #include "../msvc/contrib/dlfcn.c"
58 #endif
59 #endif
60
61 typedef struct dvdcss_s *dvdcss_t;
62 static dvdcss_t (*DVDcss_open)  (const char *);
63 static int      (*DVDcss_close) (dvdcss_t);
64 static int      (*DVDcss_seek)  (dvdcss_t, int, int);
65 static int      (*DVDcss_title) (dvdcss_t, int);
66 static int      (*DVDcss_read)  (dvdcss_t, void *, int, int);
67 static char *   (*DVDcss_error) (dvdcss_t);
68 #endif
69
70 /* The DVDinput handle, add stuff here for new input methods. */
71 struct dvd_input_s {
72   /* libdvdcss handle */
73   dvdcss_t dvdcss;
74
75   /* dummy file input */
76   int fd;
77 };
78
79
80 /**
81  * initialize and open a DVD device or file.
82  */
83 static dvd_input_t css_open(const char *target)
84 {
85   dvd_input_t dev;
86
87   /* Allocate the handle structure */
88   dev = (dvd_input_t) malloc(sizeof(*dev));
89   if(dev == NULL) {
90     fprintf(stderr, "libdvdread: Could not allocate memory.\n");
91     return NULL;
92   }
93
94   /* Really open it with libdvdcss */
95   dev->dvdcss = DVDcss_open(target);
96   if(dev->dvdcss == 0) {
97     fprintf(stderr, "libdvdread: Could not open %s with libdvdcss.\n", target);
98     free(dev);
99     return NULL;
100   }
101
102   return dev;
103 }
104
105 /**
106  * return the last error message
107  */
108 static char *css_error(dvd_input_t dev)
109 {
110   return DVDcss_error(dev->dvdcss);
111 }
112
113 /**
114  * seek into the device.
115  */
116 static int css_seek(dvd_input_t dev, int blocks)
117 {
118   /* DVDINPUT_NOFLAGS should match the DVDCSS_NOFLAGS value. */
119   return DVDcss_seek(dev->dvdcss, blocks, DVDINPUT_NOFLAGS);
120 }
121
122 /**
123  * set the block for the beginning of a new title (key).
124  */
125 static int css_title(dvd_input_t dev, int block)
126 {
127   return DVDcss_title(dev->dvdcss, block);
128 }
129
130 /**
131  * read data from the device.
132  */
133 static int css_read(dvd_input_t dev, void *buffer, int blocks, int flags)
134 {
135   return DVDcss_read(dev->dvdcss, buffer, blocks, flags);
136 }
137
138 /**
139  * close the DVD device and clean up the library.
140  */
141 static int css_close(dvd_input_t dev)
142 {
143   int ret;
144
145   ret = DVDcss_close(dev->dvdcss);
146
147   if(ret < 0)
148     return ret;
149
150   free(dev);
151
152   return 0;
153 }
154
155 /**
156  * initialize and open a DVD device or file.
157  */
158 static dvd_input_t file_open(const char *target)
159 {
160   dvd_input_t dev;
161
162   /* Allocate the library structure */
163   dev = (dvd_input_t) malloc(sizeof(*dev));
164   if(dev == NULL) {
165     fprintf(stderr, "libdvdread: Could not allocate memory.\n");
166     return NULL;
167   }
168
169   /* Open the device */
170 #if !defined(WIN32) && !defined(__OS2__)
171   dev->fd = open(target, O_RDONLY);
172 #else
173   dev->fd = open(target, O_RDONLY | O_BINARY);
174 #endif
175   if(dev->fd < 0) {
176     perror("libdvdread: Could not open input");
177     free(dev);
178     return NULL;
179   }
180
181   return dev;
182 }
183
184 /**
185  * return the last error message
186  */
187 static char *file_error(dvd_input_t dev)
188 {
189   /* use strerror(errno)? */
190   return (char *)"unknown error";
191 }
192
193 /**
194  * seek into the device.
195  */
196 static int file_seek(dvd_input_t dev, int blocks)
197 {
198   off_t pos;
199
200   pos = lseek(dev->fd, (off_t)blocks * (off_t)DVD_VIDEO_LB_LEN, SEEK_SET);
201   if(pos < 0) {
202     return pos;
203   }
204   /* assert pos % DVD_VIDEO_LB_LEN == 0 */
205   return (int) (pos / DVD_VIDEO_LB_LEN);
206 }
207
208 /**
209  * set the block for the beginning of a new title (key).
210  */
211 static int file_title(dvd_input_t dev, int block)
212 {
213   return -1;
214 }
215
216 /**
217  * read data from the device.
218  */
219 static int file_read(dvd_input_t dev, void *buffer, int blocks, int flags)
220 {
221   size_t len;
222   ssize_t ret;
223
224   len = (size_t)blocks * DVD_VIDEO_LB_LEN;
225
226   while(len > 0) {
227
228     ret = read(dev->fd, buffer, len);
229
230     if(ret < 0) {
231       /* One of the reads failed, too bad.  We won't even bother
232        * returning the reads that went OK, and as in the POSIX spec
233        * the file position is left unspecified after a failure. */
234       return ret;
235     }
236
237     if(ret == 0) {
238       /* Nothing more to read.  Return all of the whole blocks, if any.
239        * Adjust the file position back to the previous block boundary. */
240       size_t bytes = (size_t)blocks * DVD_VIDEO_LB_LEN - len;
241       off_t over_read = -(bytes % DVD_VIDEO_LB_LEN);
242       /*off_t pos =*/ lseek(dev->fd, over_read, SEEK_CUR);
243       /* should have pos % 2048 == 0 */
244       return (int) (bytes / DVD_VIDEO_LB_LEN);
245     }
246
247     len -= ret;
248   }
249
250   return blocks;
251 }
252
253 /**
254  * close the DVD device and clean up.
255  */
256 static int file_close(dvd_input_t dev)
257 {
258   int ret;
259
260   ret = close(dev->fd);
261
262   if(ret < 0)
263     return ret;
264
265   free(dev);
266
267   return 0;
268 }
269
270
271 /**
272  * Setup read functions with either libdvdcss or minimal DVD access.
273  */
274 int dvdinput_setup(void)
275 {
276   void *dvdcss_library = NULL;
277   char **dvdcss_version = NULL;
278
279 #ifdef HAVE_DVDCSS_DVDCSS_H
280   /* linking to libdvdcss */
281   dvdcss_library = &dvdcss_library;  /* Give it some value != NULL */
282   /* the DVDcss_* functions have been #defined at the top */
283   dvdcss_version = &dvdcss_interface_2;
284
285 #else
286   /* dlopening libdvdcss */
287
288 #ifdef __APPLE__
289   #define CSS_LIB "libdvdcss.2.dylib"
290 #elif defined(WIN32)
291   #define CSS_LIB "libdvdcss.dll"
292 #elif defined(__OS2__)
293   #define CSS_LIB "dvdcss.dll"
294 #else
295   #define CSS_LIB "libdvdcss.so.2"
296 #endif
297   dvdcss_library = dlopen(CSS_LIB, RTLD_LAZY);
298
299   if(dvdcss_library != NULL) {
300 #if defined(__OpenBSD__) && !defined(__ELF__) || defined(__OS2__)
301 #define U_S "_"
302 #else
303 #define U_S
304 #endif
305     DVDcss_open = (dvdcss_t (*)(const char*))
306       dlsym(dvdcss_library, U_S "dvdcss_open");
307     DVDcss_close = (int (*)(dvdcss_t))
308       dlsym(dvdcss_library, U_S "dvdcss_close");
309     DVDcss_title = (int (*)(dvdcss_t, int))
310       dlsym(dvdcss_library, U_S "dvdcss_title");
311     DVDcss_seek = (int (*)(dvdcss_t, int, int))
312       dlsym(dvdcss_library, U_S "dvdcss_seek");
313     DVDcss_read = (int (*)(dvdcss_t, void*, int, int))
314       dlsym(dvdcss_library, U_S "dvdcss_read");
315     DVDcss_error = (char* (*)(dvdcss_t))
316       dlsym(dvdcss_library, U_S "dvdcss_error");
317
318     dvdcss_version = (char **)dlsym(dvdcss_library, U_S "dvdcss_interface_2");
319
320     if(dlsym(dvdcss_library, U_S "dvdcss_crack")) {
321       fprintf(stderr,
322               "libdvdread: Old (pre-0.0.2) version of libdvdcss found.\n"
323               "libdvdread: You should get the latest version from "
324               "http://www.videolan.org/\n" );
325       dlclose(dvdcss_library);
326       dvdcss_library = NULL;
327     } else if(!DVDcss_open  || !DVDcss_close || !DVDcss_title || !DVDcss_seek
328               || !DVDcss_read || !DVDcss_error || !dvdcss_version) {
329       fprintf(stderr,  "libdvdread: Missing symbols in %s, "
330               "this shouldn't happen !\n", CSS_LIB);
331       dlclose(dvdcss_library);
332     }
333   }
334 #endif /* HAVE_DVDCSS_DVDCSS_H */
335
336   if(dvdcss_library != NULL) {
337     /*
338     char *psz_method = getenv( "DVDCSS_METHOD" );
339     char *psz_verbose = getenv( "DVDCSS_VERBOSE" );
340     fprintf(stderr, "DVDCSS_METHOD %s\n", psz_method);
341     fprintf(stderr, "DVDCSS_VERBOSE %s\n", psz_verbose);
342     */
343     fprintf(stderr, "libdvdread: Using libdvdcss version %s for DVD access\n",
344             dvdcss_version ? *dvdcss_version : "");
345
346     /* libdvdcss wrapper functions */
347     dvdinput_open  = css_open;
348     dvdinput_close = css_close;
349     dvdinput_seek  = css_seek;
350     dvdinput_title = css_title;
351     dvdinput_read  = css_read;
352     dvdinput_error = css_error;
353     return 1;
354
355   } else {
356     fprintf(stderr, "libdvdread: Encrypted DVD support unavailable.\n");
357
358     /* libdvdcss replacement functions */
359     dvdinput_open  = file_open;
360     dvdinput_close = file_close;
361     dvdinput_seek  = file_seek;
362     dvdinput_title = file_title;
363     dvdinput_read  = file_read;
364     dvdinput_error = file_error;
365     return 0;
366   }
367 }