Work at SourceForge, help us to make it a better place! We have an immediate need for a Support Technician in our San Francisco or Denver office.

Close

Diff of /src/libdvdcss.c [104348] .. [d040ac] Maximize Restore

  Switch to unified view

a/src/libdvdcss.c b/src/libdvdcss.c
1
/*****************************************************************************
1
/* libdvdcss.c: DVD reading library.
2
 * libdvdcss.c: DVD reading library.
3
 *****************************************************************************
4
 * Copyright (C) 1998-2001 VideoLAN
5
 * $Id: libdvdcss.c,v 1.1 2001/12/22 00:08:13 sam Exp $
2
 *
6
 *
3
 * Authors: StĂŠphane Borel <stef@via.ecp.fr>
7
 * Authors: Stéphane Borel <stef@via.ecp.fr>
4
 *          Sam Hocevar <sam@zoy.org>
8
 *          Samuel Hocevar <sam@zoy.org>
5
 *          HĂĽkan Hjort <d95hjort@dtek.chalmers.se>
9
 *          Hĺkan Hjort <d95hjort@dtek.chalmers.se>
6
 *
7
 * Copyright (C) 1998-2008 VideoLAN
8
 * $Id$
9
 *
10
 *
10
 * This program is free software; you can redistribute it and/or modify
11
 * 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
 * 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
 * the Free Software Foundation; either version 2 of the License, or
13
 * (at your option) any later version.
14
 * (at your option) any later version.
14
 *
15
 * 
15
 * This program is distributed in the hope that it will be useful,
16
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU General Public License for more details.
19
 * GNU General Public License for more details.
19
 *
20
 *
20
 * You should have received a copy of the GNU General Public License
21
 * 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
 * along with this program; if not, write to the Free Software
22
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23
 */
24
 *****************************************************************************/
24
25
25
/**
26
/*****************************************************************************
26
 * \mainpage libdvdcss developer documentation
27
 *
28
 * \section intro Introduction
29
 *
30
 * \e libdvdcss is a simple library designed for accessing DVDs like a block
31
 * device without having to bother about the decryption. The important features
32
 * are:
33
 * \li portability: currently supported platforms are GNU/Linux, FreeBSD,
34
 *     NetBSD, OpenBSD, BSD/OS, BeOS, Windows 95/98, Windows NT/2000, MacOS X,
35
 *     Solaris, HP-UX and OS/2.
36
 * \li adaptability: unlike most similar projects, libdvdcss doesn't require
37
 *     the region of your drive to be set and will try its best to read from
38
 *     the disc even in the case of a region mismatch.
39
 * \li simplicity: a DVD player can be built around the \e libdvdcss API using
40
 *     no more than 4 or 5 library calls.
41
 *
42
 * \e libdvdcss is free software, released under the General Public License.
43
 * This ensures that \e libdvdcss remains free and used only with free
44
 * software.
45
 *
46
 * \section api The libdvdcss API
47
 *
48
 * The complete \e libdvdcss programming interface is documented in the
49
 * dvdcss.h file.
50
 *
51
 * \section env Environment variables
52
 *
53
 * Some environment variables can be used to change the behaviour of
54
 * \e libdvdcss without having to modify the program which uses it. These
55
 * variables are:
56
 *
57
 * \li \b DVDCSS_VERBOSE: sets the verbosity level.
58
 *     - \c 0 outputs no messages at all.
59
 *     - \c 1 outputs error messages to stderr.
60
 *     - \c 2 outputs error messages and debug messages to stderr.
61
 *
62
 * \li \b DVDCSS_METHOD: sets the authentication and decryption method
63
 *     that \e libdvdcss will use to read scrambled discs. Can be one
64
 *     of \c title, \c key or \c disc.
65
 *     - \c key is the default method. \e libdvdcss will use a set of
66
 *       calculated player keys to try and get the disc key. This can fail
67
 *       if the drive does not recognize any of the player keys.
68
 *     - \c disc is a fallback method when \c key has failed. Instead of
69
 *       using player keys, \e libdvdcss will crack the disc key using
70
 *       a brute force algorithm. This process is CPU intensive and requires
71
 *       64 MB of memory to store temporary data.
72
 *     - \c title is the fallback when all other methods have failed. It does
73
 *       not rely on a key exchange with the DVD drive, but rather uses a
74
 *       crypto attack to guess the title key. On rare cases this may fail
75
 *       because there is not enough encrypted data on the disc to perform
76
 *       a statistical attack, but in the other hand it is the only way to
77
 *       decrypt a DVD stored on a hard disc, or a DVD with the wrong region
78
 *       on an RPC2 drive.
79
 *
80
 * \li \b DVDCSS_RAW_DEVICE: specify the raw device to use. Exact usage will
81
 *     depend on your operating system, the Linux utility to set up raw devices
82
 *     is \c raw(8) for instance. Please note that on most operating systems,
83
 *     using a raw device requires highly aligned buffers: Linux requires a
84
 *     2048 bytes alignment (which is the size of a DVD sector).
85
 *
86
 * \li \b DVDCSS_CACHE: specify a directory in which to store title key
87
 *     values. This will speed up descrambling of DVDs which are in the
88
 *     cache. The DVDCSS_CACHE directory is created if it does not exist,
89
 *     and a subdirectory is created named after the DVD's title or
90
 *     manufacturing date. If DVDCSS_CACHE is not set or is empty, \e libdvdcss
91
 *     will use the default value which is "${HOME}/.dvdcss/" under Unix and
92
 *     "C:\Documents and Settings\$USER\Application Data\dvdcss\" under Win32.
93
 *     The special value "off" disables caching.
94
 */
95
96
/*
97
 * Preamble
27
 * Preamble
98
 */
28
 *****************************************************************************/
99
#include "config.h"
29
#include "config.h"
100
30
101
#include <stdio.h>
31
#include <stdio.h>
102
#include <stdlib.h>
32
#include <stdlib.h>
103
#include <string.h>
33
#include <string.h>
104
#include <sys/types.h>
34
#include <sys/types.h>
105
#include <sys/stat.h>
35
#include <sys/stat.h>
106
#ifdef HAVE_SYS_PARAM_H
107
#   include <sys/param.h>
108
#endif
109
#ifdef HAVE_PWD_H
110
#   include <pwd.h>
111
#endif
112
#include <fcntl.h>
36
#include <fcntl.h>
113
#include <errno.h>
114
37
115
#ifdef HAVE_UNISTD_H
38
#ifdef HAVE_UNISTD_H
116
#   include <unistd.h>
39
#   include <unistd.h>
117
#endif
40
#endif
118
41
119
#ifdef HAVE_LIMITS_H
42
#if defined( WIN32 )
120
#   include <limits.h>
43
#   include <io.h>                                                 /* read() */
44
#else
45
#   include <sys/uio.h>                                      /* struct iovec */
121
#endif
46
#endif
122
47
123
#ifdef HAVE_DIRECT_H
48
#if defined( WIN32 )
124
#   include <direct.h>
49
#   include "input_iovec.h"
125
#endif
50
#endif
126
51
127
#include "dvdcss/dvdcss.h"
52
#include "dvdcss.h"
128
53
129
#include "common.h"
54
#include "common.h"
130
#include "css.h"
55
#include "css.h"
131
#include "libdvdcss.h"
56
#include "libdvdcss.h"
57
#include "csstables.h"
132
#include "ioctl.h"
58
#include "ioctl.h"
133
#include "device.h"
134
59
135
/**
60
/*****************************************************************************
136
 * \brief Symbol for version checks.
61
 * Local prototypes
137
 *
62
 *****************************************************************************/
138
 * The name of this symbol contains the library major number, which makes it
63
static int _dvdcss_open  ( dvdcss_handle, char *psz_target );
139
 * easy to check which \e libdvdcss development headers are installed on the
64
static int _dvdcss_close ( dvdcss_handle );
140
 * system with tools such as autoconf.
65
static int _dvdcss_readv ( dvdcss_handle, struct iovec *p_iovec, int i_blocks );
141
 *
