~ubuntu-branches/ubuntu/raring/libdvdread/raring-proposed

« back to all changes in this revision

Viewing changes to .pc/09-segfault.patch/src/dvd_reader.c

  • Committer: Package Import Robot
  • Author(s): Vibhav Pant
  • Date: 2012-12-15 17:06:42 UTC
  • mfrom: (1.3.2) (3.2.15 sid)
  • Revision ID: package-import@ubuntu.com-20121215170642-q0h4cc4r2mchkgcl
Tags: 4.2.0+20121016-1ubuntu1
* Merge from Debian unstable (LP: #1090692).  Remaining changes:
  - Re-add missing install-css.sh.
  - debian/control: add Suggests for install-css.sh on debhelper,
    fakeroot, and build-essential.
  - debian/rules: install install-css.sh, leave perms executable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (C) 2001-2004 Billy Biggs <vektor@dumbterm.net>,
3
 
 *                         Håkan Hjort <d95hjort@dtek.chalmers.se>,
4
 
 *                         Björn Englund <d4bjorn@dtek.chalmers.se>
5
 
 *
6
 
 * This file is part of libdvdread.
7
 
 *
8
 
 * libdvdread is free software; you can redistribute it and/or modify
9
 
 * it under the terms of the GNU General Public License as published by
10
 
 * the Free Software Foundation; either version 2 of the License, or
11
 
 * (at your option) any later version.
12
 
 *
13
 
 * libdvdread is distributed in the hope that it will be useful,
14
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 
 * GNU General Public License for more details.
17
 
 *
18
 
 * You should have received a copy of the GNU General Public License along
19
 
 * with libdvdread; if not, write to the Free Software Foundation, Inc.,
20
 
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
 
 */
22
 
 
23
 
#include <sys/types.h>
24
 
#include <sys/stat.h>
25
 
#include <sys/time.h> /* For the timing of dvdcss_title crack. */
26
 
#include <fcntl.h>
27
 
#include <stdlib.h>
28
 
#include <stdio.h>
29
 
#include <errno.h>
30
 
#include <string.h>
31
 
#include <ctype.h>
32
 
#define _GNU_SOURCE
33
 
#include <unistd.h>
34
 
#include <limits.h>
35
 
#include <dirent.h>
36
 
 
37
 
/* misc win32 helpers */
38
 
#ifdef WIN32
39
 
#ifndef HAVE_GETTIMEOFDAY
40
 
/* replacement gettimeofday implementation */
41
 
#include <sys/timeb.h>
42
 
static inline int _private_gettimeofday( struct timeval *tv, void *tz )
43
 
{
44
 
  struct timeb t;
45
 
  ftime( &t );
46
 
  tv->tv_sec = t.time;
47
 
  tv->tv_usec = t.millitm * 1000;
48
 
  return 0;
49
 
}
50
 
#define gettimeofday(TV, TZ) _private_gettimeofday((TV), (TZ))
51
 
#endif
52
 
#include <io.h> /* read() */
53
 
#define lseek64 _lseeki64
54
 
#endif
55
 
 
56
 
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__bsdi__) || defined(__APPLE__)
57
 
#define SYS_BSD 1
58
 
#endif
59
 
 
60
 
#if defined(__sun)
61
 
#include <sys/mnttab.h>
62
 
#elif defined(__APPLE__)
63
 
#include <sys/param.h>
64
 
#include <sys/ucred.h>
65
 
#include <sys/mount.h>
66
 
#elif defined(SYS_BSD)
67
 
#include <fstab.h>
68
 
#elif defined(__linux__)
69
 
#include <mntent.h>
70
 
#include <paths.h>
71
 
#endif
72
 
 
73
 
#include "dvdread/dvd_udf.h"
74
 
#include "dvd_input.h"
75
 
#include "dvdread/dvd_reader.h"
76
 
#include "md5.h"
77
 
 
78
 
#define DEFAULT_UDF_CACHE_LEVEL 1
79
 
 
80
 
struct dvd_reader_s {
81
 
  /* Basic information. */
82
 
  int isImageFile;
83
 
 
84
 
  /* Hack for keeping track of the css status.
85
 
   * 0: no css, 1: perhaps (need init of keys), 2: have done init */
86
 
  int css_state;
87
 
  int css_title; /* Last title that we have called dvdinpute_title for. */
88
 
 
89
 
  /* Information required for an image file. */
90
 
  dvd_input_t dev;
91
 
 
92
 
  /* Information required for a directory path drive. */
93
 
  char *path_root;
94
 
 
95
 
  /* Filesystem cache */
96
 
  int udfcache_level; /* 0 - turned off, 1 - on */
97
 
  void *udfcache;
98
 
};
99
 
 
100
 
#define TITLES_MAX 9
101
 
 
102
 
struct dvd_file_s {
103
 
  /* Basic information. */
104
 
  dvd_reader_t *dvd;
105
 
 
106
 
  /* Hack for selecting the right css title. */
107
 
  int css_title;
108
 
 
109
 
  /* Information required for an image file. */
110
 
  uint32_t lb_start;
111
 
  uint32_t seek_pos;
112
 
 
113
 
  /* Information required for a directory path drive. */
114
 
  size_t title_sizes[ TITLES_MAX ];
115
 
  dvd_input_t title_devs[ TITLES_MAX ];
116
 
 
117
 
  /* Calculated at open-time, size in blocks. */
118
 
  ssize_t filesize;
119
 
};
120
 
 
121
 
int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number,
122
 
                      size_t block_count, unsigned char *data,
123
 
                      int encrypted );
124
 
 
125
 
/**
126
 
 * Set the level of caching on udf
127
 
 * level = 0 (no caching)
128
 
 * level = 1 (caching filesystem info)
129
 
 */
130
 
int DVDUDFCacheLevel(dvd_reader_t *device, int level)
131
 
{
132
 
  struct dvd_reader_s *dev = (struct dvd_reader_s *)device;
133
 
 
134
 
  if(level > 0) {
135
 
    level = 1;
136
 
  } else if(level < 0) {
137
 
    return dev->udfcache_level;
138
 
  }
139
 
 
140
 
  dev->udfcache_level = level;
141
 
 
142
 
  return level;
143
 
}
144
 
 
145
 
void *GetUDFCacheHandle(dvd_reader_t *device)
146
 
{
147
 
  struct dvd_reader_s *dev = (struct dvd_reader_s *)device;
148
 
 
149
 
  return dev->udfcache;
150
 
}
151
 
 
152
 
void SetUDFCacheHandle(dvd_reader_t *device, void *cache)
153
 
{
154
 
  struct dvd_reader_s *dev = (struct dvd_reader_s *)device;
155
 
 
156
 
  dev->udfcache = cache;
157
 
}
158
 
 
159
 
 
160
 
 
161
 
/* Loop over all titles and call dvdcss_title to crack the keys. */
162
 
static int initAllCSSKeys( dvd_reader_t *dvd )
163
 
{
164
 
  struct timeval all_s, all_e;
165
 
  struct timeval t_s, t_e;
166
 
  char filename[ MAX_UDF_FILE_NAME_LEN ];
167
 
  uint32_t start, len;
168
 
  int title;
169
 
 
170
 
  char *nokeys_str = getenv("DVDREAD_NOKEYS");
171
 
  if(nokeys_str != NULL)
172
 
    return 0;
173
 
 
174
 
  fprintf( stderr, "\n" );
175
 
  fprintf( stderr, "libdvdread: Attempting to retrieve all CSS keys\n" );
176
 
  fprintf( stderr, "libdvdread: This can take a _long_ time, "
177
 
           "please be patient\n\n" );
178
 
  gettimeofday(&all_s, NULL);
179
 
 
180
 
  for( title = 0; title < 100; title++ ) {
181
 
    gettimeofday( &t_s, NULL );
182
 
    if( title == 0 ) {
183
 
      sprintf( filename, "/VIDEO_TS/VIDEO_TS.VOB" );
184
 
    } else {
185
 
      sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, 0 );
186
 
    }
187
 
    start = UDFFindFile( dvd, filename, &len );
188
 
    if( start != 0 && len != 0 ) {
189
 
      /* Perform CSS key cracking for this title. */
190
 
      fprintf( stderr, "libdvdread: Get key for %s at 0x%08x\n",
191
 
               filename, start );
192
 
      if( dvdinput_title( dvd->dev, (int)start ) < 0 ) {
193
 
        fprintf( stderr, "libdvdread: Error cracking CSS key for %s (0x%08x)\n", filename, start);
194
 
      }
195
 
      gettimeofday( &t_e, NULL );
196
 
      fprintf( stderr, "libdvdread: Elapsed time %ld\n",
197
 
               (long int) t_e.tv_sec - t_s.tv_sec );
198
 
    }
199
 
 
200
 
    if( title == 0 ) continue;
201
 
 
202
 
    gettimeofday( &t_s, NULL );
203
 
    sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, 1 );
