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 $
7 * Authors: Stéphane Borel <stef@via.ecp.fr>
8 * Samuel Hocevar <sam@zoy.org>
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.
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.
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 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
32 #include <sys/types.h>
39 # include "input_iovec.h"
41 # include <sys/uio.h> /* struct iovec */
47 #include "videolan/dvdcss.h"
48 #include "libdvdcss.h"
50 /*****************************************************************************
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 );
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 )
68 /* Allocate the library structure */
69 dvdcss = malloc( sizeof( struct dvdcss_s ) );
72 if( ! (i_flags & DVDCSS_INIT_QUIET) )
74 DVDCSS_ERROR( "could not initialize library" );
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";
85 i_ret = _dvdcss_open( dvdcss, psz_target );
92 i_ret = CSSTest( dvdcss );
95 _dvdcss_error( dvdcss, "css test failed" );
96 _dvdcss_close( dvdcss );
101 dvdcss->b_encrypted = i_ret;
103 /* If drive is encrypted, crack its key */
104 if( dvdcss->b_encrypted )
106 i_ret = CSSInit( dvdcss );
110 _dvdcss_close( dvdcss );
119 /*****************************************************************************
120 * dvdcss_error: return the last libdvdcss error message
121 *****************************************************************************/
122 extern char * dvdcss_error ( dvdcss_handle dvdcss )
124 return dvdcss->psz_error;
127 /*****************************************************************************
128 * dvdcss_seek: seek into the device
129 *****************************************************************************/
130 extern int dvdcss_seek ( dvdcss_handle dvdcss, int i_blocks )
132 return _dvdcss_seek( dvdcss, i_blocks );
135 /*****************************************************************************
136 * dvdcss_crack: crack the current title key
137 *****************************************************************************/
138 extern int dvdcss_crack ( dvdcss_handle dvdcss, int i_title, int i_block )
142 if( ! dvdcss->b_encrypted )
147 /* Crack CSS title key for current VTS */
148 dvdcss->css.i_title = i_title;
149 dvdcss->css.i_title_pos = i_block;
151 i_ret = CSSGetKey( dvdcss );
155 _dvdcss_error( dvdcss, "fatal error in vts css key" );
160 _dvdcss_error( dvdcss, "decryption unavailable" );
167 /*****************************************************************************
168 * dvdcss_read: read data from the device, decrypt if requested
169 *****************************************************************************/
170 extern int dvdcss_read ( dvdcss_handle dvdcss, void *p_buffer,
176 i_ret = _dvdcss_read( dvdcss, p_buffer, i_blocks );
178 if( i_ret != i_blocks
179 || !dvdcss->b_encrypted
180 || !(i_flags & DVDCSS_READ_DECRYPT) )
187 CSSDescrambleSector( dvdcss->css.pi_title_key, p_buffer );
188 ((u8*)p_buffer)[0x14] &= 0x8f;
189 (u8*)p_buffer += DVDCSS_BLOCK_SIZE;
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,
203 #define P_IOVEC ((struct iovec*)p_iovec)
208 i_ret = _dvdcss_readv( dvdcss, P_IOVEC, i_blocks );
210 if( i_ret != i_blocks
211 || !dvdcss->b_encrypted
212 || !(i_flags & DVDCSS_READ_DECRYPT) )
217 /* Initialize loop for decryption */
218 iov_base = P_IOVEC->iov_base;
219 iov_len = P_IOVEC->iov_len;
223 /* Check that iov_len is a multiple of 2048 */
224 if( iov_len & 0x7ff )
229 while( iov_len == 0 )
232 iov_base = P_IOVEC->iov_base;
233 iov_len = P_IOVEC->iov_len;
236 CSSDescrambleSector( dvdcss->css.pi_title_key, iov_base );
237 ((u8*)iov_base)[0x14] &= 0x8f;
239 (u8*)iov_base += DVDCSS_BLOCK_SIZE;
240 (u8*)iov_len -= DVDCSS_BLOCK_SIZE;
249 /*****************************************************************************
250 * dvdcss_close: close the DVD device and clean up the library
251 *****************************************************************************/
252 extern int dvdcss_close ( dvdcss_handle dvdcss )
256 i_ret = _dvdcss_close( dvdcss );
268 /* Following functions are local */
270 static int _dvdcss_open ( dvdcss_handle dvdcss, char *psz_target )
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 )
280 _dvdcss_error( dvdcss, "failed opening device" );
285 dvdcss->i_fd = open( psz_target, 0 );
287 if( dvdcss->i_fd == -1 )
289 _dvdcss_error( dvdcss, "failed opening device" );
298 static int _dvdcss_close ( dvdcss_handle dvdcss )
301 CloseHandle( (HANDLE) dvdcss->i_fd );
303 close( dvdcss->i_fd );
309 static int _dvdcss_seek ( dvdcss_handle dvdcss, int i_blocks )
314 i_read = SetFilePointer( (HANDLE) dvdcss->i_fd,
315 (off_t)i_blocks * (off_t)DVDCSS_BLOCK_SIZE,
318 i_read = lseek( dvdcss->i_fd,
319 (off_t)i_blocks * (off_t)DVDCSS_BLOCK_SIZE, SEEK_SET );
323 return i_read / DVDCSS_BLOCK_SIZE;
326 static int _dvdcss_read ( dvdcss_handle dvdcss, void *p_buffer, int i_blocks )
330 if( ReadFile( (HANDLE) dvdcss->i_fd, p_buffer,
331 (off_t)i_blocks * (off_t)DVDCSS_BLOCK_SIZE,
332 &i_read, NULL ) == -1 )
339 i_read = read( dvdcss->i_fd, p_buffer,
340 (off_t)i_blocks * (off_t)DVDCSS_BLOCK_SIZE );
344 return i_read / DVDCSS_BLOCK_SIZE;
347 static int _dvdcss_readv ( dvdcss_handle dvdcss, struct iovec *p_iovec, int i_blocks )
350 i_read = readv( dvdcss->i_fd, p_iovec, i_blocks );
352 return i_read / DVDCSS_BLOCK_SIZE;