142
 * The variable itself contains the exact version number of the library,
143
 * which can be useful for specific feature needs.
144
 */
145
char * dvdcss_interface_2 = VERSION;
146
66
147
/**
67
/*****************************************************************************
148
 * \brief Open a DVD device or directory and return a dvdcss instance.
68
 * Local prototypes, win32 specific
149
 *
69
 *****************************************************************************/
150
 * \param psz_target a string containing the target name, for instance
70
#if defined( WIN32 )
151
 *        "/dev/hdc" or "E:".
71
static int _win32_dvdcss_readv  ( int i_fd, struct iovec *p_iovec,
152
 * \return a handle to a dvdcss instance or NULL on error.
72
                                  int i_num_buffers, char *p_tmp_buffer );
153
 *
73
static int _win32_dvdcss_aopen  ( char c_drive, dvdcss_handle dvdcss );
154
 * Initialize the \e libdvdcss library and open the requested DVD device or
74
static int _win32_dvdcss_aclose ( int i_fd );
155
 * directory. \e libdvdcss checks whether ioctls can be performed on the disc,
75
static int _win32_dvdcss_aseek  ( int i_fd, int i_blocks, int i_method );
156
 * and when possible, the disc key is retrieved.
76
static int _win32_dvdcss_aread  ( int i_fd, void *p_data, int i_blocks );
157
 *
77
#else
158
 * dvdcss_open() returns a handle to be used for all subsequent \e libdvdcss
78
static int _dvdcss_raw_open     ( dvdcss_handle, char *psz_target );
159
 * calls. If an error occurred, NULL is returned.
79
#endif
160
 */
80
161
LIBDVDCSS_EXPORT dvdcss_t dvdcss_open ( char *psz_target )
81
/*****************************************************************************
82
 * dvdcss_open: initialize library, open a DVD device, crack CSS key
83
 *****************************************************************************/