204
 
    start = UDFFindFile( dvd, filename, &len );
205
 
    if( start == 0 || len == 0 ) break;
206
 
 
207
 
    /* Perform CSS key cracking for this title. */
208
 
    fprintf( stderr, "libdvdread: Get key for %s at 0x%08x\n",
209
 
             filename, start );
210
 
    if( dvdinput_title( dvd->dev, (int)start ) < 0 ) {
211
 
      fprintf( stderr, "libdvdread: Error cracking CSS key for %s (0x%08x)!!\n", filename, start);
212
 
    }
213
 
    gettimeofday( &t_e, NULL );
214
 
    fprintf( stderr, "libdvdread: Elapsed time %ld\n",
215
 
             (long int) t_e.tv_sec - t_s.tv_sec );
216
 
  }
217
 
  title--;
218
 
 
219
 
  fprintf( stderr, "libdvdread: Found %d VTS's\n", title );
220
 
  gettimeofday(&all_e, NULL);
221
 
  fprintf( stderr, "libdvdread: Elapsed time %ld\n",
222
 
           (long int) all_e.tv_sec - all_s.tv_sec );
223
 
 
224
 
  return 0;
225
 
}
226
 
 
227
 
 
228
 
 
229
 
/**
230
 
 * Open a DVD image or block device file.
231
 
 */
232
 
static dvd_reader_t *DVDOpenImageFile( const char *location, int have_css )
233
 
{
234
 
  dvd_reader_t *dvd;
235
 
  dvd_input_t dev;
236
 
 
237
 
  dev = dvdinput_open( location );
238
 
  if( !dev ) {
239
 
    fprintf( stderr, "libdvdread: Can't open %s for reading\n", location );
240
 
    return NULL;
241
 
  }
242
 
 
243
 
  dvd = (dvd_reader_t *) malloc( sizeof( dvd_reader_t ) );
244
 
  if( !dvd ) {
245
 
    dvdinput_close(dev);
246
 
    return NULL;
247
 
  }
248
 
  dvd->isImageFile = 1;
249
 
  dvd->dev = dev;
250
 
  dvd->path_root = NULL;
251
 
 
252
 
  dvd->udfcache_level = DEFAULT_UDF_CACHE_LEVEL;
253
 
  dvd->udfcache = NULL;
254
 
 
255
 
  if( have_css ) {
256
 
    /* Only if DVDCSS_METHOD = title, a bit if it's disc or if
257
 
     * DVDCSS_METHOD = key but region mismatch. Unfortunately we
258
 
     * don't have that information. */
259
 
 
260
 
    dvd->css_state = 1; /* Need key init. */
261
 
  }
262
 
  dvd->css_title = 0;
263
 
 
264
 
  return dvd;
265
 
}
266
 
 
267
 
static dvd_reader_t *DVDOpenPath( const char *path_root )
268
 
{
269
 
  dvd_reader_t *dvd;
270
 
 
271
 
  dvd = (dvd_reader_t *) malloc( sizeof( dvd_reader_t ) );
272
 
  if( !dvd ) return NULL;
273
 
  dvd->isImageFile = 0;
274
 
  dvd->dev = 0;
275
 
  dvd->path_root = strdup( path_root );
276
 
  if(!dvd->path_root) {
277
 
    free(dvd);
278
 
    return 0;
279
 
  }
280
 
  dvd->udfcache_level = DEFAULT_UDF_CACHE_LEVEL;
281
 
  dvd->udfcache = NULL;
282
 
 
283
 
  dvd->css_state = 0; /* Only used in the UDF path */
284
 
  dvd->css_title = 0; /* Only matters in the UDF path */
285
 
 
286
 
  return dvd;
287
 
}
288
 
 
289
 
#if defined(__sun)
290
 
/* /dev/rdsk/c0t6d0s0 (link to /devices/...)
291
 
   /vol/dev/rdsk/c0t6d0/??
292
 
   /vol/rdsk/<name> */
293
 
static char *sun_block2char( const char *path )
294
 
{
295
 
  char *new_path;
296
 
 
297
 
  /* Must contain "/dsk/" */
298
 
  if( !strstr( path, "/dsk/" ) ) return (char *) strdup( path );
299
 
 
300
 
  /* Replace "/dsk/" with "/rdsk/" */
301
 
  new_path = malloc( strlen(path) + 2 );
302
 
  strcpy( new_path, path );
303
 
  strcpy( strstr( new_path, "/dsk/" ), "" );
304
 
  strcat( new_path, "/rdsk/" );
305
 
  strcat( new_path, strstr( path, "/dsk/" ) + strlen( "/dsk/" ) );
306
 
 
307
 
  return new_path;
308
 
}
309
 
#endif
310
 
 
311
 
#if defined(SYS_BSD)
312
 
/* FreeBSD /dev/(r)(a)cd0c (a is for atapi), recommended to _not_ use r
313
 
   update: FreeBSD and DragonFly no longer uses the prefix so don't add it.
314
 
   OpenBSD /dev/rcd0c, it needs to be the raw device
315
 
   NetBSD  /dev/rcd0[d|c|..] d for x86, c (for non x86), perhaps others
316
 
   Darwin  /dev/rdisk0,  it needs to be the raw device
317
 
   BSD/OS  /dev/sr0c (if not mounted) or /dev/rsr0c ('c' any letter will do)
318
 
   returns a string allocated with strdup. It should be freed when no longer
319
 
   used. */
320
 
static char *bsd_block2char( const char *path )
321
 
{
322
 
#if defined(__FreeBSD__) || defined(__DragonFly__)
323
 
  return (char *) strdup( path );
324
 
#else
325
 
  char *new_path;
326
 
 
327
 
  /* If it doesn't start with "/dev/" or does start with "/dev/r" exit */
328
 
  if( strncmp( path, "/dev/",  5 ) || !strncmp( path, "/dev/r", 6 ) )
329
 
    return (char *) strdup( path );
330
 
 
331
 
  /* Replace "/dev/" with "/dev/r" */
332
 
  new_path = malloc( strlen(path) + 2 );
333
 
  strcpy( new_path, "/dev/r" );
334
 
  strcat( new_path, path + strlen( "/dev/" ) );
335
 
 
336
 
  return new_path;
337
 
#endif /* __FreeBSD__ || __DragonFly__ */
338
 
}
339
 
#endif
340
 
 
341
 
 
342
 
dvd_reader_t *DVDOpen( const char *ppath )
343
 
