]> git.sesse.net Git - vlc/blob - extras/libdvdcss/libdvdcss.c
c3404bea7ba2e5c4c361e9725f103da01ee52c56
[vlc] / extras / libdvdcss / libdvdcss.c
1 /*****************************************************************************
2  * libdvdcss.c: DVD reading library.
3  *****************************************************************************
4  * Copyright (C) 1998-2001 VideoLAN
5  * $Id: libdvdcss.c,v 1.2 2001/06/14 01:49:44 sam Exp $
6  *
7  * Authors: Stéphane Borel <stef@via.ecp.fr>
8  *          Samuel Hocevar <sam@zoy.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  * 
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include "defs.h"
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36
37 #if defined( WIN32 )
38 #   include <io.h>
39 #   include "input_iovec.h"
40 #else
41 #   include <sys/uio.h>                                      /* struct iovec */
42 #endif
43
44 #include "config.h"
45 #include "common.h"
46
47 #include "videolan/dvdcss.h"
48 #include "libdvdcss.h"
49
50 /*****************************************************************************
51  * Local prototypes
52  *****************************************************************************/
53 static int _dvdcss_open  ( dvdcss_handle, char *psz_target );
54 static int _dvdcss_close ( dvdcss_handle );
55 static int _dvdcss_seek  ( dvdcss_handle, int i_blocks );
56 static int _dvdcss_read  ( dvdcss_handle, void *p_buffer, int i_blocks );
57 static int _dvdcss_readv ( dvdcss_handle, struct iovec *p_iovec, int i_blocks );
58
59 /*****************************************************************************
60  * dvdcss_open: initialize library, open a DVD device, crack CSS key
61  *****************************************************************************/
62 extern dvdcss_handle dvdcss_open ( char *psz_target, int i_flags )
63 {
64     int i_ret;
65
66     dvdcss_handle dvdcss;
67
68     /* Allocate the library structure */
69     dvdcss = malloc( sizeof( struct dvdcss_s ) );
70     if( dvdcss == NULL )
71     {
72         if( ! (i_flags & DVDCSS_INIT_QUIET) )
73         {
74             DVDCSS_ERROR( "could not initialize library" );
75         }
76
77         return NULL;
78     }
79
80     /* Initialize structure */
81     dvdcss->b_debug = i_flags & DVDCSS_INIT_DEBUG;
82     dvdcss->b_errors = !(i_flags & DVDCSS_INIT_QUIET);
83     dvdcss->psz_error = "no error";
84
85     i_ret = _dvdcss_open( dvdcss, psz_target );
86     if( i_ret < 0 )
87     {
88         free( dvdcss );
89         return NULL;
90     }
91
92     i_ret = CSSTest( dvdcss );
93     if( i_ret < 0 )
94     {
95         _dvdcss_error( dvdcss, "css test failed" );
96         _dvdcss_close( dvdcss );
97         free( dvdcss );
98         return NULL;
99     }
100
101     dvdcss->b_encrypted = i_ret;
102
103     /* If drive is encrypted, crack its key */
104     if( dvdcss->b_encrypted )
105     {
106         i_ret = CSSInit( dvdcss );
107
108         if( i_ret < 0 )
109         {
110             _dvdcss_close( dvdcss );
111             free( dvdcss );
112             return NULL;
113         }
114     }
115
116     return dvdcss;
117 }
118
119 /*****************************************************************************
120  * dvdcss_error: return the last libdvdcss error message
121  *****************************************************************************/
122 extern char * dvdcss_error ( dvdcss_handle dvdcss )
123 {
124     return dvdcss->psz_error;
125 }
126
127 /*****************************************************************************
128  * dvdcss_seek: seek into the device
129  *****************************************************************************/
130 extern int dvdcss_seek ( dvdcss_handle dvdcss, int i_blocks )
131 {
132     return _dvdcss_seek( dvdcss, i_blocks );
133 }
134
135 /*****************************************************************************
136  * dvdcss_crack: crack the current title key
137  *****************************************************************************/
138 extern int dvdcss_crack ( dvdcss_handle dvdcss, int i_title, int i_block )
139 {
140     int i_ret;
141
142     if( ! dvdcss->b_encrypted )
143     {
144         return 0;
145     }
146
147     /* Crack CSS title key for current VTS */
148     dvdcss->css.i_title = i_title;
149     dvdcss->css.i_title_pos = i_block;
150
151     i_ret = CSSGetKey( dvdcss );
152
153     if( i_ret < 0 )
154     {
155         _dvdcss_error( dvdcss, "fatal error in vts css key" );
156         return i_ret;
157     }
158     else if( i_ret > 0 )
159     {
160         _dvdcss_error( dvdcss, "decryption unavailable" );
161         return -1;
162     }
163
164     return 0;
165 }
166
167 /*****************************************************************************
168  * dvdcss_read: read data from the device, decrypt if requested
169  *****************************************************************************/
170 extern int dvdcss_read ( dvdcss_handle dvdcss, void *p_buffer,
171                                                int i_blocks,
172                                                int i_flags )
173 {
174     int i_ret;
175
176     i_ret = _dvdcss_read( dvdcss, p_buffer, i_blocks );
177
178     if( i_ret != i_blocks
179          || !dvdcss->b_encrypted
180          || !(i_flags & DVDCSS_READ_DECRYPT) )
181     {
182         return i_ret;
183     }
184
185     while( i_ret )
186     {
187         CSSDescrambleSector( dvdcss->css.pi_title_key, p_buffer );
188         ((u8*)p_buffer)[0x14] &= 0x8f;
189         (u8*)p_buffer += DVDCSS_BLOCK_SIZE;
190         i_ret--;
191     }
192
193     return i_blocks;
194 }
195
196 /*****************************************************************************
197  * dvdcss_readv: read data to an iovec structure, decrypt if reaquested
198  *****************************************************************************/
199 extern int dvdcss_readv ( dvdcss_handle dvdcss, void *p_iovec,
200                                                 int i_blocks,
201                                                 int i_flags )
202 {
203 #define P_IOVEC ((struct iovec*)p_iovec)
204     int i_ret;
205     void *iov_base;
206     size_t iov_len;
207
208     i_ret = _dvdcss_readv( dvdcss, P_IOVEC, i_blocks );
209
210     if( i_ret != i_blocks
211          || !dvdcss->b_encrypted
212          || !(i_flags & DVDCSS_READ_DECRYPT) )
213     {
214         return i_ret;
215     }
216
217     /* Initialize loop for decryption */
218     iov_base = P_IOVEC->iov_base;
219     iov_len = P_IOVEC->iov_len;
220
221     while( i_ret )
222     {
223         /* Check that iov_len is a multiple of 2048 */
224         if( iov_len & 0x7ff )
225         {
226             return -1;
227         }
228
229         while( iov_len == 0 )
230         {
231             P_IOVEC++;
232             iov_base = P_IOVEC->iov_base;
233             iov_len = P_IOVEC->iov_len;
234         }
235
236         CSSDescrambleSector( dvdcss->css.pi_title_key, iov_base );
237         ((u8*)iov_base)[0x14] &= 0x8f;
238
239         (u8*)iov_base += DVDCSS_BLOCK_SIZE;
240         (u8*)iov_len -= DVDCSS_BLOCK_SIZE;
241
242         i_ret--;
243     }
244
245     return i_blocks;
246 #undef P_IOVEC
247 }
248
249 /*****************************************************************************
250  * dvdcss_close: close the DVD device and clean up the library
251  *****************************************************************************/
252 extern int dvdcss_close ( dvdcss_handle dvdcss )
253 {
254     int i_ret;
255
256     i_ret = _dvdcss_close( dvdcss );
257
258     if( i_ret < 0 )
259     {
260         return i_ret;
261     }
262
263     free( dvdcss );
264
265     return 0;
266 }
267
268 /* Following functions are local */
269
270 static int _dvdcss_open ( dvdcss_handle dvdcss, char *psz_target )
271 {
272 #if defined( WIN32 )
273     snprintf( buf, 7, "\\\\.\\%c:", psz_target[0] );
274     (HANDLE) dvdcss->i_fd =
275             CreateFile( psz_target, GENERIC_READ | GENERIC_WRITE,
276                                     FILE_SHARE_READ | FILE_SHARE_WRITE,
277                                     NULL, OPEN_EXISTING, 0, NULL );
278     if( (HANDLE) dvdcss->i_fd == INVALID_HANDLE_VALUE )
279     {
280         _dvdcss_error( dvdcss, "failed opening device" );
281         return -1;
282     }
283
284 #else
285     dvdcss->i_fd = open( psz_target, 0 );
286
287     if( dvdcss->i_fd == -1 )
288     {
289         _dvdcss_error( dvdcss, "failed opening device" );
290         return -1;
291     }
292
293 #endif
294
295     return 0;
296 }
297
298 static int _dvdcss_close ( dvdcss_handle dvdcss )
299 {
300 #if defined( WIN32 )
301     CloseHandle( (HANDLE) dvdcss->i_fd );
302 #else
303     close( dvdcss->i_fd );
304 #endif
305
306     return 0;
307 }
308
309 static int _dvdcss_seek ( dvdcss_handle dvdcss, int i_blocks )
310 {
311     off_t i_read;
312
313 #if defined( WIN32 )
314     i_read = SetFilePointer( (HANDLE) dvdcss->i_fd,
315                              (off_t)i_blocks * (off_t)DVDCSS_BLOCK_SIZE,
316                              NULL, FILE_BEGIN );
317 #else
318     i_read = lseek( dvdcss->i_fd,
319                     (off_t)i_blocks * (off_t)DVDCSS_BLOCK_SIZE, SEEK_SET );
320
321 #endif
322
323     return i_read / DVDCSS_BLOCK_SIZE;
324 }
325
326 static int _dvdcss_read ( dvdcss_handle dvdcss, void *p_buffer, int i_blocks )
327 {
328 #if defined( WIN32 )
329     DWORD i_read;
330     if( ReadFile( (HANDLE) dvdcss->i_fd, p_buffer,
331                   (off_t)i_blocks * (off_t)DVDCSS_BLOCK_SIZE,
332                   &i_read, NULL ) == -1 )
333     {
334         return 0;
335     }
336
337 #else
338     off_t i_read;
339     i_read = read( dvdcss->i_fd, p_buffer,
340                    (off_t)i_blocks * (off_t)DVDCSS_BLOCK_SIZE );
341
342 #endif
343
344     return i_read / DVDCSS_BLOCK_SIZE;
345 }
346
347 static int _dvdcss_readv ( dvdcss_handle dvdcss, struct iovec *p_iovec, int i_blocks )
348 {
349     off_t i_read;
350     i_read = readv( dvdcss->i_fd, p_iovec, i_blocks );
351
352     return i_read / DVDCSS_BLOCK_SIZE;
353 }
354