84
extern dvdcss_handle dvdcss_open ( char *psz_target )
162
{
85
{
163
    char psz_buffer[PATH_MAX];
164
    int i_ret;
86
    int i_ret;
165
87
166
    char *psz_method = getenv( "DVDCSS_METHOD" );
88
    char *psz_method = getenv( "DVDCSS_METHOD" );
167
    char *psz_verbose = getenv( "DVDCSS_VERBOSE" );
89
    char *psz_verbose = getenv( "DVDCSS_VERBOSE" );
168
    char *psz_cache = getenv( "DVDCSS_CACHE" );
169
#ifndef WIN32
90
#ifndef WIN32
170
    char *psz_raw_device = getenv( "DVDCSS_RAW_DEVICE" );
91
    char *psz_raw_device = getenv( "DVDCSS_RAW_DEVICE" );
171
#endif
92
#endif
172
93
173
    dvdcss_t dvdcss;
94
    dvdcss_handle dvdcss;
174
95
175
    /*
176
     *  Allocate the library structure
96
    /* Allocate the library structure */
177
     */
178
    dvdcss = malloc( sizeof( struct dvdcss_s ) );
97
    dvdcss = malloc( sizeof( struct dvdcss_s ) );
179
    if( dvdcss == NULL )
98
    if( dvdcss == NULL )
180
    {
99
    {
181
        return NULL;
100
        return NULL;
182
    }
101
    }
183
102
184
    /*
185
     *  Initialize structure with default values
103
    /* Initialize structure with default values */
186
     */
187
#ifndef WIN32
188
    dvdcss->i_raw_fd = -1;
189
#endif
190
    dvdcss->p_titles = NULL;
104
    dvdcss->p_titles = NULL;
191
    dvdcss->psz_device = (char *)strdup( psz_target );
192
    dvdcss->psz_error = "no error";
105
    dvdcss->psz_error = "no error";
193
    dvdcss->i_method = DVDCSS_METHOD_KEY;
106
    dvdcss->i_method = DVDCSS_METHOD_TITLE;
194
    dvdcss->psz_cachefile[0] = '\0';
195
    dvdcss->b_debug = 0;
107
    dvdcss->b_debug = 0;
196
    dvdcss->b_errors = 0;
108
    dvdcss->b_errors = 1;
197
109
198
    /*
199
     *  Find verbosity from DVDCSS_VERBOSE environment variable
200
     */
201
    if( psz_verbose != NULL )
202
    {
203
        int i = atoi( psz_verbose );
204
205
        if( i >= 2 ) dvdcss->b_debug = i;
206
        if( i >= 1 ) dvdcss->b_errors = 1;
207
    }
208
209
    /*
210
     *  Find method from DVDCSS_METHOD environment variable
110
    /* Find method from DVDCSS_METHOD environment variable */
211
     */
212
    if( psz_method != NULL )
111
    if( psz_method != NULL )
213
    {
112
    {
214
        if( !strncmp( psz_method, "key", 4 ) )
113
        if( !strncmp( psz_method, "key", 4 ) )
215
        {
114
        {
216
            dvdcss->i_method = DVDCSS_METHOD_KEY;
115
            dvdcss->i_method = DVDCSS_METHOD_KEY;
...
...
223
        {
122
        {
224
            dvdcss->i_method = DVDCSS_METHOD_TITLE;
123
            dvdcss->i_method = DVDCSS_METHOD_TITLE;
225
        }
124
        }
226
        else
125
        else
227
        {
126
        {
228
            print_error( dvdcss, "unknown decrypt method, please choose "
127
            _dvdcss_error( dvdcss, "unknown decrypt method, please choose "
229
                                 "from 'title', 'key' or 'disc'" );
128
                                   "from 'title', 'key' or 'disc'" );
230
            free( dvdcss->psz_device );
231
            free( dvdcss );
129
            free( dvdcss );
232
            return NULL;
130
            return NULL;
233
        }
131
        }
234
    }
132
    }
235
133
134
    /* Find verbosity from DVDCSS_VERBOSE environment variable */
135
    if( psz_verbose != NULL )
236
    /*
136
    {
237
     *  If DVDCSS_CACHE was not set, try to guess a default value
137
        switch( atoi( psz_verbose ) )
238
     */
239
    if( psz_cache == NULL || psz_cache[0] == '\0' )
240
    {
241
#ifdef HAVE_DIRECT_H
242
        typedef HRESULT( WINAPI *SHGETFOLDERPATH )
243
                       ( HWND, int, HANDLE, DWORD, LPTSTR );
244
245
#   define CSIDL_FLAG_CREATE 0x8000
246
#   define CSIDL_APPDATA 0x1A
247
#   define SHGFP_TYPE_CURRENT 0
248
249
        char psz_home[MAX_PATH];
250
        HINSTANCE p_dll;
251
        SHGETFOLDERPATH p_getpath;
252
253
        *psz_home = '\0';
254
255
        /* Load the shfolder dll to retrieve SHGetFolderPath */
256
        p_dll = LoadLibrary( "shfolder.dll" );
257
        if( p_dll )
258
        {
259
            p_getpath = (void*)GetProcAddress( p_dll, "SHGetFolderPathA" );
260
            if( p_getpath )
261
            {
262
                /* Get the "Application Data" folder for the current user */
263
                if( p_getpath( NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE,
264
                               NULL, SHGFP_TYPE_CURRENT, psz_home ) == S_OK )
265
                {
266
                    FreeLibrary( p_dll );
267
                }
268
                else
269
                {
270
                    *psz_home = '\0';
271
                }
272
            }
273
            FreeLibrary( p_dll );
274
        }
138
        {
275
139
        case 0:
276
        /* Cache our keys in
140
            dvdcss->b_errors = 0;
277
         * C:\Documents and Settings\$USER\Application Data\dvdcss\ */
141
            break;
278
        if( *psz_home )
142
        case 1:
143
            break;
144
        case 2:
145
            dvdcss->b_debug = 1;
146
            break;
147
        default:
148
            _dvdcss_error( dvdcss, "unknown verbose level, please choose "
149
                                   "from '0', '1' or '2'" );
150
            free( dvdcss );
151
            return NULL;
152
            break;
279
        {
153
        }
280
            snprintf( psz_buffer, PATH_MAX, "%s/dvdcss", psz_home );
281
            psz_buffer[PATH_MAX-1] = '\0';
282
            psz_cache = psz_buffer;
283
        }
284
#else
285
        char *psz_home = NULL;
286
#   ifdef HAVE_PWD_H
287
        struct passwd *p_pwd;
288
289
        /* Try looking in password file for home dir. */
290
        p_pwd = getpwuid(getuid());
291
        if( p_pwd )
292
        {
293
            psz_home = p_pwd->pw_dir;
294
        }
295
#   endif
296
297
        if( psz_home == NULL )
298
        {
299
            psz_home = getenv( "HOME" );
300
        }
301
        if( psz_home == NULL )
302
        {
303
            psz_home = getenv( "USERPROFILE" );
304
        }
305
306
        /* Cache our keys in ${HOME}/.dvdcss/ */
307
        if( psz_home )
308
        {
309
            snprintf( psz_buffer, PATH_MAX, "%s/.dvdcss", psz_home );
310
            psz_buffer[PATH_MAX-1] = '\0';
311
            psz_cache = psz_buffer;
312
        }
313
#endif
314
    }
315
316
    /*
317
     *  Find cache dir from the DVDCSS_CACHE environment variable
318
     */
319
    if( psz_cache != NULL )
320
    {
154
    }
321
        if( psz_cache[0] == '\0' || !strcmp( psz_cache, "off" ) )
322
        {
323
            psz_cache = NULL;
324
        }
325
        /* Check that we can add the ID directory and the block filename */
326
        else if( strlen( psz_cache ) + 1 + 32 + 1 + (KEY_SIZE * 2) + 10 + 1
327
                  > PATH_MAX )
328
        {
329
            print_error( dvdcss, "cache directory name is too long" );
330
            psz_cache = NULL;
331
        }
332
    }
333
155
334
    /*
335
     *  Open device
156
    /* Open device */
336
     */
337
    _dvdcss_check( dvdcss );
338
    i_ret = _dvdcss_open( dvdcss );
157
    i_ret = _dvdcss_open( dvdcss, psz_target );
339
    if( i_ret < 0 )
158
    if( i_ret < 0 )
340
    {
159
    {
341
        free( dvdcss->psz_device );
342
        free( dvdcss );
160
        free( dvdcss );
343
        return NULL;
161
        return NULL;
344
    }
162
    }
345
163
346
    dvdcss->b_scrambled = 1; /* Assume the worst */
164
    i_ret = CSSTest( dvdcss );
347
    dvdcss->b_ioctls = _dvdcss_use_ioctls( dvdcss );
165
    if( i_ret < 0 )
348
166
    {
167
        _dvdcss_error( dvdcss, "CSS test failed" );
168
        /* Disable the CSS ioctls and hope that it works? */
349
    if( dvdcss->b_ioctls )
169
        dvdcss->b_ioctls = 0;
170
        dvdcss->b_encrypted = 1;
350
    {
171
    }
351
        i_ret = _dvdcss_test( dvdcss );
172
    else
173
    {
174
        dvdcss->b_ioctls = 1;
175
        dvdcss->b_encrypted = i_ret;
176
    }
177
178
    /* If disc is CSS protected and the ioctls work, authenticate the drive */
179
    if( dvdcss->b_encrypted && dvdcss->b_ioctls )
180
    {
181
        i_ret = CSSGetDiscKey( dvdcss );
182
352
        if( i_ret < 0 )
183
        if( i_ret < 0 )
353
        {
184
        {
354
            /* Disable the CSS ioctls and hope that it works? */
185
            _dvdcss_close( dvdcss );
355
            print_debug( dvdcss,
186
            free( dvdcss );
356
                         "could not check whether the disc was scrambled" );
187
            return NULL;
357
            dvdcss->b_ioctls = 0;
358
        }
359
        else
360
        {
188
        }
361
            print_debug( dvdcss, i_ret ? "disc is scrambled"
362
                                       : "disc is unscrambled" );
363
            dvdcss->b_scrambled = i_ret;
364
        }
365
    }
366
367
    /* If disc is CSS protected and the ioctls work, authenticate the drive */
368
    if( dvdcss->b_scrambled && dvdcss->b_ioctls )
369
    {
189
    }
370
        i_ret = _dvdcss_disckey( dvdcss );
371
372
        if( i_ret < 0 )
373
        {
374
            print_debug( dvdcss, "could not get disc key" );
375
        }
376
    }
377
    else
378
    {
379
        memset( dvdcss->css.p_disc_key, 0, KEY_SIZE );
380
    }
381
382
    /* If the cache is enabled, write the cache directory tag */
383
    if( psz_cache )
384
    {
385
        char *psz_tag = "Signature: 8a477f597d28d172789f06886806bc55\r\n"
386
            "# This file is a cache directory tag created by libdvdcss.\r\n"
387
            "# For information about cache directory tags, see:\r\n"
388
            "#   http://www.brynosaurus.com/cachedir/\r\n";
389
        char psz_tagfile[PATH_MAX + 1 + 12 + 1];
390
        int i_fd;
391
392
        sprintf( psz_tagfile, "%s/CACHEDIR.TAG", psz_cache );
393
        i_fd = open( psz_tagfile, O_RDWR|O_CREAT, 0644 );
394
        if( i_fd >= 0 )
395
        {
396
            write( i_fd, psz_tag, strlen(psz_tag) );
397
            close( i_fd );
398
        }
399
    }
400
401
    /* If the cache is enabled, extract a unique disc ID */
402
    if( psz_cache )
403
    {
404
        uint8_t p_sector[DVDCSS_BLOCK_SIZE];
405
        char psz_debug[PATH_MAX + 30];
406
        char psz_key[1 + KEY_SIZE * 2 + 1];
407
        char *psz_title;
408
        uint8_t *psz_serial;
409
        int i;
410
411
        /* We read sector 0. If it starts with 0x000001ba (BE), we are
412
         * reading a VOB file, and we should not cache anything. */
413
414
        i_ret = dvdcss->pf_seek( dvdcss, 0 );
415
        if( i_ret != 0 )
416
        {
417
            goto nocache;
418
        }
419
420
        i_ret = dvdcss->pf_read( dvdcss, p_sector, 1 );
421
        if( i_ret != 1 )
422
        {
423
            goto nocache;
424
        }
425
426
        if( p_sector[0] == 0x00 && p_sector[1] == 0x00
427
             && p_sector[2] == 0x01 && p_sector[3] == 0xba )
428
        {
429
            goto nocache;
430
        }
431
432
        /* The data we are looking for is at sector 16 (32768 bytes):
433
         *  - offset 40: disc title (32 uppercase chars)
434
         *  - offset 813: manufacturing date + serial no (16 digits) */
435
436
        i_ret = dvdcss->pf_seek( dvdcss, 16 );
437
        if( i_ret != 16 )
438
        {
439
            goto nocache;
440
        }
441
442
        i_ret = dvdcss->pf_read( dvdcss, p_sector, 1 );
443
        if( i_ret != 1 )
444
        {
445
            goto nocache;
446
        }
447
448
        /* Get the disc title */
449
        psz_title = (char *)p_sector + 40;
450
        psz_title[32] = '\0';
451
452
        for( i = 0 ; i < 32 ; i++ )
453
        {
454
            if( psz_title[i] <= ' ' )
455
            {
456
                psz_title[i] = '\0';
457
                break;
458
            }
459
            else if( psz_title[i] == '/' || psz_title[i] == '\\' )
460
            {
461
                psz_title[i] = '-';
462
            }
463
        }
464
465
        /* Get the date + serial */
466
        psz_serial = p_sector + 813;
467
        psz_serial[16] = '\0';
468
469
        /* Check that all characters are digits, otherwise convert. */
470
        for( i = 0 ; i < 16 ; i++ )
471
        {
472
            if( psz_serial[i] < '0' || psz_serial[i] > '9' )
473
            {
474
                char psz_tmp[16 + 1];
475
                sprintf( psz_tmp,
476
                         "%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x",
477
                         psz_serial[0], psz_serial[1], psz_serial[2],
478
                         psz_serial[3], psz_serial[4], psz_serial[5],
479
                         psz_serial[6], psz_serial[7] );
480
                memcpy( psz_serial, psz_tmp, 16 );
481
                break;
482
            }
483
        }
484
485
        /* Get disk key, since some discs have got same title, manufacturing
486
         * date and serial number, but different keys */
487
        if( dvdcss->b_scrambled )
488
        {
489
             psz_key[0] = '-';
490
             for( i = 0; i < KEY_SIZE; i++ )
491
             {
492
                 sprintf( &psz_key[1+i*2], "%.2x", dvdcss->css.p_disc_key[i] );
493
             }
494
             psz_key[1 + KEY_SIZE * 2] = '\0';
495
        }
496
        else
497
        {
498
             psz_key[0] = 0;
499
        }
500
501
        /* We have a disc name or ID, we can create the cache dir */
502
        i = sprintf( dvdcss->psz_cachefile, "%s", psz_cache );
503
#if !defined( WIN32 ) || defined( SYS_CYGWIN )
504
        i_ret = mkdir( dvdcss->psz_cachefile, 0755 );
505
#else
506
        i_ret = mkdir( dvdcss->psz_cachefile );
507
#endif
508
        if( i_ret < 0 && errno != EEXIST )
509
        {
510
            print_error( dvdcss, "failed creating cache directory" );
511
            dvdcss->psz_cachefile[0] = '\0';
512
            goto nocache;
513
        }
514
515
        i += sprintf( dvdcss->psz_cachefile + i, "/%s-%s%s", psz_title,
516
                      psz_serial, psz_key );
517
#if !defined( WIN32 ) || defined( SYS_CYGWIN )
518
        i_ret = mkdir( dvdcss->psz_cachefile, 0755 );
519
#else
520
        i_ret = mkdir( dvdcss->psz_cachefile );
521
#endif
522
        if( i_ret < 0 && errno != EEXIST )
523
        {
524
            print_error( dvdcss, "failed creating cache subdirectory" );
525
            dvdcss->psz_cachefile[0] = '\0';
526
            goto nocache;
527
        }
528
        i += sprintf( dvdcss->psz_cachefile + i, "/");
529
530
        /* Pointer to the filename we will use. */
531
        dvdcss->psz_block = dvdcss->psz_cachefile + i;
532
533
        sprintf( psz_debug, "using CSS key cache dir: %s",
534
                            dvdcss->psz_cachefile );
535
        print_debug( dvdcss, psz_debug );
536
    }
537
    nocache:
538
190
539
#ifndef WIN32
191
#ifndef WIN32
540
    if( psz_raw_device != NULL )
192
    if( psz_raw_device != NULL )
541
    {
193
    {
542
        _dvdcss_raw_open( dvdcss, psz_raw_device );
194
        _dvdcss_raw_open( dvdcss, psz_raw_device );
543
    }
195
    }
544
#endif
196
#endif
545
197
546
    /* Seek at the beginning, just for safety. */
547
    dvdcss->pf_seek( dvdcss, 0 );
548
549
    return dvdcss;
198
    return dvdcss;
550
}
199
}
551
200
552
/**
201
/*****************************************************************************
553
 * \brief Return a string containing the latest error that occurred in the
202
 * dvdcss_error: return the last libdvdcss error message
554
 *        given \e libdvdcss instance.
203
 *****************************************************************************/
555
 *
204
extern char * dvdcss_error ( dvdcss_handle dvdcss )
556
 * \param dvdcss a \e libdvdcss instance.
557
 * \return a null-terminated string containing the latest error message.
558
 *
559
 * This function returns a constant string containing the latest error that
560
 * occurred in \e libdvdcss. It can be used to format error messages at your
561
 * convenience in your application.
562
 */
563
LIBDVDCSS_EXPORT char * dvdcss_error ( dvdcss_t dvdcss )
564
{
205
{
565
    return dvdcss->psz_error;
206
    return dvdcss->psz_error;
566
}
207
}
567
208
568
/**
209
/*****************************************************************************
569
 * \brief Seek in the disc and change the current key if requested.
210
 * dvdcss_seek: seek into the device
570
 *
211
 *****************************************************************************/
571
 * \param dvdcss a \e libdvdcss instance.
572
 * \param i_blocks an absolute block offset to seek to.
573
 * \param i_flags #DVDCSS_NOFLAGS, optionally ored with one of #DVDCSS_SEEK_KEY
574
 *        or #DVDCSS_SEEK_MPEG.
575
 * \return the new position in blocks, or a negative value in case an error
576
 *         happened.
577
 *
578
 * This function seeks to the requested position, in logical blocks.
579
 *
580
 * You typically set \p i_flags to #DVDCSS_NOFLAGS when seeking in a .IFO.
581
 *
582
 * If #DVDCSS_SEEK_MPEG is specified in \p i_flags and if \e libdvdcss finds it
583
 * reasonable to do so (ie, if the dvdcss method is not "title"), the current
584
 * title key will be checked and a new one will be calculated if necessary.
585
 * This flag is typically used when reading data from a VOB.
586
 *
587
 * If #DVDCSS_SEEK_KEY is specified, the title key will be always checked,
588
 * even with the "title" method. This is equivalent to using the now
589
 * deprecated dvdcss_title() call. This flag is typically used when seeking
590
 * in a new title.
591
 */
592
LIBDVDCSS_EXPORT int dvdcss_seek ( dvdcss_t dvdcss, int i_blocks, int i_flags )
212
extern int dvdcss_seek ( dvdcss_handle dvdcss, int i_blocks, int i_flags )
593
{
213
{
594
    /* title cracking method is too slow to be used at each seek */
214
    /* title cracking method is too slow to be used at each seek */
595
    if( ( ( i_flags & DVDCSS_SEEK_MPEG )
215
    if( ( ( i_flags & DVDCSS_SEEK_MPEG )
596
             && ( dvdcss->i_method != DVDCSS_METHOD_TITLE ) )
216
             && ( dvdcss->i_method != DVDCSS_METHOD_TITLE ) ) 
597
       || ( i_flags & DVDCSS_SEEK_KEY ) )
217
       || ( i_flags & DVDCSS_SEEK_KEY ) )
598
    {
218
    {
599
        /* check the title key */
219
        /* check the title key */
600
        if( _dvdcss_title( dvdcss, i_blocks ) )
220
        if( dvdcss_title( dvdcss, i_blocks ) ) 
601
        {
221
        {
602
            return -1;
222
            return -1;
603
        }
223
        }
604
    }
224
    }
605
225
606
    return dvdcss->pf_seek( dvdcss, i_blocks );
226
    return _dvdcss_seek( dvdcss, i_blocks );
607
}
227
}
608
228
609
/**
229
/*****************************************************************************
610
 * \brief Read from the disc and decrypt data if requested.
230
 * dvdcss_title: crack or decrypt the current title key if needed
611
 *
231
 *****************************************************************************
612
 * \param dvdcss a \e libdvdcss instance.
232
 * This function should only be called by dvdcss_seek and should eventually
613
 * \param p_buffer a buffer that will contain the data read from the disc.
233
 * not be external if possible.
614
 * \param i_blocks the amount of blocks to read.
234
 *****************************************************************************/
615
 * \param i_flags #DVDCSS_NOFLAGS, optionally ored with #DVDCSS_READ_DECRYPT.
235
extern int dvdcss_title ( dvdcss_handle dvdcss, int i_block )
616
 * \return the amount of blocks read, or a negative value in case an
236
{
617
 *         error happened.
237
    dvd_title_t *p_title;
618
 *
238
    dvd_title_t *p_newtitle;
619
 * This function reads \p i_blocks logical blocks from the DVD.
239
    int          i_ret;
620
 *
240
621
 * You typically set \p i_flags to #DVDCSS_NOFLAGS when reading data from a
241
    if( ! dvdcss->b_encrypted )
622
 * .IFO file on the DVD.
242
    {
623
 *
243
        return 0;
624
 * If #DVDCSS_READ_DECRYPT is specified in \p i_flags, dvdcss_read() will
244
    }
625
 * automatically decrypt scrambled sectors. This flag is typically used when
245
626
 * reading data from a .VOB file on the DVD. It has no effect on unscrambled
246
    /* Check if we've already cracked this key */
627
 * discs or unscrambled sectors, and can be safely used on those.
247
    p_title = dvdcss->p_titles;
628
 *
248
    while( p_title != NULL
629
 * \warning dvdcss_read() expects to be able to write \p i_blocks *
249
            && p_title->p_next != NULL
630
 *          #DVDCSS_BLOCK_SIZE bytes in \p p_buffer.
250
            && p_title->p_next->i_startlb <= i_block )
631
 */
251
    {
252
        p_title = p_title->p_next;
253
    }
254
255
    if( p_title != NULL
256
         && p_title->i_startlb == i_block )
257
    {
258
        /* We've already cracked this key, nothing to do */
259
        memcpy( dvdcss->css.p_title_key, p_title->p_key, sizeof(dvd_key_t) );
260
        return 0;
261
    }
262
263
    /* Crack or decrypt CSS title key for current VTS */
264
    i_ret = CSSGetTitleKey( dvdcss, i_block );
265
266
    if( i_ret < 0 )
267
    {
268
        _dvdcss_error( dvdcss, "fatal error in vts css key" );
269
        return i_ret;
270
    }
271
    else if( i_ret > 0 )
272
    {
273
        _dvdcss_error( dvdcss, "decryption unavailable" );
274
        return -1;
275
    }
276
277
    /* Find our spot in the list */
278
    p_newtitle = NULL;
279
    p_title = dvdcss->p_titles;
280
    while( ( p_title != NULL ) && ( p_title->i_startlb < i_block ) )
281
    {
282
        p_newtitle = p_title;
283
        p_title = p_title->p_next;
284
    }
285
286
    /* Save the found title */
287
    p_title = p_newtitle;
288
289
    /* Write in the new title and its key */
290
    p_newtitle = malloc( sizeof( dvd_title_t ) );
291
    p_newtitle->i_startlb = i_block;
292
    memcpy( p_newtitle->p_key, dvdcss->css.p_title_key, KEY_SIZE );
293
294
    /* Link the new title, either at the beginning or inside the list */
295
    if( p_title == NULL )
296
    {
297
        dvdcss->p_titles = p_newtitle;
298
        p_newtitle->p_next = NULL;
299
    }
300
    else
301
    {
302
        p_newtitle->p_next = p_title->p_next;
303
        p_title->p_next = p_newtitle;
304
    }
305
306
    return 0;
307
}
308
309
#define Pkey dvdcss->css.p_title_key
310
/*****************************************************************************
311
 * dvdcss_read: read data from the device, decrypt if requested
312
 *****************************************************************************/
632
LIBDVDCSS_EXPORT int dvdcss_read ( dvdcss_t dvdcss, void *p_buffer,
313
extern int dvdcss_read ( dvdcss_handle dvdcss, void *p_buffer,
633
                                          int i_blocks,
314
                                               int i_blocks,
634
                                          int i_flags )
315
                                               int i_flags )
635
{
316
{
636
    int i_ret, i_index;
317
    int i_ret, i_index;
637
318
638
    i_ret = dvdcss->pf_read( dvdcss, p_buffer, i_blocks );
319
    i_ret = _dvdcss_read( dvdcss, p_buffer, i_blocks );
639
320
640
    if( i_ret <= 0
321
    if( i_ret <= 0
641
         || !dvdcss->b_scrambled
322
         || !dvdcss->b_encrypted
642
         || !(i_flags & DVDCSS_READ_DECRYPT) )
323
         || !(i_flags & DVDCSS_READ_DECRYPT) )
643
    {
324
    {
644
        return i_ret;
325
        return i_ret;
645
    }
326
    }
646
327
647
    if( ! memcmp( dvdcss->css.p_title_key, "\0\0\0\0\0", 5 ) )
648
    {
649
        /* For what we believe is an unencrypted title,
328
    /* For what we believe is an unencrypted title, 
650
         * check that there are no encrypted blocks */
329
       check that there are no encrypted blocks */
330
    if( !( Pkey[0] | Pkey[1] | Pkey[2] | Pkey[3] | Pkey[4] ) ) 
331
    {
651
        for( i_index = i_ret; i_index; i_index-- )
332
        for( i_index = i_ret; i_index; i_index-- )
652
        {
333
        {
653
            if( ((uint8_t*)p_buffer)[0x14] & 0x30 )
334
            if( ((u8*)p_buffer)[0x14] & 0x30 )
654
            {
335
            {
655
                print_error( dvdcss, "no key but found encrypted block" );
336
                _dvdcss_error( dvdcss, "no key but found encrypted block" );
656
                /* Only return the initial range of unscrambled blocks? */
337
                /* Only return the initial range of unscrambled blocks? */
338
                i_ret = i_index;
657
                /* or fail completely? return 0; */
339
                /* or fail completely? return 0; */
658
                break;
659
            }
340
            }
660
            p_buffer = (void *) ((uint8_t *)p_buffer + DVDCSS_BLOCK_SIZE);
341
            (u8*)p_buffer += DVDCSS_BLOCK_SIZE;
661
        }
662
    }
342
        }
663
    else
664
    {
343
    }
344
665
        /* Decrypt the blocks we managed to read */
345
    /* Decrypt the blocks we managed to read */
666
        for( i_index = i_ret; i_index; i_index-- )
346
    for( i_index = i_ret; i_index; i_index-- )
667
        {
347
    {
668
            _dvdcss_unscramble( dvdcss->css.p_title_key, p_buffer );
348
        CSSDescrambleSector( dvdcss->css.p_title_key, p_buffer );
669
            ((uint8_t*)p_buffer)[0x14] &= 0x8f;
349
        ((u8*)p_buffer)[0x14] &= 0x8f;
670
            p_buffer = (void *) ((uint8_t *)p_buffer + DVDCSS_BLOCK_SIZE);
350
        (u8*)p_buffer += DVDCSS_BLOCK_SIZE;
671
        }
672
    }
351
    }
673
352
674
    return i_ret;
353
    return i_ret;
675
}
354
}
676
355
677
/**
356
/*****************************************************************************
678
 * \brief Read from the disc into multiple buffers and decrypt data if
357
 * dvdcss_readv: read data to an iovec structure, decrypt if requested
679
 *        requested.
358
 *****************************************************************************/
680
 *
681
 * \param dvdcss a \e libdvdcss instance.
682
 * \param p_iovec a pointer to an array of iovec structures that will contain
683
 *        the data read from the disc.
684
 * \param i_blocks the amount of blocks to read.
685
 * \param i_flags #DVDCSS_NOFLAGS, optionally ored with #DVDCSS_READ_DECRYPT.
686
 * \return the amount of blocks read, or a negative value in case an
687
 *         error happened.
688
 *
689
 * This function reads \p i_blocks logical blocks from the DVD and writes them
690
 * to an array of iovec structures.
691
 *
692
 * You typically set \p i_flags to #DVDCSS_NOFLAGS when reading data from a
693
 * .IFO file on the DVD.
694
 *
695
 * If #DVDCSS_READ_DECRYPT is specified in \p i_flags, dvdcss_readv() will
696
 * automatically decrypt scrambled sectors. This flag is typically used when
697
 * reading data from a .VOB file on the DVD. It has no effect on unscrambled
698
 * discs or unscrambled sectors, and can be safely used on those.
699
 *
700
 * \warning dvdcss_readv() expects to be able to write \p i_blocks *
701
 *          #DVDCSS_BLOCK_SIZE bytes in the buffers pointed by \p p_iovec.
702
 *          Moreover, all iov_len members of the iovec structures should be
703
 *          multiples of #DVDCSS_BLOCK_SIZE.
704
 */
705
LIBDVDCSS_EXPORT int dvdcss_readv ( dvdcss_t dvdcss, void *p_iovec,
359
extern int dvdcss_readv ( dvdcss_handle dvdcss, void *p_iovec,
706
                                           int i_blocks,
360
                                                int i_blocks,
707
                                           int i_flags )
361
                                                int i_flags )
708
{
362
{
709
    struct iovec *_p_iovec = (struct iovec *)p_iovec;
363
#define P_IOVEC ((struct iovec*)p_iovec)
710
    int i_ret, i_index;
364
    int i_ret, i_index;
711
    void *iov_base;
365
    void *iov_base;
712
    size_t iov_len;
366
    size_t iov_len;
713
367
714
    i_ret = dvdcss->pf_readv( dvdcss, _p_iovec, i_blocks );
368
    i_ret = _dvdcss_readv( dvdcss, P_IOVEC, i_blocks );
715
369
716
    if( i_ret <= 0
370
    if( i_ret <= 0
717
         || !dvdcss->b_scrambled
371
         || !dvdcss->b_encrypted
718
         || !(i_flags & DVDCSS_READ_DECRYPT) )
372
         || !(i_flags & DVDCSS_READ_DECRYPT) )
719
    {
373
    {
720
        return i_ret;
374
        return i_ret;
721
    }
375
    }
722
376
377
723
    /* Initialize loop for decryption */
378
    /* Initialize loop for decryption */
724
    iov_base = _p_iovec->iov_base;
379
    iov_base = P_IOVEC->iov_base;
725
    iov_len = _p_iovec->iov_len;
380
    iov_len = P_IOVEC->iov_len;
726
381
727
    /* Decrypt the blocks we managed to read */
382
    /* Decrypt the blocks we managed to read */
728
    for( i_index = i_ret; i_index; i_index-- )
383
    for( i_index = i_ret; i_index; i_index-- )
729
    {
384
    {
730
        /* Check that iov_len is a multiple of 2048 */
385
        /* Check that iov_len is a multiple of 2048 */
...
...
733
            return -1;
388
            return -1;
734
        }
389
        }
735
390
736
        while( iov_len == 0 )
391
        while( iov_len == 0 )
737
        {
392
        {
738
            _p_iovec++;
393
            P_IOVEC++;
739
            iov_base = _p_iovec->iov_base;
394
            iov_base = P_IOVEC->iov_base;
740
            iov_len = _p_iovec->iov_len;
395
            iov_len = P_IOVEC->iov_len;
741
        }
396
        }
742
397
743
        _dvdcss_unscramble( dvdcss->css.p_title_key, iov_base );
398
        CSSDescrambleSector( dvdcss->css.p_title_key, iov_base );
744
        ((uint8_t*)iov_base)[0x14] &= 0x8f;
399
        ((u8*)iov_base)[0x14] &= 0x8f;
745
400
746
        iov_base = (void *) ((uint8_t*)iov_base + DVDCSS_BLOCK_SIZE);
401
        (u8*)iov_base += DVDCSS_BLOCK_SIZE;
747
        iov_len -= DVDCSS_BLOCK_SIZE;
402
        (u8*)iov_len -= DVDCSS_BLOCK_SIZE;
748
    }
403
    }
749
404
750
    return i_ret;
405
    return i_ret;
406
#undef P_IOVEC
751
}
407
}
408
#undef Pkey
752
409
753
/**
410
/*****************************************************************************
754
 * \brief Close the DVD and clean up the library.
411
 * dvdcss_close: close the DVD device and clean up the library
755
 *
412
 *****************************************************************************/