{
344
 
  struct stat fileinfo;
345
 
  int ret, have_css, retval, cdir = -1;
346
 
  dvd_reader_t *ret_val = NULL;
347
 
  char *dev_name = NULL;
348
 
  char *path = NULL, *new_path = NULL, *path_copy = NULL;
349
 
 
350
 
#if defined(_WIN32) || defined(__OS2__)
351
 
      int len;
352
 
#endif
353
 
 
354
 
  if( ppath == NULL )
355
 
    goto DVDOpen_error;
356
 
 
357
 
      path = strdup(ppath);
358
 
  if( path == NULL )
359
 
    goto DVDOpen_error;
360
 
 
361
 
  /* Try to open libdvdcss or fall back to standard functions */
362
 
  have_css = dvdinput_setup();
363
 
 
364
 
#if defined(_WIN32) || defined(__OS2__)
365
 
  /* Strip off the trailing \ if it is not a drive */
366
 
  len = strlen(path);
367
 
  if ((len > 1) &&
368
 
      (path[len - 1] == '\\')  &&
369
 
      (path[len - 2] != ':'))
370
 
  {
371
 
    path[len-1] = '\0';
372
 
  }
373
 
#endif
374
 
 
375
 
  ret = stat( path, &fileinfo );
376
 
 
377
 
  if( ret < 0 ) {
378
 
 
379
 
    /* maybe "host:port" url? try opening it with acCeSS library */
380
 
    if( strchr(path,':') ) {
381
 
                    ret_val = DVDOpenImageFile( path, have_css );
382
 
                    free(path);
383
 
            return ret_val;
384
 
    }
385
 
 
386
 
    /* If we can't stat the file, give up */
387
 
    fprintf( stderr, "libdvdread: Can't stat %s\n", path );
388
 
    perror("");
389
 
    goto DVDOpen_error;
390
 
  }
391
 
 
392
 
  /* First check if this is a block/char device or a file*/
393
 
  if( S_ISBLK( fileinfo.st_mode ) ||
394
 
      S_ISCHR( fileinfo.st_mode ) ||
395
 
      S_ISREG( fileinfo.st_mode ) ) {
396
 
 
397
 
    /**
398
 
     * Block devices and regular files are assumed to be DVD-Video images.
399
 
     */
400
 
    dvd_reader_t *dvd = NULL;
401
 
#if defined(__sun)
402
 
    dev_name = sun_block2char( path );
403
 
#elif defined(SYS_BSD)
404
 
    dev_name = bsd_block2char( path );
405
 
#else
406
 
    dev_name = strdup( path );
407
 
#endif
408
 
    dvd = DVDOpenImageFile( dev_name, have_css );
409
 
    free( dev_name );
410
 
    free(path);
411
 
    return dvd;
412
 
  } else if( S_ISDIR( fileinfo.st_mode ) ) {
413
 
    dvd_reader_t *auth_drive = 0;
414
 
#if defined(SYS_BSD)
415
 
    struct fstab* fe;
416
 
#elif defined(__sun) || defined(__linux__)
417
 
    FILE *mntfile;
418
 
#endif
419
 
 
420
 
    /* XXX: We should scream real loud here. */
421
 
    if( !(path_copy = strdup( path ) ) )
422
 
      goto DVDOpen_error;
423
 
 
424
 
#ifndef WIN32 /* don't have fchdir, and getcwd( NULL, ... ) is strange */
425
 
              /* Also WIN32 does not have symlinks, so we don't need this bit of code. */
426
 
 
427
 
    /* Resolve any symlinks and get the absolute dir name. */
428
 
    {
429
 
      if( ( cdir  = open( ".", O_RDONLY ) ) >= 0 ) {
430
 
        if( chdir( path_copy ) == -1 ) {
431
 
          goto DVDOpen_error;
432
 
        }
433
 
#ifdef __GLIBC__
434
 
        new_path = get_current_dir_name();
435
 
        if(new_path == NULL) {
436
 
          goto DVDOpen_error;
437
 
        }
438
 
#else
439
 
        new_path = malloc(PATH_MAX+1);
440
 
        if(!new_path) {
441
 
          goto DVDOpen_error;
442
 
        }
443
 
        if( getcwd( new_path, PATH_MAX ) == NULL ) {
444
 
          goto DVDOpen_error;
445
 
        }
446
 
#endif
447
 
        retval = fchdir( cdir );
448
 
        close( cdir );
449
 
        cdir = -1;
450
 
        if( retval == -1 ) {
451
 
          goto DVDOpen_error;
452
 
        }
453
 
        path_copy = new_path;
454
 
        new_path = NULL;
455
 
      }
456
 
    }
457
 
#endif
458
 
 
459
 
    /**
460
 
     * If we're being asked to open a directory, check if that directory
461
 
     * is the mount point for a DVD-ROM which we can use instead.
462
 
     */
463
 
 
464
 
    if( strlen( path_copy ) > 1 ) {
465
 
      if( path_copy[ strlen( path_copy ) - 1 ] == '/' ) {
466
 
        path_copy[ strlen( path_copy ) - 1 ] = '\0';
467
 
      }
468
 
    }
469
 
 
470
 
#if defined(_WIN32) || defined(__OS2__)
471
 
    if(strlen(path_copy) > TITLES_MAX) {
472
 
      if(!strcasecmp(&(path_copy[strlen( path_copy ) - TITLES_MAX]),
473
 
                       "\\video_ts"))
474
 
        path_copy[strlen(path_copy) - (TITLES_MAX-1)] = '\0';
475
 
    }
476
 
#endif
477
 
    if( strlen( path_copy ) > TITLES_MAX ) {
478
 
      if( !strcasecmp( &(path_copy[ strlen( path_copy ) - TITLES_MAX ]),
479
 
                       "/video_ts" ) ) {
480
 
        path_copy[ strlen( path_copy ) - TITLES_MAX ] = '\0';
481
 
      }
482
 
    }
483
 
 
484
 
    if(path_copy[0] == '\0') {
485
 
      path_copy[0] = '/';
486
 
      path_copy[1] = '\0';
487
 
    }
488
 
 
489
 
#if defined(__APPLE__)
490
 
    struct statfs s[128];
491
 
    int r = getfsstat(NULL, 0, MNT_NOWAIT);
492
 
    if (r > 0) {
493
 
        if (r > 128)
494
 
            r = 128;
495
 
        r = getfsstat(s, r * sizeof(s[0]), MNT_NOWAIT);
496
 
        int i;
497
 
        for (i=0; i<r; i++) {
498
 
            if (!strcmp(path_copy, s[i].f_mntonname)) {
499
 
                dev_name = bsd_block2char(s[i].f_mntfromname);
500
 
                fprintf( stderr,
501
 
                        "libdvdread: Attempting to use device %s"
502
 
                        " mounted on %s for CSS authentication\n",
503
 
                        dev_name,
504
 
                        s[i].f_mntonname);
505
 
                auth_drive = DVDOpenImageFile( dev_name, have_css );
506
 
                break;
507
 
            }
508
 
        }
509
 
    }
510
 
#elif defined(SYS_BSD)
511
 
    if( ( fe = getfsfile( path_copy ) ) ) {
512
 
      dev_name = bsd_block2char( fe->fs_spec );
513
 
      fprintf( stderr,
514
 
               "libdvdread: Attempting to use device %s"
515
 
               " mounted on %s for CSS authentication\n",
516
 
               dev_name,
517
 
               fe->fs_file );
518
 
      auth_drive = DVDOpenImageFile( dev_name, have_css );
519
 
    }
520
 
#elif defined(__sun)
521
 
    mntfile = fopen( MNTTAB, "r" );
522
 
    if( mntfile ) {
523
 
      struct mnttab mp;
524
 
      int res;
525
 
 
526
 
      while( ( res = getmntent( mntfile, &mp ) ) != -1 ) {
527
 
        if( res == 0 && !strcmp( mp.mnt_mountp, path_copy ) ) {
528
 
          dev_name = sun_block2char( mp.mnt_special );
529
 
          fprintf( stderr,
530
 
                   "libdvdread: Attempting to use device %s"
531
 
                   " mounted on %s for CSS authentication\n",
532
 
                   dev_name,
533
 
                   mp.mnt_mountp );
534
 
          auth_drive = DVDOpenImageFile( dev_name, have_css );
535
 
          break;
536
 
        }
537
 
      }
538
 
      fclose( mntfile );
539
 
    }
540
 
#elif defined(__linux__)
541
 
    mntfile = fopen( _PATH_MOUNTED, "r" );
542
 
    if( mntfile ) {
543
 
      struct mntent *me;
544
 
 
545
 
      while( ( me = getmntent( mntfile ) ) ) {
546
 
        if( !strcmp( me->mnt_dir, path_copy ) ) {
547
 
          fprintf( stderr,
548
 
                   "libdvdread: Attempting to use device %s"
549
 
                   " mounted on %s for CSS authentication\n",
550
 
                   me->mnt_fsname,
551
 
                   me->mnt_dir );
552
 
          auth_drive = DVDOpenImageFile( me->mnt_fsname, have_css );
553
 
          dev_name = strdup(me->mnt_fsname);
554
 
          break;
555
 
        }
556
 
      }
557
 
      fclose( mntfile );
558
 
    }
559
 
#elif defined(_WIN32) || defined(__OS2__)
560
 
#ifdef __OS2__
561
 
    /* Use DVDOpenImageFile() only if it is a drive */
562
 
    if(isalpha(path[0]) && path[1] == ':' &&
563
 
        ( !path[2] ||
564
 
          ((path[2] == '\\' || path[2] == '/') && !path[3])))
565
 
#endif
566
 
    auth_drive = DVDOpenImageFile( path, have_css );
567
 
#endif
568
 
 
569
 
#if !defined(_WIN32) && !defined(__OS2__)
570
 
    if( !dev_name ) {
571
 
      fprintf( stderr, "libdvdread: Couldn't find device name.\n" );
572
 
    } else if( !auth_drive ) {
573
 
      fprintf( stderr, "libdvdread: Device %s inaccessible, "
574
 
               "CSS authentication not available.\n", dev_name );
575
 
    }
576
 
#else
577
 
    if( !auth_drive ) {
578
 
        fprintf( stderr, "libdvdread: Device %s inaccessible, "
579
 
                 "CSS authentication not available.\n", path );
580
 
    }
581
 
#endif
582
 
 
583
 
    free( dev_name );
584
 
    dev_name = NULL;
585
 
    free( path_copy );
586
 
    path_copy = NULL;
587
 
 
588
 
    /**
589
 
     * If we've opened a drive, just use that.
590
 
     */
591
 
    if( auth_drive ) {
592
 
      free(path);
593
 
      return auth_drive;
594
 
    }
595
 
    /**
596
 
     * Otherwise, we now try to open the directory tree instead.
597
 
     */
598
 
    ret_val = DVDOpenPath( path );
599
 
      free( path );
600
 
      return ret_val;
601
 
  }
602
 
 
603
 
DVDOpen_error:
604
 
  /* If it's none of the above, screw it. */
605
 
  fprintf( stderr, "libdvdread: Could not open %s\n", path );
606
 
  if( path != NULL )
607
 
    free( path );
608
 
  if ( path_copy != NULL )
609
 
    free( path_copy );
610
 
  if ( cdir >= 0 )
611
 
    close( cdir );
612
 
  if ( new_path != NULL )
613
 
    free( new_path );
614
 
  return NULL;
615
 
}
616
 
 
617
 
