Replace deprecated dvdcss_title() function by dvdcss_seek().
[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_read    dvdcss_read
47 #define DVDcss_error   dvdcss_error
48 #else
49
50 /* dlopening libdvdcss */
51 #if defined(HAVE_DLFCN_H) && !defined(USING_BUILTIN_DLFCN)
52 #include <dlfcn.h>
53 #else
54 #if defined(WIN32)
55 /* Only needed on MINGW at the moment */
56 #include "../msvc/contrib/dlfcn.c"
57 #endif
58 #endif
59
60 typedef struct dvdcss_s *dvdcss_t;
61 static dvdcss_t (*DVDcss_open)  (const char *);
62 static int      (*DVDcss_close) (dvdcss_t);
63 static int      (*DVDcss_seek)  (dvdcss_t, int, int);
64 static int      (*DVDcss_read)  (dvdcss_t, void *, int, int);
65 static char *   (*DVDcss_error) (dvdcss_t);
66 #define DVDCSS_SEEK_KEY (1 << 1)
67 #endif
68
69 /* The DVDinput handle, add stuff here for new input methods. */
70 struct dvd_input_s {
71   /* libdvdcss handle */
72   dvdcss_t dvdcss;
73
74   /* dummy file input */
75   int fd;
76 };
77
78
79 /**
80  * initialize and open a DVD device or file.
81  */
82 static dvd_input_t css_open(const char *target)
83 {
84   dvd_input_t dev;
85
86   /* Allocate the handle structure */
87   dev = (dvd_input_t) malloc(sizeof(*dev));
88   if(dev == NULL) {
89     fprintf(stderr, "libdvdread: Could not allocate memory.\n");
90     return NULL;
91   }
92
93   /* Really open it with libdvdcss */
94   dev->dvdcss = DVDcss_open(target);
95   if(dev->dvdcss == 0) {
96     fprintf(stderr, "libdvdread: Could not open %s with libdvdcss.\n", target);
97     free(dev);
98     return NULL;
99   }
100
101   return dev;
102 }
103
104 /**
105  * return the last error message
106  */
107 static char *css_error(dvd_input_t dev)
108 {
109   return DVDcss_error(dev->dvdcss);
110 }
111
112 /**
113  * seek into the device.
114  */
115 static int css_seek(dvd_input_t dev, int blocks)
116 {
117   /* DVDINPUT_NOFLAGS should match the DVDCSS_NOFLAGS value. */
118   return DVDcss_seek(dev->dvdcss, blocks, DVDINPUT_NOFLAGS);
119 }
120
121 /**
122  * set the block for the beginning of a new title (key).
123  */
124 static int css_title(dvd_input_t dev, int block)
125 {
126   return DVDcss_seek(dev->dvdcss, block, DVDCSS_SEEK_KEY);
127 }
128
129 /**
130  * read data from the device.
131  */
132 static int css_read(dvd_input_t dev, void *buffer, int blocks, int flags)
133 {
134   return DVDcss_read(dev->dvdcss, buffer, blocks, flags);
135 }
136
137 /**
138  * close the DVD device and clean up the library.
139  */
140 static int css_close(dvd_input_t dev)
141 {
142   int ret;
143
144   ret = DVDcss_close(dev->dvdcss);
145
146   if(ret < 0)
147     return ret;
148
149   free(dev);
150
151   return 0;
152 }
153
154 /**
155  * initialize and open a DVD device or file.
156  */
157 static dvd_input_t file_open(const char *target)
158 {
159   dvd_input_t dev;
160
161   /* Allocate the library structure */
162   dev = (dvd_input_t) malloc(sizeof(*dev));
163   if(dev == NULL) {
164     fprintf(stderr, "libdvdread: Could not allocate memory.\n");
165     return NULL;
166   }
167
168   /* Open the device */
169 #if !defined(WIN32) && !defined(__OS2__)
170   dev->fd = open(target, O_RDONLY);
171 #else
172   dev->fd = open(target, O_RDONLY | O_BINARY);
173 #endif
174   if(dev->fd < 0) {
175     perror("libdvdread: Could not open input");
176     free(dev);
177     return NULL;
178   }
179
180   return dev;
181 }
182
183 /**
184  * return the last error message
185  */
186 static char *file_error(dvd_input_t dev)
187 {
188   /* use strerror(errno)? */
189   return (char *)"unknown error";
190 }
191
192 /**
193  * seek into the device.
194  */
195 static int file_seek(dvd_input_t dev, int blocks)
196 {
197   off_t pos;
198
199   pos = lseek(dev->fd, (off_t)blocks * (off_t)DVD_VIDEO_LB_LEN, SEEK_SET);
200   if(pos < 0) {
201     return pos;
202   }
203   /* assert pos % DVD_VIDEO_LB_LEN == 0 */
204   return (int) (pos / DVD_VIDEO_LB_LEN);
205 }
206
207 /**
208  * set the block for the beginning of a new title (key).
209  */
210 static int file_title(dvd_input_t dev, int block)
211 {
212   return -1;
213 }
214
215 /**
216  * read data from the device.
217  */
218 static int file_read(dvd_input_t dev, void *buffer, int blocks, int flags)
219 {
220   size_t len;
221   ssize_t ret;
222
223   len = (size_t)blocks * DVD_VIDEO_LB_LEN;
224
225   while(len > 0) {
226
227     ret = read(dev->fd, buffer, len);
228
229     if(ret < 0) {
230       /* One of the reads failed, too bad.  We won't even bother
231        * returning the reads that went OK, and as in the POSIX spec
232        * the file position is left unspecified after a failure. */
233       return ret;
234     }
235
236     if(ret == 0) {
237       /* Nothing more to read.  Return all of the whole blocks, if any.
238        * Adjust the file position back to the previous block boundary. */
239       size_t bytes = (size_t)blocks * DVD_VIDEO_LB_LEN - len;
240       off_t over_read = -(bytes % DVD_VIDEO_LB_LEN);
241       /*off_t pos =*/ lseek(dev->fd, over_read, SEEK_CUR);
242       /* should have pos % 2048 == 0 */
243       return (int) (bytes / DVD_VIDEO_LB_LEN);
244     }
245
246     len -= ret;
247   }
248
249   return blocks;
250 }
251
252 /**
253  * close the DVD device and clean up.
254  */
255 static int file_close(dvd_input_t dev)
256 {
257   int ret;
258
259   ret = close(dev->fd);
260
261   if(ret < 0)
262     return ret;
263
264   free(dev);
265
266   return 0;
267 }
268
269
270 /**
271  * Setup read functions with either libdvdcss or minimal DVD access.
272  */
273 int dvdinput_setup(void)
274 {
275   void *dvdcss_library = NULL;
276
277 #ifdef HAVE_DVDCSS_DVDCSS_H
278   /* linking to libdvdcss */
279   dvdcss_library = &dvdcss_library;  /* Give it some value != NULL */
280
281 #else
282   /* dlopening libdvdcss */
283
284 #ifdef __APPLE__
285   #define CSS_LIB "libdvdcss.2.dylib"
286 #elif defined(WIN32)
287   #define CSS_LIB "libdvdcss.dll"
288 #elif defined(__OS2__)
289   #define CSS_LIB "dvdcss.dll"
290 #else
291   #define CSS_LIB "libdvdcss.so.2"
292 #endif
293   dvdcss_library = dlopen(CSS_LIB, RTLD_LAZY);
294
295   if(dvdcss_library != NULL) {
296 #if defined(__OpenBSD__) && !defined(__ELF__) || defined(__OS2__)
297 #define U_S "_"
298 #else
299 #define U_S
300 #endif
301     DVDcss_open = (dvdcss_t (*)(const char*))
302       dlsym(dvdcss_library, U_S "dvdcss_open");
303     DVDcss_close = (int (*)(dvdcss_t))
304       dlsym(dvdcss_library, U_S "dvdcss_close");
305     DVDcss_seek = (int (*)(dvdcss_t, int, int))
306       dlsym(dvdcss_library, U_S "dvdcss_seek");
307     DVDcss_read = (int (*)(dvdcss_t, void*, int, int))
308       dlsym(dvdcss_library, U_S "dvdcss_read");
309     DVDcss_error = (char* (*)(dvdcss_t))
310       dlsym(dvdcss_library, U_S "dvdcss_error");
311
312     if(dlsym(dvdcss_library, U_S "dvdcss_crack")) {
313       fprintf(stderr,
314               "libdvdread: Old (pre-0.0.2) version of libdvdcss found.\n"
315               "libdvdread: You should get the latest version from "
316               "http://www.videolan.org/\n" );
317       dlclose(dvdcss_library);
318       dvdcss_library = NULL;
319     } else if(!DVDcss_open  || !DVDcss_close || !DVDcss_seek
320               || !DVDcss_read || !DVDcss_error) {
321       fprintf(stderr,  "libdvdread: Missing symbols in %s, "
322               "this shouldn't happen !\n", CSS_LIB);
323       dlclose(dvdcss_library);
324     }
325   }
326 #endif /* HAVE_DVDCSS_DVDCSS_H */
327
328   if(dvdcss_library != NULL) {
329     /*
330     char *psz_method = getenv( "DVDCSS_METHOD" );
331     char *psz_verbose = getenv( "DVDCSS_VERBOSE" );
332     fprintf(stderr, "DVDCSS_METHOD %s\n", psz_method);
333     fprintf(stderr, "DVDCSS_VERBOSE %s\n", psz_verbose);
334     */
335
336     /* libdvdcss wrapper functions */
337     dvdinput_open  = css_open;
338     dvdinput_close = css_close;
339     dvdinput_seek  = css_seek;
340     dvdinput_title = css_title;
341     dvdinput_read  = css_read;
342     dvdinput_error = css_error;
343     return 1;
344
345   } else {
346     fprintf(stderr, "libdvdread: Encrypted DVD support unavailable.\n");
347
348     /* libdvdcss replacement functions */
349     dvdinput_open  = file_open;
350     dvdinput_close = file_close;
351     dvdinput_seek  = file_seek;
352     dvdinput_title = file_title;
353     dvdinput_read  = file_read;
354     dvdinput_error = file_error;
355     return 0;
356   }
357 }