756
 * \param dvdcss a \e libdvdcss instance.
413
extern int dvdcss_close ( dvdcss_handle dvdcss )
757
 * \return zero in case of success, a negative value otherwise.
758
 *
759
 * This function closes the DVD device and frees all the memory allocated
760
 * by \e libdvdcss. On return, the #dvdcss_t is invalidated and may not be
761
 * used again.
762
 */
763
LIBDVDCSS_EXPORT int dvdcss_close ( dvdcss_t dvdcss )
764
{
414
{
765
    dvd_title_t *p_title;
415
    dvd_title_t *p_title;
766
    int i_ret;
416
    int i_ret;
767
417
768
    /* Free our list of keys */
418
    /* Free our list of keys */
...
...
779
    if( i_ret < 0 )
429
    if( i_ret < 0 )
780
    {
430
    {
781
        return i_ret;
431
        return i_ret;
782
    }
432
    }
783
433
784
    free( dvdcss->psz_device );
785
    free( dvdcss );
434
    free( dvdcss );
786
435
787
    return 0;
436
    return 0;
788
}
437
}
789
438
790
/*
439
/* Following functions are local */
791
 *  Deprecated. See dvdcss_seek().
440
441
static int _dvdcss_open ( dvdcss_handle dvdcss, char *psz_target )
442
{
443
#if defined( WIN32 )
444
    if( WIN2K )
445
    {
446
        char psz_dvd[7];
447
        _snprintf( psz_dvd, 7, "\\\\.\\%c:", psz_target[0] );
448
        (HANDLE) dvdcss->i_fd =
449
                CreateFile( psz_dvd, GENERIC_READ | GENERIC_WRITE,
450
                                FILE_SHARE_READ | FILE_SHARE_WRITE,
451
                                NULL, OPEN_EXISTING, 0, NULL );
452
        if( (HANDLE) dvdcss->i_fd == INVALID_HANDLE_VALUE )
453
        {
454
            _dvdcss_error( dvdcss, "failed opening device" );
455
            return -1;
456
        }
457
    }
458
    else
459
    {
460
        dvdcss->i_fd = _win32_dvdcss_aopen( psz_target[0], dvdcss );
461
        if( dvdcss->i_fd == -1 )
462
        {
463
            _dvdcss_error( dvdcss, "failed opening device" );
464
            return -1;
465
        }
466
    }
467
468
    /* initialise readv temporary buffer */
469
    dvdcss->p_readv_buffer   = NULL;
470
    dvdcss->i_readv_buf_size = 0;
471
472
#else
473
    dvdcss->i_fd = dvdcss->i_read_fd = open( psz_target, 0 );
474
475
    if( dvdcss->i_fd == -1 )
476
    {
477
        _dvdcss_error( dvdcss, "failed opening device" );
478
        return -1;
479
    }
480
481
#endif
482
483
    return 0;
484
}
485
486
#ifndef WIN32
487
static int _dvdcss_raw_open ( dvdcss_handle dvdcss, char *psz_target )
488
{
489
    dvdcss->i_raw_fd = open( psz_target, 0 );
490
491
    if( dvdcss->i_raw_fd == -1 )
492
    {
493
        _dvdcss_error( dvdcss, "failed opening raw device, continuing" );
494
        return -1;
495
    }
496
    else
497
    {
498
        dvdcss->i_read_fd = dvdcss->i_raw_fd;
499
    }
500
501
    return 0;
502
}
503
#endif
504
505
static int _dvdcss_close ( dvdcss_handle dvdcss )
506
{
507
#if defined( WIN32 )
508
    if( WIN2K )
509
    {
510
        CloseHandle( (HANDLE) dvdcss->i_fd );
511
    }
512
    else
513
    {
514
        _win32_dvdcss_aclose( dvdcss->i_fd );
515
    }
516
517
    /* Free readv temporary buffer */
518
    if( dvdcss->p_readv_buffer )
519
    {
520
        free( dvdcss->p_readv_buffer );
521
        dvdcss->p_readv_buffer   = NULL;
522
        dvdcss->i_readv_buf_size = 0;
523
    }
524
525
#else
526
    close( dvdcss->i_fd );
527
528
    if( dvdcss->i_raw_fd >= 0 )
529
    {
530
        close( dvdcss->i_raw_fd );
531
        dvdcss->i_raw_fd = -1;
532
    }
533
534
#endif
535
536
    return 0;
537
}
538
539
int _dvdcss_seek ( dvdcss_handle dvdcss, int i_blocks )
540
{
541
#if defined( WIN32 )
542
    dvdcss->i_seekpos = i_blocks;
543
544
    if( WIN2K )
545
    {
546
        LARGE_INTEGER li_read;
547
548
#ifndef INVALID_SET_FILE_POINTER
549
#define INVALID_SET_FILE_POINTER ((DWORD)-1)
550
#endif
551
552
        li_read.QuadPart = (LONGLONG)i_blocks * DVDCSS_BLOCK_SIZE;
553
554
        li_read.LowPart = SetFilePointer( (HANDLE) dvdcss->i_fd,
555
                                          li_read.LowPart,
556
                                          &li_read.HighPart, FILE_BEGIN );
557
        if( (li_read.LowPart == INVALID_SET_FILE_POINTER)
558
            && GetLastError() != NO_ERROR)
559
        {
560
            li_read.QuadPart = -DVDCSS_BLOCK_SIZE;
561
        }
562
563
        li_read.QuadPart /= DVDCSS_BLOCK_SIZE;
564
        return (int)li_read.QuadPart;
565
    }
566
    else
567
    {
568
        return ( _win32_dvdcss_aseek( dvdcss->i_fd, i_blocks, SEEK_SET ) );
569
    }
570
#else
571
    off_t   i_read;
572
573
    dvdcss->i_seekpos = i_blocks;
574
575
    i_read = lseek( dvdcss->i_read_fd,
576
                    (off_t)i_blocks * (off_t)DVDCSS_BLOCK_SIZE, SEEK_SET );
577
578
    return i_read / DVDCSS_BLOCK_SIZE;
579
#endif
580
581
}
582
583
int _dvdcss_read ( dvdcss_handle dvdcss, void *p_buffer, int i_blocks )
584
{
585
#if defined( WIN32 ) 
586
    if( WIN2K )
587
    {
588
        int i_bytes;
589
590
        if( !ReadFile( (HANDLE) dvdcss->i_fd, p_buffer,
591
                  i_blocks * DVDCSS_BLOCK_SIZE,
592
                  (LPDWORD)&i_bytes, NULL ) )
593
        {
594
            return -1;
595
        }
596
        return i_bytes / DVDCSS_BLOCK_SIZE;
597
    }
598
    else
599
    {
600
        return _win32_dvdcss_aread( dvdcss->i_fd, p_buffer, i_blocks );
601
    }
602
603
#else
604
    int i_bytes;
605
606
    i_bytes = read( dvdcss->i_read_fd, p_buffer,
607
                    (size_t)i_blocks * DVDCSS_BLOCK_SIZE );
608
    return i_bytes / DVDCSS_BLOCK_SIZE;
609
#endif
610
611
}
612
613
static int _dvdcss_readv ( dvdcss_handle dvdcss, struct iovec *p_iovec,
614
                           int i_blocks )