void DVDClose( dvd_reader_t *dvd )
618
 
{
619
 
  if( dvd ) {
620
 
    if( dvd->dev ) dvdinput_close( dvd->dev );
621
 
    if( dvd->path_root ) free( dvd->path_root );
622
 
    if( dvd->udfcache ) FreeUDFCache( dvd->udfcache );
623
 
    free( dvd );
624
 
  }
625
 
}
626
 
 
627
 
/**
628
 
 * Open an unencrypted file on a DVD image file.
629
 
 */
630
 
static dvd_file_t *DVDOpenFileUDF( dvd_reader_t *dvd, char *filename )
631
 
{
632
 
  uint32_t start, len;
633
 
  dvd_file_t *dvd_file;
634
 
 
635
 
  start = UDFFindFile( dvd, filename, &len );
636
 
  if( !start ) {
637
 
    fprintf( stderr, "libdvdnav:DVDOpenFileUDF:UDFFindFile %s failed\n", filename );
638
 
    return NULL;
639
 
  }
640
 
 
641
 
  dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
642
 
  if( !dvd_file ) {
643
 
    fprintf( stderr, "libdvdnav:DVDOpenFileUDF:malloc failed\n" );
644
 
    return NULL;
645
 
  }
646
 
  dvd_file->dvd = dvd;
647
 
  dvd_file->lb_start = start;
648
 
  dvd_file->seek_pos = 0;
649
 
  memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
650
 
  memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) );
651
 
  dvd_file->filesize = len / DVD_VIDEO_LB_LEN;
652
 
 
653
 
  return dvd_file;
654
 
}
655
 
 
656
 
/**
657
 
 * Searches for <file> in directory <path>, ignoring case.
658
 
 * Returns 0 and full filename in <filename>.
659
 
 *     or -1 on file not found.
660
 
 *     or -2 on path not found.
661
 
 */
662
 
static int findDirFile( const char *path, const char *file, char **filename )
663
 
{
664
 
  DIR *dir;
665
 
  struct dirent *ent;
666
 
  *filename = NULL;
667
 
 
668
 
  dir = opendir( path );
669
 
  if( !dir ) return -2;
670
 
 
671
 
  while( ( ent = readdir( dir ) ) != NULL ) {
672
 
    if( !strcasecmp( ent->d_name, file ) ) {
673
 
      *filename = malloc( strlen( path ) + 1 + strlen( ent->d_name ) + 1 );
674
 
      if( *filename == NULL ) {
675
 
        closedir(dir);
676
 
        return -1;
677
 
      }
678
 
      sprintf( *filename, "%s%s%s", path,
679
 
               ( ( path[ strlen( path ) - 1 ] == '/' ) ? "" : "/" ),
680
 
               ent->d_name );
681
 
      closedir(dir);
682
 
      return 0;
683
 
    }
684
 
  }
685
 
  closedir(dir);
686
 
  return -1;
687
 
}
688
 
 
689
 
static int findDVDFile( dvd_reader_t *dvd, const char *file, char **filename )
690
 
{
691
 
  char *video_path = NULL;
692
 
  const char *nodirfile;
693
 
  int ret;
694
 
 
695
 
  /* Strip off the directory for our search */
696
 
  if( !strncasecmp( "/VIDEO_TS/", file, 10 ) ) {
697
 
    nodirfile = &(file[ 10 ]);
698
 
  } else {
699
 
    nodirfile = file;
700
 
  }
701
 
 
702
 
  ret = findDirFile( dvd->path_root, nodirfile, filename );
703
 
  if( ret < 0 ) {
704
 
    /* Try also with adding the path, just in case. */
705
 
    video_path = malloc( strlen( dvd->path_root ) + 10 + 1 );
706
 
    if( video_path == NULL ) return 0;
707
 
    sprintf( video_path, "%s/VIDEO_TS/", dvd->path_root );
708
 
    ret = findDirFile( video_path, nodirfile, filename );
709
 
    if( ret < 0 ) {
710
 
      /* Try with the path, but in lower case. */
711
 
      sprintf( video_path, "%s/video_ts/", dvd->path_root );
712
 
      ret = findDirFile( video_path, nodirfile, filename );
713
 
      if( ret < 0 ) {
714
 
        free( video_path );
715
 
        return 0;
716
 
      }
717
 
    }
718
 
    free( video_path );
719
 
  }
720
 
 
721
 
  return 1;
722
 
}
723
 
 
724
 
/**
725
 
 * Open an unencrypted file from a DVD directory tree.
726
 
 */
727
 
static dvd_file_t *DVDOpenFilePath( dvd_reader_t *dvd, char *filename )
728
 
{
729
 
  char *full_path = NULL;
730
 
  dvd_file_t *dvd_file;
731
 
  struct stat fileinfo;
732
 
  dvd_input_t dev;
733
 
 
734
 
  /* Get the full path of the file. */
735
 
  if( !findDVDFile( dvd, filename, &full_path ) ) {
736
 
    fprintf( stderr, "libdvdnav:DVDOpenFilePath:findDVDFile %s failed\n", filename );
737
 
    free( full_path );
738
 
    return NULL;
739
 
  }
740
 
 
741
 
  dev = dvdinput_open( full_path );
742
 
  if( !dev ) {
743
 
    fprintf( stderr, "libdvdnav:DVDOpenFilePath:dvdinput_open %s failed\n", full_path );
744
 
    free( full_path );
745
 
    return NULL;
746
 
  }
747
 
 
748
 
  dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
749
 
  if( !dvd_file ) {
750
 
    fprintf( stderr, "libdvdnav:DVDOpenFilePath:dvd_file malloc failed\n" );
751
 
    dvdinput_close(dev);
752
 
    free( full_path );
753
 
    return NULL;
754
 
  }
755
 
  dvd_file->dvd = dvd;
756
 
  dvd_file->lb_start = 0;
757
 
  dvd_file->seek_pos = 0;
758
 
  memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
759
 
  memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) );
760
 
  dvd_file->filesize = 0;
761
 
 
762
 
  if( stat( full_path, &fileinfo ) < 0 ) {
763
 
    fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
764
 
    free( full_path );
765
 
    free( dvd_file );
766
 
    dvdinput_close( dev );
767
 
    return NULL;
768
 
  }
769
 
  dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
770
 
  dvd_file->title_devs[ 0 ] = dev;
771
 
  dvd_file->filesize = dvd_file->title_sizes[ 0 ];
772
 
 
773
 
  free( full_path );
774
 
  return dvd_file;
775
 
}
776
 
 
777
 
static dvd_file_t *DVDOpenVOBUDF( dvd_reader_t *dvd, int title, int menu )
778
 
