Mercurial > mplayer.hg
comparison libmpdvdkit2/libdvdcss.c @ 9333:f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
patch by Andreas Hess <jaska@gmx.net>
author | arpi |
---|---|
date | Sat, 08 Feb 2003 00:22:39 +0000 |
parents | ddf6a9f4cc6a |
children | cbc01dc4b773 |
comparison
equal
deleted
inserted
replaced
9332:a604236b0dd6 | 9333:f0f0f176d298 |
---|---|
9 * | 9 * |
10 * This program is free software; you can redistribute it and/or modify | 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 | 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 | 12 * the Free Software Foundation; either version 2 of the License, or |
13 * (at your option) any later version. | 13 * (at your option) any later version. |
14 * | 14 * |
15 * This program is distributed in the hope that it will be useful, | 15 * This program is distributed in the hope that it will be useful, |
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 * GNU General Public License for more details. | 18 * GNU General Public License for more details. |
19 * | 19 * |
20 * You should have received a copy of the GNU General Public License | 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 | 21 * along with this program; if not, write to the Free Software |
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. | 22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. |
23 */ | 23 */ |
24 | 24 |
25 /** | 25 /** |
26 * \mainpage libdvdcss developer documentation | 26 * \mainpage libdvdcss developer documentation |
27 * | 27 * |
28 * \section intro Introduction | 28 * \section intro Introduction |
29 * | 29 * |
30 * \e libdvdcss is a simple library designed for accessing DVDs like a block | 30 * \e libdvdcss is a simple library designed for accessing DVDs like a block |
75 * because there is not enough encrypted data on the disc to perform | 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 | 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 | 77 * decrypt a DVD stored on a hard disc, or a DVD with the wrong region |
78 * on an RPC2 drive. | 78 * on an RPC2 drive. |
79 * | 79 * |
80 * \li \b DVDCSS_RAW_DEVICE: specify the raw device to use. | 80 * \li \b DVDCSS_RAW_DEVICE: specify the raw device to use. Exact usage will |
81 * | 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. | |
82 */ | 91 */ |
83 | 92 |
84 /* | 93 /* |
85 * Preamble | 94 * Preamble |
86 */ | 95 */ |
90 #include <stdlib.h> | 99 #include <stdlib.h> |
91 #include <string.h> | 100 #include <string.h> |
92 #include <sys/types.h> | 101 #include <sys/types.h> |
93 #include <sys/stat.h> | 102 #include <sys/stat.h> |
94 #include <fcntl.h> | 103 #include <fcntl.h> |
95 | 104 #include <errno.h> |
96 #ifdef HAVE_UNISTD_H | 105 #include <unistd.h> |
97 # include <unistd.h> | 106 #include <limits.h> |
98 #endif | |
99 | 107 |
100 #include "dvdcss.h" | 108 #include "dvdcss.h" |
101 | 109 |
102 #include "common.h" | 110 #include "common.h" |
103 #include "css.h" | 111 #include "css.h" |
115 * The variable itself contains the exact version number of the library, | 123 * The variable itself contains the exact version number of the library, |
116 * which can be useful for specific feature needs. | 124 * which can be useful for specific feature needs. |
117 */ | 125 */ |
118 char * dvdcss_interface_2 = VERSION; | 126 char * dvdcss_interface_2 = VERSION; |
119 | 127 |
120 char * dvdcss_cache_dir = NULL; | |
121 | |
122 /** | 128 /** |
123 * \brief Open a DVD device or directory and return a dvdcss instance. | 129 * \brief Open a DVD device or directory and return a dvdcss instance. |
124 * | 130 * |
125 * \param psz_target a string containing the target name, for instance | 131 * \param psz_target a string containing the target name, for instance |
126 * "/dev/hdc" or "E:". | 132 * "/dev/hdc" or "E:". |
137 { | 143 { |
138 int i_ret; | 144 int i_ret; |
139 | 145 |
140 char *psz_method = getenv( "DVDCSS_METHOD" ); | 146 char *psz_method = getenv( "DVDCSS_METHOD" ); |
141 char *psz_verbose = getenv( "DVDCSS_VERBOSE" ); | 147 char *psz_verbose = getenv( "DVDCSS_VERBOSE" ); |
148 char *psz_cache = getenv( "DVDCSS_CACHE" ); | |
142 #ifndef WIN32 | 149 #ifndef WIN32 |
143 char *psz_raw_device = getenv( "DVDCSS_RAW_DEVICE" ); | 150 char *psz_raw_device = getenv( "DVDCSS_RAW_DEVICE" ); |
144 #endif | 151 #endif |
145 | 152 |
146 dvdcss_t dvdcss; | 153 dvdcss_t dvdcss; |
162 #endif | 169 #endif |
163 dvdcss->p_titles = NULL; | 170 dvdcss->p_titles = NULL; |
164 dvdcss->psz_device = (char *)strdup( psz_target ); | 171 dvdcss->psz_device = (char *)strdup( psz_target ); |
165 dvdcss->psz_error = "no error"; | 172 dvdcss->psz_error = "no error"; |
166 dvdcss->i_method = DVDCSS_METHOD_KEY; | 173 dvdcss->i_method = DVDCSS_METHOD_KEY; |
174 dvdcss->psz_cachefile[0] = '\0'; | |
167 dvdcss->b_debug = 0; | 175 dvdcss->b_debug = 0; |
168 dvdcss->b_errors = 0; | 176 dvdcss->b_errors = 0; |
169 dvdcss->psz_cache = NULL; | |
170 | 177 |
171 /* | 178 /* |
172 * Find verbosity from DVDCSS_VERBOSE environment variable | 179 * Find verbosity from DVDCSS_VERBOSE environment variable |
173 */ | 180 */ |
174 if( psz_verbose != NULL ) | 181 if( psz_verbose != NULL ) |
209 free( dvdcss ); | 216 free( dvdcss ); |
210 return NULL; | 217 return NULL; |
211 } | 218 } |
212 } | 219 } |
213 | 220 |
214 if(!dvdcss_cache_dir) dvdcss_cache_dir = getenv( "DVDCSS_CACHE" ); | 221 /* |
222 * Find cache dir from the DVDCSS_CACHE environment variable | |
223 */ | |
224 if( psz_cache != NULL ) | |
225 { | |
226 if( psz_cache[0] == '\0' ) | |
227 { | |
228 psz_cache = NULL; | |
229 } | |
230 /* Check that we can add the ID directory and the block filename */ | |
231 else if( strlen( psz_cache ) + 1 + 32 + 1 + 10 + 1 > PATH_MAX ) | |
232 { | |
233 _dvdcss_error( dvdcss, "cache directory name is too long" ); | |
234 psz_cache = NULL; | |
235 } | |
236 } | |
237 else psz_cache = get_path( "DVDKeys" ); | |
215 | 238 |
216 /* | 239 /* |
217 * Open device | 240 * Open device |
218 */ | 241 */ |
219 i_ret = _dvdcss_open( dvdcss ); | 242 i_ret = _dvdcss_open( dvdcss ); |
221 { | 244 { |
222 free( dvdcss->psz_device ); | 245 free( dvdcss->psz_device ); |
223 free( dvdcss ); | 246 free( dvdcss ); |
224 return NULL; | 247 return NULL; |
225 } | 248 } |
226 | 249 |
227 dvdcss->b_scrambled = 1; /* Assume the worst */ | 250 dvdcss->b_scrambled = 1; /* Assume the worst */ |
228 dvdcss->b_ioctls = _dvdcss_use_ioctls( dvdcss ); | 251 dvdcss->b_ioctls = _dvdcss_use_ioctls( dvdcss ); |
229 | 252 |
230 if( dvdcss->b_ioctls ) | 253 if( dvdcss->b_ioctls ) |
231 { | 254 { |
232 i_ret = _dvdcss_test( dvdcss ); | 255 i_ret = _dvdcss_test( dvdcss ); |
233 if( i_ret < 0 ) | 256 if( i_ret < 0 ) |
234 { | 257 { |
235 /* Disable the CSS ioctls and hope that it works? */ | 258 /* Disable the CSS ioctls and hope that it works? */ |
236 _dvdcss_debug( dvdcss, | 259 _dvdcss_debug( dvdcss, |
237 "could not check whether the disc was scrambled" ); | 260 "could not check whether the disc was scrambled" ); |
238 dvdcss->b_ioctls = 0; | 261 dvdcss->b_ioctls = 0; |
239 } | 262 } |
240 else | 263 else |
241 { | 264 { |
242 _dvdcss_debug( dvdcss, i_ret ? "disc is scrambled" | 265 _dvdcss_debug( dvdcss, i_ret ? "disc is scrambled" |
243 : "disc is unscrambled" ); | 266 : "disc is unscrambled" ); |
244 dvdcss->b_scrambled = i_ret; | 267 dvdcss->b_scrambled = i_ret; |
245 } | 268 } |
246 } | 269 } |
247 | 270 |
248 /* If disc is CSS protected and the ioctls work, authenticate the drive */ | 271 /* If disc is CSS protected and the ioctls work, authenticate the drive */ |
249 if( dvdcss->b_scrambled && dvdcss->b_ioctls ) | 272 if( dvdcss->b_scrambled && dvdcss->b_ioctls ) |
250 { | 273 { |
264 { | 287 { |
265 _dvdcss_raw_open( dvdcss, psz_raw_device ); | 288 _dvdcss_raw_open( dvdcss, psz_raw_device ); |
266 } | 289 } |
267 #endif | 290 #endif |
268 | 291 |
269 /* if the CACHE is enabled, extract some unique disc ID */ | 292 /* If the cache is enabled, extract a unique disc ID */ |
270 if(dvdcss_cache_dir){ | 293 if( psz_cache ) |
271 char* disc_id=NULL; | 294 { |
272 /*char title_name[64];*/ | 295 uint8_t p_sector[DVDCSS_BLOCK_SIZE]; |
273 char sector[DVDCSS_BLOCK_SIZE]; | 296 unsigned char psz_debug[PATH_MAX+30]; |
274 // 32768+40 -> disc title (32 uppercase chars) | 297 unsigned char * psz_data; |
275 // 32768+813 -> disc manufacturing date + serial no (16 digit number) | 298 int i; |
276 int ret=dvdcss->pf_seek( dvdcss, 32768/DVDCSS_BLOCK_SIZE); | 299 |
277 //printf("disc_id seek: %d -> %d, i_fd=%d i_read_fd=%d\n",32768/DVDCSS_BLOCK_SIZE,ret,dvdcss->i_fd,dvdcss->i_read_fd); | 300 /* We read sector 0. If it starts with 0x000001ba (BE), we are |
278 if(dvdcss->pf_read( dvdcss, sector, 1) == 1){ | 301 * reading a VOB file, and we should not cache anything. */ |
279 // check disc title first: | 302 |
280 char* title_name=§or[40]; | 303 i_ret = dvdcss->pf_seek( dvdcss, 0 ); |
281 int i=0; | 304 if( i_ret != 0 ) |
282 while(i<32 && title_name[i]>='0' && title_name[i]<='z') i++; | 305 { |
283 title_name[i]=0; | 306 goto nocache; |
284 if(i>5){ | 307 } |
285 disc_id=strdup(title_name); | 308 |
286 } else { | 309 i_ret = dvdcss->pf_read( dvdcss, p_sector, 1 ); |
287 // use disc date+serial: | 310 if( i_ret != 1 ) |
288 title_name=§or[813]; | 311 { |
289 title_name[16]=0; | 312 goto nocache; |
290 for ( i=0;i<16;i++ ) | 313 } |
291 if ( ( title_name[i] < '0' )||( title_name[i] > '9' ) ){ | 314 |
292 disc_id=malloc(16+4); | 315 if( p_sector[0] == 0x00 && p_sector[1] == 0x00 |
293 snprintf( disc_id,17,"%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X",title_name[0],title_name[1],title_name[2],title_name[3],title_name[4],title_name[5],title_name[6],title_name[7] ); | 316 && p_sector[2] == 0x01 && p_sector[3] == 0xba ) |
294 break; | 317 { |
295 } | 318 goto nocache; |
296 if(!disc_id) disc_id=strdup(title_name); | 319 } |
297 } | 320 |
298 if(disc_id){ | 321 /* The data we are looking for is at sector 16 (32768 bytes): |
299 // yeah, we have a disc name/id, let's set up cache path: | 322 * - offset 40: disc title (32 uppercase chars) |
300 /*char* dir;*/ | 323 * - offset 813: manufacturing date + serial no (16 digits) */ |
301 dvdcss->psz_cache = malloc(strlen(dvdcss_cache_dir)+strlen(disc_id)+4); | 324 |
302 sprintf(dvdcss->psz_cache,"%s/%s",dvdcss_cache_dir,disc_id); | 325 i_ret = dvdcss->pf_seek( dvdcss, 16 ); |
303 mkdir( dvdcss->psz_cache,493 ); | 326 if( i_ret != 16 ) |
304 free(disc_id); | 327 { |
305 fprintf(stderr,"Using CSS Key-cache dir: %s\n",dvdcss->psz_cache); | 328 goto nocache; |
306 } | 329 } |
307 } | 330 |
308 } | 331 i_ret = dvdcss->pf_read( dvdcss, p_sector, 1 ); |
332 if( i_ret != 1 ) | |
333 { | |
334 goto nocache; | |
335 } | |
336 | |
337 /* Get the disc title */ | |
338 psz_data = p_sector + 40; | |
339 psz_data[32] = '\0'; | |
340 | |
341 for( i = 0 ; i < 32 ; i++ ) | |
342 { | |
343 if( psz_data[i] <= ' ' ) | |
344 { | |
345 psz_data[i] = '\0'; | |
346 break; | |
347 } | |
348 else if( psz_data[i] == '/' || psz_data[i] == '\\' ) | |
349 { | |
350 psz_data[i] = '-'; | |
351 } | |
352 } | |
353 | |
354 /* If it's not long enough, try the date + serial */ | |
355 if( strlen( psz_data ) < 6 ) | |
356 { | |
357 psz_data = p_sector + 813; | |
358 psz_data[16] = '\0'; | |
359 | |
360 /* Check that all characters are digits, otherwise convert. */ | |
361 for( i = 0 ; i < 16 ; i++ ) | |
362 { | |
363 if( psz_data[i] < '0' || psz_data[i] > '9' ) | |
364 { | |
365 sprintf( psz_data, | |
366 "%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X", | |
367 psz_data[0], psz_data[1], psz_data[2], | |
368 psz_data[3], psz_data[4], psz_data[5], | |
369 psz_data[6], psz_data[7] ); | |
370 break; | |
371 } | |
372 } | |
373 } | |
374 | |
375 /* We have a disc name or ID, we can create the cache dir */ | |
376 i = sprintf( dvdcss->psz_cachefile, "%s", psz_cache ); | |
377 #if !defined( WIN32 ) || defined( SYS_CYGWIN ) | |
378 i_ret = mkdir( dvdcss->psz_cachefile, 0755 ); | |
379 #else | |
380 i_ret = mkdir( dvdcss->psz_cachefile ); | |
381 #endif | |
382 if( i_ret < 0 && errno != EEXIST ) | |
383 { | |
384 _dvdcss_error( dvdcss, "failed creating cache directory" ); | |
385 dvdcss->psz_cachefile[0] = '\0'; | |
386 goto nocache; | |
387 } | |
388 | |
389 i += sprintf( dvdcss->psz_cachefile + i, "/%s/", psz_data ); | |
390 #if !defined( WIN32 ) || defined( SYS_CYGWIN ) | |
391 i_ret = mkdir( dvdcss->psz_cachefile, 0755 ); | |
392 #else | |
393 i_ret = mkdir( dvdcss->psz_cachefile ); | |
394 #endif | |
395 if( i_ret < 0 && errno != EEXIST ) | |
396 { | |
397 _dvdcss_error( dvdcss, "failed creating cache subdirectory" ); | |
398 dvdcss->psz_cachefile[0] = '\0'; | |
399 goto nocache; | |
400 } | |
401 | |
402 /* Pointer to the filename we will use. */ | |
403 dvdcss->psz_block = dvdcss->psz_cachefile + i; | |
404 | |
405 sprintf( psz_debug, "using CSS key cache dir: %s", | |
406 dvdcss->psz_cachefile ); | |
407 _dvdcss_debug( dvdcss, psz_debug ); | |
408 } | |
409 nocache: | |
410 | |
411 /* Seek at the beginning, just for safety. */ | |
412 dvdcss->pf_seek( dvdcss, 0 ); | |
309 | 413 |
310 return dvdcss; | 414 return dvdcss; |
311 } | 415 } |
312 | 416 |
313 /** | 417 /** |
352 */ | 456 */ |
353 extern int dvdcss_seek ( dvdcss_t dvdcss, int i_blocks, int i_flags ) | 457 extern int dvdcss_seek ( dvdcss_t dvdcss, int i_blocks, int i_flags ) |
354 { | 458 { |
355 /* title cracking method is too slow to be used at each seek */ | 459 /* title cracking method is too slow to be used at each seek */ |
356 if( ( ( i_flags & DVDCSS_SEEK_MPEG ) | 460 if( ( ( i_flags & DVDCSS_SEEK_MPEG ) |
357 && ( dvdcss->i_method != DVDCSS_METHOD_TITLE ) ) | 461 && ( dvdcss->i_method != DVDCSS_METHOD_TITLE ) ) |
358 || ( i_flags & DVDCSS_SEEK_KEY ) ) | 462 || ( i_flags & DVDCSS_SEEK_KEY ) ) |
359 { | 463 { |
360 /* check the title key */ | 464 /* check the title key */ |
361 if( _dvdcss_title( dvdcss, i_blocks ) ) | 465 if( _dvdcss_title( dvdcss, i_blocks ) ) |
362 { | 466 { |
363 return -1; | 467 return -1; |
364 } | 468 } |
365 } | 469 } |
366 | 470 |
405 return i_ret; | 509 return i_ret; |
406 } | 510 } |
407 | 511 |
408 if( ! memcmp( dvdcss->css.p_title_key, "\0\0\0\0\0", 5 ) ) | 512 if( ! memcmp( dvdcss->css.p_title_key, "\0\0\0\0\0", 5 ) ) |
409 { | 513 { |
410 /* For what we believe is an unencrypted title, | 514 /* For what we believe is an unencrypted title, |
411 * check that there are no encrypted blocks */ | 515 * check that there are no encrypted blocks */ |
412 for( i_index = i_ret; i_index; i_index-- ) | 516 for( i_index = i_ret; i_index; i_index-- ) |
413 { | 517 { |
414 if( ((u8*)p_buffer)[0x14] & 0x30 ) | 518 if( ((uint8_t*)p_buffer)[0x14] & 0x30 ) |
415 { | 519 { |
416 _dvdcss_error( dvdcss, "no key but found encrypted block" ); | 520 _dvdcss_error( dvdcss, "no key but found encrypted block" ); |
417 /* Only return the initial range of unscrambled blocks? */ | 521 /* Only return the initial range of unscrambled blocks? */ |
418 /* or fail completely? return 0; */ | 522 /* or fail completely? return 0; */ |
419 break; | 523 break; |
420 } | 524 } |
421 p_buffer = (void *) ((u8 *)p_buffer + DVDCSS_BLOCK_SIZE); | 525 p_buffer = (void *) ((uint8_t *)p_buffer + DVDCSS_BLOCK_SIZE); |
422 } | 526 } |
423 } | 527 } |
424 else | 528 else |
425 { | 529 { |
426 /* Decrypt the blocks we managed to read */ | 530 /* Decrypt the blocks we managed to read */ |
427 for( i_index = i_ret; i_index; i_index-- ) | 531 for( i_index = i_ret; i_index; i_index-- ) |
428 { | 532 { |
429 _dvdcss_unscramble( dvdcss->css.p_title_key, p_buffer ); | 533 _dvdcss_unscramble( dvdcss->css.p_title_key, p_buffer ); |
430 ((u8*)p_buffer)[0x14] &= 0x8f; | 534 ((uint8_t*)p_buffer)[0x14] &= 0x8f; |
431 p_buffer = (void *) ((u8 *)p_buffer + DVDCSS_BLOCK_SIZE); | 535 p_buffer = (void *) ((uint8_t *)p_buffer + DVDCSS_BLOCK_SIZE); |
432 } | 536 } |
433 } | 537 } |
434 | 538 |
435 return i_ret; | 539 return i_ret; |
436 } | 540 } |
437 | 541 |
438 /** | 542 /** |
439 * \brief Read from the disc into multiple buffers and decrypt data if | 543 * \brief Read from the disc into multiple buffers and decrypt data if |
500 iov_base = _p_iovec->iov_base; | 604 iov_base = _p_iovec->iov_base; |
501 iov_len = _p_iovec->iov_len; | 605 iov_len = _p_iovec->iov_len; |
502 } | 606 } |
503 | 607 |
504 _dvdcss_unscramble( dvdcss->css.p_title_key, iov_base ); | 608 _dvdcss_unscramble( dvdcss->css.p_title_key, iov_base ); |
505 ((u8*)iov_base)[0x14] &= 0x8f; | 609 ((uint8_t*)iov_base)[0x14] &= 0x8f; |
506 | 610 |
507 iov_base = (void *) ((u8*)iov_base + DVDCSS_BLOCK_SIZE); | 611 iov_base = (void *) ((uint8_t*)iov_base + DVDCSS_BLOCK_SIZE); |
508 iov_len -= DVDCSS_BLOCK_SIZE; | 612 iov_len -= DVDCSS_BLOCK_SIZE; |
509 } | 613 } |
510 | 614 |
511 return i_ret; | 615 return i_ret; |
512 } | 616 } |