615
{
616
    int i_read;
617
618
#if defined( WIN32 )
619
    /* Check the size of the readv temp buffer, just in case we need to
620
     * realloc something bigger */
621
    if( dvdcss->i_readv_buf_size < i_blocks * DVDCSS_BLOCK_SIZE )
622
    {
623
        dvdcss->i_readv_buf_size = i_blocks * DVDCSS_BLOCK_SIZE;
624
625
        if( dvdcss->p_readv_buffer ) free( dvdcss->p_readv_buffer );
626
627
        /* Allocate a buffer which will be used as a temporary storage
628
         * for readv */
629
        dvdcss->p_readv_buffer = malloc( dvdcss->i_readv_buf_size );
630
        if( !dvdcss->p_readv_buffer )
631
        {
632
            _dvdcss_error( dvdcss, " failed (readv)" );
633
            return -1;
634
        }
635
    }
636
637
    i_read = _win32_dvdcss_readv( dvdcss->i_fd, p_iovec, i_blocks,
638
                                  dvdcss->p_readv_buffer );
639
    return i_read;
640
641
#else
642
    i_read = readv( dvdcss->i_read_fd, p_iovec, i_blocks );
643
    return i_read / DVDCSS_BLOCK_SIZE;
644
645
#endif
646
}
647
648
649
#if defined( WIN32 )
650
651
/*****************************************************************************
652
 * _win32_dvdcss_readv: vectored read using ReadFile for Win2K and
653
 *                      _win32_dvdcss_aread for win9x
654
 *****************************************************************************/