{
779
 
  char filename[ MAX_UDF_FILE_NAME_LEN ];
780
 
  uint32_t start, len;
781
 
  dvd_file_t *dvd_file;
782
 
 
783
 
  if( title == 0 ) {
784
 
    sprintf( filename, "/VIDEO_TS/VIDEO_TS.VOB" );
785
 
  } else {
786
 
    sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, menu ? 0 : 1 );
787
 
  }
788
 
  start = UDFFindFile( dvd, filename, &len );
789
 
  if( start == 0 ) return NULL;
790
 
 
791
 
  dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
792
 
  if( !dvd_file ) return NULL;
793
 
  dvd_file->dvd = dvd;
794
 
  /*Hack*/ dvd_file->css_title = title << 1 | menu;
795
 
  dvd_file->lb_start = start;
796
 
  dvd_file->seek_pos = 0;
797
 
  memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
798
 
  memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) );
799
 
  dvd_file->filesize = len / DVD_VIDEO_LB_LEN;
800
 
 
801
 
  /* Calculate the complete file size for every file in the VOBS */
802
 
  if( !menu ) {
803
 
    int cur;
804
 
 
805
 
    for( cur = 2; cur < 10; cur++ ) {
806
 
      sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, cur );
807
 
      if( !UDFFindFile( dvd, filename, &len ) ) break;
808
 
      dvd_file->filesize += len / DVD_VIDEO_LB_LEN;
809
 
    }
810
 
  }
811
 
 
812
 
  if( dvd->css_state == 1 /* Need key init */ ) {
813
 
    initAllCSSKeys( dvd );
814
 
    dvd->css_state = 2;
815
 
  }
816
 
  /*
817
 
  if( dvdinput_title( dvd_file->dvd->dev, (int)start ) < 0 ) {
818
 
      fprintf( stderr, "libdvdread: Error cracking CSS key for %s\n",
819
 
               filename );
820
 
  }
821
 
  */
822
 
 
823
 
  return dvd_file;
824
 
}
825
 
 
826
 
static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *dvd, int title, int menu )
827
 
{
828
 
  char filename[ MAX_UDF_FILE_NAME_LEN ];
829
 
  char *full_path = NULL;
830
 
  struct stat fileinfo;
831
 
  dvd_file_t *dvd_file;
832
 
  int i;
833
 
 
834
 
  dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
835
 
  if( !dvd_file ) return NULL;
836
 
  dvd_file->dvd = dvd;
837
 
  /*Hack*/ dvd_file->css_title = title << 1 | menu;
838
 
  dvd_file->lb_start = 0;
839
 
  dvd_file->seek_pos = 0;
840
 
  memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
841
 
  memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) );
842
 
  dvd_file->filesize = 0;
843
 
 
844
 
  if( menu ) {
845
 
    dvd_input_t dev;
846
 
 
847
 
    if( title == 0 ) {
848
 
      sprintf( filename, "VIDEO_TS.VOB" );
849
 
    } else {
850
 
      sprintf( filename, "VTS_%02i_0.VOB", title );
851
 
    }
852
 
    if( !findDVDFile( dvd, filename, &full_path ) ) {
853
 
      free( full_path );
854
 
      free( dvd_file );
855
 
      return NULL;
856
 
    }
857
 
 
858
 
    dev = dvdinput_open( full_path );
859
 
    if( dev == NULL ) {
860
 
      free( full_path );
861
 
      free( dvd_file );
862
 
      return NULL;
863
 
    }
864
 
 
865
 
    if( stat( full_path, &fileinfo ) < 0 ) {
866
 
      fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
867
 
      dvdinput_close(dev);
868
 
      free( full_path );
869
 
      free( dvd_file );
870
 
      return NULL;
871
 
    }
872
 
    dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
873
 
    dvd_file->title_devs[ 0 ] = dev;
874
 
    dvdinput_title( dvd_file->title_devs[0], 0);
875
 
    dvd_file->filesize = dvd_file->title_sizes[ 0 ];
876
 
 
877
 
  } else {
878
 
    for( i = 0; i < TITLES_MAX; ++i ) {
879
 
 
880
 
      sprintf( filename, "VTS_%02i_%i.VOB", title, i + 1 );
881
 
      if( !findDVDFile( dvd, filename, &full_path ) ) {
882
 
        break;
883
 
      }
884
 
 
885
 
      if( stat( full_path, &fileinfo ) < 0 ) {
886
 
        fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
887
 
        break;
888
 
      }
889
 
 
890
 
      dvd_file->title_sizes[ i ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
891
 
      dvd_file->title_devs[ i ] = dvdinput_open( full_path );
892
 
      dvdinput_title( dvd_file->title_devs[ i ], 0 );
893
 
      dvd_file->filesize += dvd_file->title_sizes[ i ];
894
 
    }
895
 
    if( !dvd_file->title_devs[ 0 ] ) {
896
 
      free( full_path );
897
 
      free( dvd_file );
898
 
      return NULL;
899
 
    }
900
 
  }
901
 
  free( full_path );
902
 
  return dvd_file;
903
 
}
904
 
 
905
 
dvd_file_t *DVDOpenFile( dvd_reader_t *dvd, int titlenum,
906
 
                         dvd_read_domain_t domain )
907
 
{
908
 
  char filename[ MAX_UDF_FILE_NAME_LEN ];
909
 
 
910
 
  /* Check arguments. */
911
 
  if( dvd == NULL || titlenum < 0 )
912
 
    return NULL;
913
 
 
914
 
  switch( domain ) {
915
 
  case DVD_READ_INFO_FILE:
916
 
    if( titlenum == 0 ) {
917
 
      sprintf( filename, "/VIDEO_TS/VIDEO_TS.IFO" );
918
 
    } else {
919
 
      sprintf( filename, "/VIDEO_TS/VTS_%02i_0.IFO", titlenum );
920
 
    }
921
 
    break;
922
 
  case DVD_READ_INFO_BACKUP_FILE:
923
 
    if( titlenum == 0 ) {
924
 
      sprintf( filename, "/VIDEO_TS/VIDEO_TS.BUP" );
925
 
    } else {
926
 
      sprintf( filename, "/VIDEO_TS/VTS_%02i_0.BUP", titlenum );
927
 
    }
928
 
    break;
929
 
  case DVD_READ_MENU_VOBS:
930
 
    if( dvd->isImageFile ) {
931
 
      return DVDOpenVOBUDF( dvd, titlenum, 1 );
932
 
    } else {
933
 
      return DVDOpenVOBPath( dvd, titlenum, 1 );
934
 
    }
935
 
    break;
936
 
  case DVD_READ_TITLE_VOBS:
937
 
    if( titlenum == 0 ) return 0;
938
 
    if( dvd->isImageFile ) {
939
 
      return DVDOpenVOBUDF( dvd, titlenum, 0 );
940
 
    } else {
941
 
      return DVDOpenVOBPath( dvd, titlenum, 0 );
942
 
    }
943
 
    break;
944
 
  default:
945
 
    fprintf( stderr, "libdvdread: Invalid domain for file open.\n" );
946
 
    return NULL;
947
 
  }
948
 
 
949
 
  if( dvd->isImageFile ) {
950
 
    return DVDOpenFileUDF( dvd, filename );
951
 
  } else {
952
 
    return DVDOpenFilePath( dvd, filename );
953
 
  }
954
 
}
955
 
 
956
 
void DVDCloseFile( dvd_file_t *dvd_file )
957
 
{
958
 
  int i;
959
 
 
960
 
  if( dvd_file ) {
961
 
    if( !dvd_file->dvd->isImageFile ) {
962
 
      for( i = 0; i < TITLES_MAX; ++i ) {
963
 
        if( dvd_file->title_devs[ i ] ) {
964
 
          dvdinput_close( dvd_file->title_devs[i] );
965
 
        }
966
 
      }
967
 
    }
968
 
 
969
 
    free( dvd_file );
970
 
    dvd_file = 0;
971
 
  }
972
 
}
973
 
 
974
 
static int DVDFileStatVOBUDF( dvd_reader_t *dvd, int title,
975
 
                              int menu, dvd_stat_t *statbuf )
976
 