655
static int _win32_dvdcss_readv( int i_fd, struct iovec *p_iovec,
656
                                int i_num_buffers, char *p_tmp_buffer )
657
{
658
    int i_index;
659
    int i_blocks, i_blocks_total = 0;
660
661
    for( i_index = i_num_buffers; i_index; i_index-- )
662
    {
663
        i_blocks_total += p_iovec[i_index-1].iov_len; 
664
    }
665
666
    if( i_blocks_total <= 0 ) return 0;
667
668
    i_blocks_total /= DVDCSS_BLOCK_SIZE;
669
670
    if( WIN2K )
671
    {
672
        unsigned long int i_bytes;
673
        if( !ReadFile( (HANDLE)i_fd, p_tmp_buffer,
674
                       i_blocks_total * DVDCSS_BLOCK_SIZE, &i_bytes, NULL ) )
675
        {
676
            return -1;
677
            /* The read failed... too bad.
678
               As in the posix spec the file postition is left
679
               unspecified after a failure */
680
        }
681
        i_blocks = i_bytes / DVDCSS_BLOCK_SIZE;
682
    }
683
    else /* Win9x */
684
    {
685
        i_blocks = _win32_dvdcss_aread( i_fd, p_tmp_buffer, i_blocks_total );
686
        if( i_blocks < 0 )
687
        {
688
            return -1;  /* idem */
689
        }
690
    }
691
692
    /* We just have to copy the content of the temp buffer into the iovecs */
693
    i_index = 0;
694
    i_blocks_total = i_blocks;
695
    while( i_blocks_total > 0 )
696
    {
697
        memcpy( p_iovec[i_index].iov_base,
698
                &p_tmp_buffer[(i_blocks - i_blocks_total) * DVDCSS_BLOCK_SIZE],
699
                p_iovec[i_index].iov_len );
700
        /* if we read less blocks than asked, we'll just end up copying
701
           garbage, this isn't an issue as we return the number of
702
           blocks actually read */
703
        i_blocks_total -= ( p_iovec[i_index].iov_len / DVDCSS_BLOCK_SIZE );
704
        i_index++;
705
    } 
706
707
    return i_blocks;
708
}
709
710
/*****************************************************************************
711
 * _win32_dvdcss_aopen: open dvd drive (load aspi and init w32_aspidev
712
 *                      structure)
713
 *****************************************************************************/