{
977
 
  char filename[ MAX_UDF_FILE_NAME_LEN ];
978
 
  uint32_t size;
979
 
  off_t tot_size;
980
 
  off_t parts_size[ 9 ];
981
 
  int nr_parts = 0;
982
 
  int n;
983
 
 
984
 
  if( title == 0 )
985
 
    sprintf( filename, "/VIDEO_TS/VIDEO_TS.VOB" );
986
 
  else
987
 
    sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, menu ? 0 : 1 );
988
 
 
989
 
  if( !UDFFindFile( dvd, filename, &size ) )
990
 
    return -1;
991
 
 
992
 
  tot_size = size;
993
 
  nr_parts = 1;
994
 
  parts_size[ 0 ] = size;
995
 
 
996
 
  if( !menu ) {
997
 
    int cur;
998
 
 
999
 
    for( cur = 2; cur < 10; cur++ ) {
1000
 
      sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, cur );
1001
 
      if( !UDFFindFile( dvd, filename, &size ) )
1002
 
        break;
1003
 
 
1004
 
      parts_size[ nr_parts ] = size;
1005
 
      tot_size += size;
1006
 
      nr_parts++;
1007
 
    }
1008
 
  }
1009
 
 
1010
 
  statbuf->size = tot_size;
1011
 
  statbuf->nr_parts = nr_parts;
1012
 
  for( n = 0; n < nr_parts; n++ )
1013
 
    statbuf->parts_size[ n ] = parts_size[ n ];
1014
 
 
1015
 
  return 0;
1016
 
}
1017
 
 
1018
 
 
1019
 
static int DVDFileStatVOBPath( dvd_reader_t *dvd, int title,
1020
 
                               int menu, dvd_stat_t *statbuf )
1021
 
{
1022
 
  char filename[ MAX_UDF_FILE_NAME_LEN ];
1023
 
  char *full_path = NULL;
1024
 
  struct stat fileinfo;
1025
 
  off_t tot_size;
1026
 
  off_t parts_size[ 9 ];
1027
 
  int nr_parts = 0;
1028
 
  int n;
1029
 
 
1030
 
  if( title == 0 )
1031
 
    sprintf( filename, "VIDEO_TS.VOB" );
1032
 
  else
1033
 
    sprintf( filename, "VTS_%02d_%d.VOB", title, menu ? 0 : 1 );
1034
 
 
1035
 
  if( !findDVDFile( dvd, filename, &full_path ) ) {
1036
 
    free( full_path );
1037
 
    return -1;
1038
 
  }
1039
 
 
1040
 
  if( stat( full_path, &fileinfo ) < 0 ) {
1041
 
    fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
1042
 
    free( full_path );
1043
 
    return -1;
1044
 
  }
1045
 
 
1046
 
  tot_size = fileinfo.st_size;
1047
 
  nr_parts = 1;
1048
 
  parts_size[ 0 ] = fileinfo.st_size;
1049
 
 
1050
 
  if( !menu ) {
1051
 
    int cur;
1052
 
    for( cur = 2; cur < 10; cur++ ) {
1053
 
      sprintf( filename, "VTS_%02d_%d.VOB", title, cur );
1054
 
      if( !findDVDFile( dvd, filename, &full_path ) )
1055
 
        break;
1056
 
 
1057
 
      if( stat( full_path, &fileinfo ) < 0 ) {
1058
 
        fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
1059
 
        break;
1060
 
      }
1061
 
 
1062
 
      parts_size[ nr_parts ] = fileinfo.st_size;
1063
 
      tot_size += parts_size[ nr_parts ];
1064
 
      nr_parts++;
1065
 
    }
1066
 
  }
1067
 
 
1068
 
  statbuf->size = tot_size;
1069
 
  statbuf->nr_parts = nr_parts;
1070
 
  for( n = 0; n < nr_parts; n++ )
1071
 
    statbuf->parts_size[ n ] = parts_size[ n ];
1072
 
 
1073
 
  free( full_path );
1074
 
  return 0;
1075
 
}
1076
 
 
1077
 
 
1078
 
int DVDFileStat( dvd_reader_t *dvd, int titlenum,
1079
 
                 dvd_read_domain_t domain, dvd_stat_t *statbuf )
1080
 
{
1081
 
  char filename[ MAX_UDF_FILE_NAME_LEN ];
1082
 
  char *full_path = NULL;
1083
 
  struct stat fileinfo;
1084
 
  uint32_t size;
1085
 
 
1086
 
  /* Check arguments. */
1087
 
  if( dvd == NULL || titlenum < 0 ) {
1088
 
    errno = EINVAL;
1089
 
    return -1;
1090
 
  }
1091
 
 
1092
 
  switch( domain ) {
1093
 
  case DVD_READ_INFO_FILE:
1094
 
    if( titlenum == 0 )
1095
 
      sprintf( filename, "/VIDEO_TS/VIDEO_TS.IFO" );
1096
 
    else
1097
 
      sprintf( filename, "/VIDEO_TS/VTS_%02i_0.IFO", titlenum );
1098
 
 
1099
 
    break;
1100
 
  case DVD_READ_INFO_BACKUP_FILE:
1101
 
    if( titlenum == 0 )
1102
 
      sprintf( filename, "/VIDEO_TS/VIDEO_TS.BUP" );
1103
 
    else
1104
 
      sprintf( filename, "/VIDEO_TS/VTS_%02i_0.BUP", titlenum );
1105
 
 
1106
 
    break;
1107
 
  case DVD_READ_MENU_VOBS:
1108
 
    if( dvd->isImageFile )
1109
 
      return DVDFileStatVOBUDF( dvd, titlenum, 1, statbuf );
1110
 
    else
1111
 
      return DVDFileStatVOBPath( dvd, titlenum, 1, statbuf );
1112
 
 
1113
 
    break;
1114
 
  case DVD_READ_TITLE_VOBS:
1115
 
    if( titlenum == 0 )
1116
 
      return -1;
1117
 
 
1118
 
    if( dvd->isImageFile )
1119
 
      return DVDFileStatVOBUDF( dvd, titlenum, 0, statbuf );
1120
 
    else
1121
 
      return DVDFileStatVOBPath( dvd, titlenum, 0, statbuf );
1122
 
 
1123
 
    break;
1124
 
  default:
1125
 
    fprintf( stderr, "libdvdread: Invalid domain for file stat.\n" );
1126
 
    errno = EINVAL;
1127
 
    return -1;
1128
 
  }
1129
 
 
1130
 
  if( dvd->isImageFile ) {
1131
 
    if( UDFFindFile( dvd, filename, &size ) ) {
1132
 
      statbuf->size = size;
1133
 
      statbuf->nr_parts = 1;
1134
 
      statbuf->parts_size[ 0 ] = size;
1135
 
      return 0;
1136
 
    }
1137
 
  } else {
1138
 
    if( findDVDFile( dvd, filename, &full_path ) ) {
1139
 
      if( stat( full_path, &fileinfo ) < 0 )
1140
 
        fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
1141
 
      else {
1142
 
        statbuf->size = fileinfo.st_size;
1143
 
        statbuf->nr_parts = 1;
1144
 
        statbuf->parts_size[ 0 ] = statbuf->size;
1145
 
        free( full_path );
1146
 
        return 0;
1147
 
      }
1148
 
    }
1149
 
  }
1150
 
  free( full_path );
1151
 
  return -1;
1152
 
}
1153
 
 
1154
 
/* Internal, but used from dvd_udf.c */
1155
 
int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number,
1156
 
                      size_t block_count, unsigned char *data,
1157
 
                      int encrypted )
1158
 
{
1159
 
  int ret;
1160
 
 
1161
 
  if( !device->dev ) {
1162
 
    fprintf( stderr, "libdvdread: Fatal error in block read.\n" );
1163
 
    return 0;
1164
 
  }
1165
 
 
1166
 
  ret = dvdinput_seek( device->dev, (int) lb_number );
1167
 
  if( ret != (int) lb_number ) {
1168
 
    fprintf( stderr, "libdvdread: Can't seek to block %u\n", lb_number );
1169
 
    return 0;
1170
 
  }
1171
 
 
1172
 
  ret = dvdinput_read( device->dev, (char *) data,
1173
 
                       (int) block_count, encrypted );
1174
 
  return ret;
1175
 
}
1176
 
 
1177
 
/* This is using a single input and starting from 'dvd_file->lb_start' offset.
1178
 
 *
1179
 
 * Reads 'block_count' blocks from 'dvd_file' at block offset 'offset'
1180
 
 * into the buffer located at 'data' and if 'encrypted' is set
1181
 
 * descramble the data if it's encrypted.  Returning either an
1182
 
 * negative error or the number of blocks read. */