714
static int _win32_dvdcss_aopen( char c_drive, dvdcss_handle dvdcss )
715
{
716
    HMODULE hASPI;
717
    DWORD dwSupportInfo;
718
    struct w32_aspidev *fd;
719
    int i, j, i_hostadapters;
720
    long (*lpGetSupport)( void );
721
    long (*lpSendCommand)( void* );
722
     
723
    hASPI = LoadLibrary( "wnaspi32.dll" );
724
    if( hASPI == NULL )
725
    {
726
        _dvdcss_error( dvdcss, "unable to load wnaspi32.dll" );
727
        return -1;
728
    }
729
730
    (FARPROC) lpGetSupport = GetProcAddress( hASPI, "GetASPI32SupportInfo" );
731
    (FARPROC) lpSendCommand = GetProcAddress( hASPI, "SendASPI32Command" );
732
 
733
    if(lpGetSupport == NULL || lpSendCommand == NULL )
734
    {
735
        _dvdcss_debug( dvdcss, "unable to get aspi function pointers" );
736
        FreeLibrary( hASPI );
737
        return -1;
738
    }
739
740
    dwSupportInfo = lpGetSupport();
741
742
    if( HIBYTE( LOWORD ( dwSupportInfo ) ) == SS_NO_ADAPTERS )
743
    {
744
        _dvdcss_debug( dvdcss, "no host adapters found (aspi)" );
745
        FreeLibrary( hASPI );
746
        return -1;
747
    }
748
749
    if( HIBYTE( LOWORD ( dwSupportInfo ) ) != SS_COMP )
750
    {
751
        _dvdcss_error( dvdcss, "unable to initalize aspi layer" );
752
        FreeLibrary( hASPI );
753
        return -1;
754
    }
755
756
    i_hostadapters = LOBYTE( LOWORD( dwSupportInfo ) );
757
    if( i_hostadapters == 0 )
758
    {
759
        FreeLibrary( hASPI );
760
        return -1;
761
    }
762
763
    fd = malloc( sizeof( struct w32_aspidev ) );
764
    if( fd == NULL )
765
    {
766
        FreeLibrary( hASPI );
767
        return -1;
768
    }
769
770
    fd->i_blocks = 0;
771
    fd->hASPI = (long) hASPI;
772
    fd->lpSendCommand = lpSendCommand;
773
774
    c_drive = c_drive > 'Z' ? c_drive - 'a' : c_drive - 'A';
775
776
    for( i = 0; i < i_hostadapters; i++ )
777
    {
778
        for( j = 0; j < 15; j++ )
779
        {
780
            struct SRB_GetDiskInfo srbDiskInfo;
781
782
            srbDiskInfo.SRB_Cmd         = SC_GET_DISK_INFO;
783
            srbDiskInfo.SRB_HaId        = i;
784
            srbDiskInfo.SRB_Flags       = 0;
785
            srbDiskInfo.SRB_Hdr_Rsvd    = 0;
786
            srbDiskInfo.SRB_Target      = j;
787
            srbDiskInfo.SRB_Lun         = 0;
788
789
            lpSendCommand( (void*) &srbDiskInfo );
790
791
            if( (srbDiskInfo.SRB_Status == SS_COMP) &&
792
                (srbDiskInfo.SRB_Int13HDriveInfo == c_drive) )
793
            {
794
                fd->i_sid = MAKEWORD( i, j );
795
                return (int) fd;
796
            }
797
        }
798
    }
799
800
    free( (void*) fd );
801
    FreeLibrary( hASPI );
802
    _dvdcss_debug( dvdcss, "unable to get haid and target (aspi)" );
803
    return( -1 );        
804
}
805
806
/*****************************************************************************
807
 * _win32_dvdcss_aclose: close dvd drive (unload aspi and free w32_aspidev
808
 *                       structure)
809
 *****************************************************************************/