1183
 
static int DVDReadBlocksUDF( dvd_file_t *dvd_file, uint32_t offset,
1184
 
                             size_t block_count, unsigned char *data,
1185
 
                             int encrypted )
1186
 
{
1187
 
  return UDFReadBlocksRaw( dvd_file->dvd, dvd_file->lb_start + offset,
1188
 
                           block_count, data, encrypted );
1189
 
}
1190
 
 
1191
 
/* This is using possibly several inputs and starting from an offset of '0'.
1192
 
 *
1193
 
 * Reads 'block_count' blocks from 'dvd_file' at block offset 'offset'
1194
 
 * into the buffer located at 'data' and if 'encrypted' is set
1195
 
 * descramble the data if it's encrypted.  Returning either an
1196
 
 * negative error or the number of blocks read. */
1197
 
static int DVDReadBlocksPath( dvd_file_t *dvd_file, unsigned int offset,
1198
 
                              size_t block_count, unsigned char *data,
1199
 
                              int encrypted )
1200
 
{
1201
 
  int i;
1202
 
  int ret, ret2, off;
1203
 
 
1204
 
  ret = 0;
1205
 
  ret2 = 0;
1206
 
  for( i = 0; i < TITLES_MAX; ++i ) {
1207
 
    if( !dvd_file->title_sizes[ i ] ) return 0; /* Past end of file */
1208
 
 
1209
 
    if( offset < dvd_file->title_sizes[ i ] ) {
1210
 
      if( ( offset + block_count ) <= dvd_file->title_sizes[ i ] ) {
1211
 
        off = dvdinput_seek( dvd_file->title_devs[ i ], (int)offset );
1212
 
        if( off < 0 || off != (int)offset ) {
1213
 
          fprintf( stderr, "libdvdread: Can't seek to block %d\n",
1214
 
                   offset );
1215
 
          return off < 0 ? off : 0;
1216
 
        }
1217
 
        ret = dvdinput_read( dvd_file->title_devs[ i ], data,
1218
 
                             (int)block_count, encrypted );
1219
 
        break;
1220
 
      } else {
1221
 
        size_t part1_size = dvd_file->title_sizes[ i ] - offset;
1222
 
        /* FIXME: Really needs to be a while loop.
1223
 
         * (This is only true if you try and read >1GB at a time) */
1224
 
 
1225
 
        /* Read part 1 */
1226
 
        off = dvdinput_seek( dvd_file->title_devs[ i ], (int)offset );
1227
 
        if( off < 0 || off != (int)offset ) {
1228
 
          fprintf( stderr, "libdvdread: Can't seek to block %d\n",
1229
 
                   offset );
1230
 
          return off < 0 ? off : 0;
1231
 
        }
1232
 
        ret = dvdinput_read( dvd_file->title_devs[ i ], data,
1233
 
                             (int)part1_size, encrypted );
1234
 
        if( ret < 0 ) return ret;
1235
 
        /* FIXME: This is wrong if i is the last file in the set.
1236
 
         * also error from this read will not show in ret. */
1237
 
 
1238
 
        /* Does the next part exist? If not then return now. */
1239
 
        if( i + 1 >= TITLES_MAX || !dvd_file->title_devs[ i + 1 ] )
1240
 
          return ret;
1241
 
 
1242
 
        /* Read part 2 */
1243
 
        off = dvdinput_seek( dvd_file->title_devs[ i + 1 ], 0 );
1244
 
        if( off < 0 || off != 0 ) {
1245
 
          fprintf( stderr, "libdvdread: Can't seek to block %d\n",
1246
 
                   0 );
1247
 
          return off < 0 ? off : 0;
1248
 
        }
1249
 
        ret2 = dvdinput_read( dvd_file->title_devs[ i + 1 ],
1250
 
                              data + ( part1_size
1251
 
                                       * (int64_t)DVD_VIDEO_LB_LEN ),
1252
 
                              (int)(block_count - part1_size),
1253
 
                              encrypted );
1254
 
        if( ret2 < 0 ) return ret2;
1255
 
        break;
1256
 
      }
1257
 
    } else {
1258
 
      offset -= dvd_file->title_sizes[ i ];
1259
 
    }
1260
 
  }
1261
 
 
1262
 
  return ret + ret2;
1263
 
}
1264
 
 
1265
 
/* This is broken reading more than 2Gb at a time is ssize_t is 32-bit. */
1266
 
ssize_t DVDReadBlocks( dvd_file_t *dvd_file, int offset,
1267
 
                       size_t block_count, unsigned char *data )
1268
 
{
1269
 
  int ret;
1270
 
 
1271
 
  /* Check arguments. */
1272
 
  if( dvd_file == NULL || offset < 0 || data == NULL )
1273
 
    return -1;
1274
 
 
1275
 
  /* Hack, and it will still fail for multiple opens in a threaded app ! */
1276
 
  if( dvd_file->dvd->css_title != dvd_file->css_title ) {
1277
 
    dvd_file->dvd->css_title = dvd_file->css_title;
1278
 
    if( dvd_file->dvd->isImageFile ) {
1279
 
      dvdinput_title( dvd_file->dvd->dev, (int)dvd_file->lb_start );
1280
 
    }
1281
 
    /* Here each vobu has it's own dvdcss handle, so no need to update
1282
 
    else {
1283
 
      dvdinput_title( dvd_file->title_devs[ 0 ], (int)dvd_file->lb_start );
1284
 
    }*/
1285
 
  }
1286
 
 
1287
 
  if( dvd_file->dvd->isImageFile ) {
1288
 
    ret = DVDReadBlocksUDF( dvd_file, (uint32_t)offset,
1289
 
                            block_count, data, DVDINPUT_READ_DECRYPT );
1290
 
  } else {
1291
 
    ret = DVDReadBlocksPath( dvd_file, (unsigned int)offset,
1292
 
                             block_count, data, DVDINPUT_READ_DECRYPT );
1293
 
  }
1294
 
 
1295
 
  return (ssize_t)ret;
1296
 
}
1297
 
 
1298
 
int32_t DVDFileSeek( dvd_file_t *dvd_file, int32_t offset )
1299
 
{
1300
 
  /* Check arguments. */
1301
 
  if( dvd_file == NULL || offset < 0 )
1302
 
    return -1;
1303
 
 
1304
 
  if( offset > dvd_file->filesize * DVD_VIDEO_LB_LEN ) {
1305
 
    return -1;
1306
 
  }
1307
 
  dvd_file->seek_pos = (uint32_t) offset;
1308
 
  return offset;
1309
 
}
1310
 
 
1311
 
int DVDFileSeekForce(dvd_file_t *dvd_file, int offset, int force_size)
1312
 
{
1313
 
  /* Check arguments. */
1314
 
  if( dvd_file == NULL || offset <= 0 )
1315
 
      return -1;
1316
 
 
1317
 
  if( dvd_file->dvd->isImageFile ) {
1318
 
    if( force_size < 0 )
1319
 
      force_size = (offset - 1) / DVD_VIDEO_LB_LEN + 1;
1320
 
    if( dvd_file->filesize < force_size ) {
1321
 
      dvd_file->filesize = force_size;
1322
 
      fprintf(stderr, "libdvdread: Ignored size of file indicated in UDF.\n");
1323
 
    }
1324
 
  }
1325
 
 
1326
 
  if( offset > dvd_file->filesize * DVD_VIDEO_LB_LEN )
1327
 
    return -1;
1328
 
 
1329
 
  dvd_file->seek_pos = (uint32_t) offset;
1330
 
  return offset;
1331
 
}
1332
 
 
1333
 
ssize_t DVDReadBytes( dvd_file_t *dvd_file, void *data, size_t byte_size )
1334
 