810
static int _win32_dvdcss_aclose( int i_fd )
811
{
812
    struct w32_aspidev *fd = (struct w32_aspidev *) i_fd;
813
814
    FreeLibrary( (HMODULE) fd->hASPI );
815
    free( (void*) i_fd );
816
817
    return 0;
818
}
819
820
/*****************************************************************************
821
 * _win32_dvdcss_aseek: aspi version of _dvdcss_seek
792
 */
822
 * 
793
#undef dvdcss_title
823
 * returns the number of blocks read.
794
LIBDVDCSS_EXPORT int dvdcss_title ( dvdcss_t dvdcss, int i_block )
824
 *****************************************************************************/
825
static int _win32_dvdcss_aseek( int i_fd, int i_blocks, int i_method )
795
{
826
{
796
    return _dvdcss_title( dvdcss, i_block );
827
    int i_old_blocks;
797
}
828
    char sz_buf[ DVDCSS_BLOCK_SIZE ];
829
    struct w32_aspidev *fd = (struct w32_aspidev *) i_fd;
830
    
831
    i_old_blocks = fd->i_blocks;
832
    fd->i_blocks = i_blocks;
798
833
799
/**
834
    if( _win32_dvdcss_aread( i_fd, sz_buf, 1 ) == -1 )
800
 * \brief Return 1 if the DVD is scrambled, 0 otherwise.
835
    {
836
        fd->i_blocks = i_old_blocks;
837
        return -1;
838
    }
839
840
    (fd->i_blocks)--;
841
842
    return fd->i_blocks;
843
}
844
845
/*****************************************************************************
846
 * _win32_dvdcss_aread: aspi version of _dvdcss_read
801
 *
847
 *
802
 * \param dvdcss a \e libdvdcss instance.
848
 * returns the number of blocks read.
803
 * \return 1 if the DVD is scrambled, 0 otherwise.
849
 *****************************************************************************/
804
 *
850
static int _win32_dvdcss_aread( int i_fd, void *p_data, int i_blocks )
805
 * This function returns whether the DVD is scrambled.
806
 */
807
LIBDVDCSS_EXPORT int dvdcss_is_scrambled ( dvdcss_t dvdcss )
808
{
851
{
809
    return dvdcss->b_scrambled;
852
    HANDLE hEvent;
810
}
853
    struct SRB_ExecSCSICmd ssc;
854
    struct w32_aspidev *fd = (struct w32_aspidev *) i_fd;
811
855
856
    /* Create the transfer completion event */
857
    hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
858
    if( hEvent == NULL )
859
    {
860
        return -1;
861
    }
862
863
    memset( &ssc, 0, sizeof( ssc ) );
864
865
    ssc.SRB_Cmd         = SC_EXEC_SCSI_CMD;
866
    ssc.SRB_Flags       = SRB_DIR_IN | SRB_EVENT_NOTIFY;
867
    ssc.SRB_HaId        = LOBYTE( fd->i_sid );
868
    ssc.SRB_Target      = HIBYTE( fd->i_sid );
869
    ssc.SRB_SenseLen    = SENSE_LEN;
870
    
871
    ssc.SRB_PostProc = (LPVOID) hEvent;
872
    ssc.SRB_BufPointer  = p_data;
873
    ssc.SRB_CDBLen      = 12;
874
    
875
    ssc.CDBByte[0]      = 0xA8; /* RAW */
876
    ssc.CDBByte[2]      = (UCHAR) (fd->i_blocks >> 24);
877
    ssc.CDBByte[3]      = (UCHAR) (fd->i_blocks >> 16) & 0xff;
878
    ssc.CDBByte[4]      = (UCHAR) (fd->i_blocks >> 8) & 0xff;
879
    ssc.CDBByte[5]      = (UCHAR) (fd->i_blocks) & 0xff;
880
    
881
    /* We have to break down the reads into 64kb pieces (ASPI restriction) */
882
    if( i_blocks > 32 )
883
    {
884
        ssc.SRB_BufLen = 32 * DVDCSS_BLOCK_SIZE;
885
        ssc.CDBByte[9] = 32;
886
        fd->i_blocks  += 32;
887
888
        /* Initiate transfer */  
889
        ResetEvent( hEvent );
890
        fd->lpSendCommand( (void*) &ssc );
891
892
        /* transfer the next 64kb (_win32_dvdcss_aread is called recursively)
893
         * We need to check the status of the read on return */
894
        if( _win32_dvdcss_aread( i_fd, (u8*) p_data + 32 * DVDCSS_BLOCK_SIZE,
895
                                 i_blocks - 32) < 0 )
896
        {
897
            return -1;
898
        }
899
    }
900
    else
901
    {
902
        /* This is the last transfer */
903
        ssc.SRB_BufLen   = i_blocks * DVDCSS_BLOCK_SIZE;
904
        ssc.CDBByte[9]   = (UCHAR) i_blocks;
905
        fd->i_blocks += i_blocks;
906
907
        /* Initiate transfer */  
908
        ResetEvent( hEvent );
909
        fd->lpSendCommand( (void*) &ssc );
910
911
    }
912
913
    /* If the command has still not been processed, wait until it's finished */
914
    if( ssc.SRB_Status == SS_PENDING )
915
    {
916
        WaitForSingleObject( hEvent, INFINITE );
917
    }
918
    CloseHandle( hEvent );
919
920
    /* check that the transfer went as planned */
921
    if( ssc.SRB_Status != SS_COMP )
922
    {
923
      return -1;
924
    }
925
926
    return i_blocks;
927
}
928
929
#endif
930