{
1335
 
  unsigned char *secbuf_base, *secbuf;
1336
 
  unsigned int numsec, seek_sector, seek_byte;
1337
 
  int ret;
1338
 
 
1339
 
  /* Check arguments. */
1340
 
  if( dvd_file == NULL || data == NULL )
1341
 
    return -1;
1342
 
 
1343
 
  seek_sector = dvd_file->seek_pos / DVD_VIDEO_LB_LEN;
1344
 
  seek_byte   = dvd_file->seek_pos % DVD_VIDEO_LB_LEN;
1345
 
 
1346
 
  numsec = ( ( seek_byte + byte_size ) / DVD_VIDEO_LB_LEN ) +
1347
 
    ( ( ( seek_byte + byte_size ) % DVD_VIDEO_LB_LEN ) ? 1 : 0 );
1348
 
 
1349
 
  secbuf_base = (unsigned char *) malloc( numsec * DVD_VIDEO_LB_LEN + 2048 );
1350
 
  secbuf = (unsigned char *)(((uintptr_t)secbuf_base & ~((uintptr_t)2047)) + 2048);
1351
 
  if( !secbuf_base ) {
1352
 
    fprintf( stderr, "libdvdread: Can't allocate memory "
1353
 
             "for file read!\n" );
1354
 
    return 0;
1355
 
  }
1356
 
 
1357
 
  if( dvd_file->dvd->isImageFile ) {
1358
 
    ret = DVDReadBlocksUDF( dvd_file, (uint32_t) seek_sector,
1359
 
                            (size_t) numsec, secbuf, DVDINPUT_NOFLAGS );
1360
 
  } else {
1361
 
    ret = DVDReadBlocksPath( dvd_file, seek_sector,
1362
 
                             (size_t) numsec, secbuf, DVDINPUT_NOFLAGS );
1363
 
  }
1364
 
 
1365
 
  if( ret != (int) numsec ) {
1366
 
    free( secbuf_base );
1367
 
    return ret < 0 ? ret : 0;
1368
 
  }
1369
 
 
1370
 
  memcpy( data, &(secbuf[ seek_byte ]), byte_size );
1371
 
  free( secbuf_base );
1372
 
 
1373
 
  DVDFileSeekForce(dvd_file, dvd_file->seek_pos + byte_size, -1);
1374
 
  return byte_size;
1375
 
}
1376
 
 
1377
 
ssize_t DVDFileSize( dvd_file_t *dvd_file )
1378
 
{
1379
 
  /* Check arguments. */
1380
 
  if( dvd_file == NULL )
1381
 
    return -1;
1382
 
 
1383
 
  return dvd_file->filesize;
1384
 
}
1385
 
 
1386
 
int DVDDiscID( dvd_reader_t *dvd, unsigned char *discid )
1387
 
{
1388
 
  struct md5_ctx ctx;
1389
 
  int title;
1390
 
  int nr_of_files = 0;
1391
 
 
1392
 
  /* Check arguments. */
1393
 
  if( dvd == NULL || discid == NULL )
1394
 
    return 0;
1395
 
 
1396
 
  /* Go through the first 10 IFO:s, in order,
1397
 
   * and md5sum them, i.e  VIDEO_TS.IFO and VTS_0?_0.IFO */
1398
 
  md5_init_ctx( &ctx );
1399
 
  for( title = 0; title < 10; title++ ) {
1400
 
    dvd_file_t *dvd_file = DVDOpenFile( dvd, title, DVD_READ_INFO_FILE );
1401
 
    if( dvd_file != NULL ) {
1402
 
      ssize_t bytes_read;
1403
 
      size_t file_size = dvd_file->filesize * DVD_VIDEO_LB_LEN;
1404
 
      char *buffer_base = malloc( file_size + 2048 );
1405
 
      char *buffer = (char *)(((uintptr_t)buffer_base & ~((uintptr_t)2047)) + 2048);
1406
 
 
1407
 
      if( buffer_base == NULL ) {
1408
 
          DVDCloseFile( dvd_file );
1409
 
          fprintf( stderr, "libdvdread: DVDDiscId, failed to "
1410
 
                   "allocate memory for file read!\n" );
1411
 
          return -1;
1412
 
      }
1413
 
 
1414
 
      bytes_read = DVDReadBytes( dvd_file, buffer, file_size );
1415
 
      if( bytes_read != file_size ) {
1416
 
          fprintf( stderr, "libdvdread: DVDDiscId read returned %zd bytes"
1417
 
                   ", wanted %zd\n", bytes_read, file_size );
1418
 
          DVDCloseFile( dvd_file );
1419
 
          free( buffer_base );
1420
 
          return -1;
1421
 
      }
1422
 
 
1423
 
      md5_process_bytes( buffer, file_size,  &ctx );
1424
 
 
1425
 
      DVDCloseFile( dvd_file );
1426
 
      free( buffer_base );
1427
 
      nr_of_files++;
1428
 
    }
1429
 
  }
1430
 
  md5_finish_ctx( &ctx, discid );
1431
 
  if(!nr_of_files)
1432
 
    return -1;
1433
 
 
1434
 
  return 0;
1435
 
}
1436
 
 
1437
 
 
1438
 
int DVDISOVolumeInfo( dvd_reader_t *dvd,
1439
 
                      char *volid, unsigned int volid_size,
1440
 
                      unsigned char *volsetid, unsigned int volsetid_size )
1441
 
{
1442
 
  unsigned char *buffer, *buffer_base;
1443
 
  int ret;
1444
 
 
1445
 
  /* Check arguments. */
1446
 
  if( dvd == NULL )
1447
 
    return 0;
1448
 
 
1449
 
  if( dvd->dev == NULL ) {
1450
 
    /* No block access, so no ISO... */
1451
 
    return -1;
1452
 
  }
1453
 
 
1454
 
  buffer_base = malloc( DVD_VIDEO_LB_LEN + 2048 );
1455
 
  buffer = (unsigned char *)(((uintptr_t)buffer_base & ~((uintptr_t)2047)) + 2048);
1456
 
 
1457
 
  if( buffer_base == NULL ) {
1458
 
    fprintf( stderr, "libdvdread: DVDISOVolumeInfo, failed to "
1459
 
             "allocate memory for file read!\n" );
1460
 
    return -1;
1461
 
  }
1462
 
 
1463
 
  ret = UDFReadBlocksRaw( dvd, 16, 1, buffer, 0 );
1464
 
  if( ret != 1 ) {
1465
 
    fprintf( stderr, "libdvdread: DVDISOVolumeInfo, failed to "
1466
 
             "read ISO9660 Primary Volume Descriptor!\n" );
1467
 
    free( buffer_base );
1468
 
    return -1;
1469
 
  }
1470
 
 
1471
 
  if( (volid != NULL) && (volid_size > 0) ) {
1472
 
    unsigned int n;
1473
 
    for(n = 0; n < 32; n++) {
1474
 
      if(buffer[40+n] == 0x20) {
1475
 
        break;
1476
 
      }
1477
 
    }
1478
 
 
1479
 
    if(volid_size > n+1) {
1480
 
      volid_size = n+1;
1481
 
    }
1482
 
 
1483
 
    memcpy(volid, &buffer[40], volid_size-1);
1484
 
    volid[volid_size-1] = '\0';
1485
 
  }
1486
 
 
1487
 
  if( (volsetid != NULL) && (volsetid_size > 0) ) {
1488
 
    if(volsetid_size > 128) {
1489
 
      volsetid_size = 128;
1490
 
    }
1491
 
    memcpy(volsetid, &buffer[190], volsetid_size);
1492
 
  }
1493
 
  free( buffer_base );
1494
 
  return 0;
1495
 
}
1496
 
 
1497
 
 
1498
 
int DVDUDFVolumeInfo( dvd_reader_t *dvd,
1499
 
                      char *volid, unsigned int volid_size,
1500
 
                      unsigned char *volsetid, unsigned int volsetid_size )
1501
 
{
1502
 
  int ret;
1503
 
  /* Check arguments. */
1504
 
  if( dvd == NULL )
1505
 
    return -1;
1506
 
 
1507
 
  if( dvd->dev == NULL ) {
1508
 
    /* No block access, so no UDF VolumeSet Identifier */
1509
 
    return -1;
1510
 
  }
1511
 
 
1512
 
  if( (volid != NULL) && (volid_size > 0) ) {
1513
 
    ret = UDFGetVolumeIdentifier(dvd, volid, volid_size);
1514
 
    if(!ret) {
1515
 
      return -1;
1516
 
    }
1517
 
  }
1518
 
  if( (volsetid != NULL) && (volsetid_size > 0) ) {
1519
 
    ret =  UDFGetVolumeSetIdentifier(dvd, volsetid, volsetid_size);
1520
 
    if(!ret) {
1521
 
      return -1;
1522
 
    }
1523
 
  }
1524
 
 
1525
 
  return 0;
1526
 
}