* modules/access/vcd/*, configure.ac.in:
authorGildas Bazin <gbazin@videolan.org>
Tue, 15 Oct 2002 19:56:59 +0000 (19:56 +0000)
committerGildas Bazin <gbazin@videolan.org>
Tue, 15 Oct 2002 19:56:59 +0000 (19:56 +0000)
   - Major changes to allow reading vcd images directly from the hard drive
      (you need a .cue and .bin file).
   - Removed duplicated code by merging ioctl_GetTrackCount and ioctl_GetSectors.
   - Implemented necessary ioctls for Win9x/NT/2K/XP.

configure.ac.in
modules/access/vcd/cdrom.c
modules/access/vcd/cdrom.h
modules/access/vcd/vcd.c
modules/access/vcd/vcd.h

index 4b18581..52aab21 100644 (file)
@@ -305,7 +305,7 @@ AC_EGREP_HEADER(strncasecmp,strings.h,[
 
 dnl Check for headers
 AC_CHECK_HEADERS(stdint.h getopt.h strings.h inttypes.h sys/int_types.h)
-AC_CHECK_HEADERS(sys/sockio.h fcntl.h sys/types.h sys/time.h sys/times.h)
+AC_CHECK_HEADERS(sys/sockio.h fcntl.h sys/types.h sys/time.h sys/times.h sys/ioctl.h)
 AC_CHECK_HEADERS(dlfcn.h image.h)
 AC_CHECK_HEADERS(arpa/inet.h net/if.h netinet/in.h sys/socket.h)
 AC_CHECK_HEADERS(machine/param.h sys/shm.h)
@@ -965,7 +965,7 @@ dnl
 dnl  VCD module
 dnl
 AC_ARG_ENABLE(vcd,
-  [  --enable-vcd            VCD support for Linux, FreeBSD and MacOS X (default enabled)])
+  [  --enable-vcd            VCD support for Linux, FreeBSD, MacOS X and Win32 (default enabled)])
 
 if test "x${enable_vcd}" != "xno"
 then
@@ -978,7 +978,7 @@ then
     AC_DEFINE(HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H, 1, For FreeBSD VCD support)
   ])
 
-  if test "x${SYS}" = "xbsdi"
+  if test "x${SYS}" = "xbsdi" -o "x${SYS}" = "xmingw32"
   then
     PLUGINS="${PLUGINS} vcd"
   fi
index 135ca2b..b6cf06a 100644 (file)
@@ -2,10 +2,11 @@
  * cdrom.c: cdrom tools
  *****************************************************************************
  * Copyright (C) 1998-2001 VideoLAN
- * $Id: cdrom.c,v 1.3 2002/08/09 23:47:22 massiot Exp $
+ * $Id: cdrom.c,v 1.4 2002/10/15 19:56:59 gbazin Exp $
  *
- * Author: Johan Bilien <jobi@via.ecp.fr>
- *         Jon Lech Johansen <jon-vl@nanocrew.net>
+ * Authors: Johan Bilien <jobi@via.ecp.fr>
+ *          Gildas Bazin <gbazin@netcourrier.com>
+ *          Jon Lech Johansen <jon-vl@nanocrew.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -39,7 +40,9 @@
 #include <string.h>
 #include <errno.h>
 
-#include <sys/ioctl.h>
+#ifdef HAVE_SYS_IOCTL_H
+#   include <sys/ioctl.h>
+#endif
 
 #if defined( SYS_BSDI )
 #   include <dvd.h>
 #elif defined( HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H )
 #   include <sys/cdio.h>
 #   include <sys/cdrio.h>
+#elif defined( WIN32 )
+#   include <windows.h>
+#   include <winioctl.h>
 #else
 #   include <linux/cdrom.h>
 #endif
 
 #include "cdrom.h"
+#include "vcd.h"
 
 /*****************************************************************************
- * Platform specific 
+ * ioctl_Open: Opens a VCD device or file and returns an opaque handle
  *****************************************************************************/
-#if defined( SYS_DARWIN )
-CDTOC *getTOC( vlc_object_t *, const char * );
-#define freeTOC( p ) free( (void*)p )
-int getNumberOfDescriptors( CDTOC * );
-int getNumberOfTracks( CDTOC *, int );
-#define CD_MIN_TRACK_NO 01
-#define CD_MAX_TRACK_NO 99
+vcddev_t *ioctl_Open( vlc_object_t *p_this, const char *psz_dev )
+{
+    int i_ret;
+    int b_is_file;
+    vcddev_t *p_vcddev;
+#ifndef WIN32
+    struct stat fileinfo;
 #endif
 
-/*****************************************************************************
- * ioctl_ReadTocHeader: Read the TOC header and return the track number.
- *****************************************************************************/
-int ioctl_GetTrackCount( vlc_object_t * p_this, int i_fd, const char *psz_dev )
-{
-    int i_count = -1;
+    if( !psz_dev ) return NULL;
 
-#if defined( SYS_DARWIN )
-    CDTOC *pTOC;
-    int i_descriptors;
-
-    if( ( pTOC = getTOC( p_this, psz_dev ) ) == NULL )
+    /*
+     *  Initialize structure with default values
+     */
+    p_vcddev = (vcddev_t *)malloc( sizeof(vcddev_t) );
+    if( p_vcddev == NULL )
     {
-        msg_Err( p_this, "failed to get the TOC" );
-        return( -1 );
+        msg_Err( p_this, "out of memory" );
+        return NULL;
+    }
+    p_vcddev->i_vcdimage_handle = -1;
+    p_vcddev->psz_dev = NULL;
+    b_is_file = 1;
+
+    /*
+     *  Check if we are dealing with a device or a file (vcd image)
+     */
+#ifdef WIN32
+    if( strlen( psz_dev ) == 1 ||
+        (strlen( psz_dev ) == 2 && psz_dev[1] == ':') )
+    {
+        b_is_file = 0;
     }
 
-    i_descriptors = getNumberOfDescriptors( pTOC );
-    i_count = getNumberOfTracks( pTOC, i_descriptors );
+#else
+    if( stat( psz_dev, &fileinfo ) < 0 )
+    {
+        free( p_vcddev );
+        return NULL;
+    }
 
-    freeTOC( pTOC );
+    /* Check if this is a block/char device */
+    if( S_ISBLK( fileinfo.st_mode ) || S_ISCHR( fileinfo.st_mode ) )
+        b_is_file = 0;
+#endif
 
-#elif defined( HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H )
-    struct ioc_toc_header tochdr;
-    
-    if( ioctl( i_fd, CDIOREADTOCHEADER, &tochdr ) == -1 )
+    if( b_is_file )
     {
-        msg_Err( p_this, "could not read TOCHDR" );
-        return -1;
+        i_ret = OpenVCDImage( p_this, psz_dev, p_vcddev );
     }
+    else
+    {
+        /*
+         *  open the vcd device
+         */
 
-    i_count = tochdr.ending_track - tochdr.starting_track + 1;
-    
+#ifdef WIN32
+        i_ret = win32_vcd_open( p_this, psz_dev, p_vcddev );
 #else
-    struct cdrom_tochdr   tochdr;
+        p_vcddev->i_device_handle = -1;
+        p_vcddev->i_device_handle = open( psz_dev, O_RDONLY | O_NONBLOCK );
+        i_ret = (p_vcddev->i_device_handle == -1) ? -1 : 0;
+#endif
+    }
 
-    /* First we read the TOC header */
-    if( ioctl( i_fd, CDROMREADTOCHDR, &tochdr ) == -1 )
+    if( i_ret == 0 )
     {
-        msg_Err( p_this, "could not read TOCHDR" );
-        return -1;
+        p_vcddev->psz_dev = (char *)strdup( psz_dev );
+    }
+    else
+    {
+        free( p_vcddev );
+        p_vcddev = NULL;
     }
 
-    i_count = tochdr.cdth_trk1 - tochdr.cdth_trk0 + 1;
-#endif
-
-    return( i_count );
+    return p_vcddev;
 }
 
 /*****************************************************************************
- * ioctl_GetSectors: Read the Table of Contents and fill p_vcd.
+ * ioctl_Close: Closes an already opened VCD device or file.
  *****************************************************************************/
-int * ioctl_GetSectors( vlc_object_t *p_this, int i_fd, const char *psz_dev )
+void ioctl_Close( vlc_object_t * p_this, vcddev_t *p_vcddev )
 {
-    int i, i_tracks;
-    int *p_sectors = NULL;
-
-#if defined( SYS_DARWIN )
-    CDTOC *pTOC;
-    u_char track;
-    int i_descriptors;
-    int i_leadout = -1;
-    CDTOCDescriptor *pTrackDescriptors;
+    if( p_vcddev->psz_dev ) free( p_vcddev->psz_dev );
 
-    if( ( pTOC = getTOC( p_this, psz_dev ) ) == NULL )
+    if( p_vcddev->i_vcdimage_handle != -1 )
     {
-        msg_Err( p_this, "failed to get the TOC" );
-        return( NULL );
+        /*
+         *  vcd image mode
+         */
+
+        CloseVCDImage( p_this, p_vcddev );
+        return;
     }
 
-    i_descriptors = getNumberOfDescriptors( pTOC );
-    i_tracks = getNumberOfTracks( pTOC, i_descriptors );
+    /*
+     *  vcd device mode
+     */
 
-    p_sectors = malloc( (i_tracks + 1) * sizeof(int) );
-    if( p_sectors == NULL )
-    {
-        msg_Err( p_this, "out of memory" );
-        freeTOC( pTOC );
-        return NULL;
-    }
-    
-    pTrackDescriptors = pTOC->descriptors;
+#ifdef WIN32
+    if( p_vcddev->h_device_handle )
+        CloseHandle( p_vcddev->h_device_handle );
+    if( p_vcddev->hASPI )
+        FreeLibrary( (HMODULE)p_vcddev->hASPI );
+#else
+    if( p_vcddev->i_device_handle != -1 )
+        close( p_vcddev->i_device_handle );
+#endif
+}
 
-    for( i_tracks = 0, i = 0; i <= i_descriptors; i++ )
+/*****************************************************************************
+ * ioctl_GetTracksMap: Read the Table of Content, fill in the pp_sectors map
+ *                     if pp_sectors is not null and return the number of
+ *                     tracks available.
+ *****************************************************************************/
+int ioctl_GetTracksMap( vlc_object_t *p_this, const vcddev_t *p_vcddev,
+                        int **pp_sectors )
+{
+    int i_tracks = 0;
+
+    if( p_vcddev->i_vcdimage_handle != -1 )
     {
-        track = pTrackDescriptors[i].point;
+        /*
+         *  vcd image mode
+         */
 
-        if( track == 0xA2 )
-            i_leadout = i;
+        i_tracks = p_vcddev->i_tracks;
 
-        if( track > CD_MAX_TRACK_NO || track < CD_MIN_TRACK_NO )
-            continue;
+        if( pp_sectors )
+        {
+            *pp_sectors = malloc( (i_tracks + 1) * sizeof(int) );
+            if( *pp_sectors == NULL )
+            {
+                msg_Err( p_this, "out of memory" );
+                return 0;
+            }
+            memcpy( *pp_sectors, p_vcddev->p_sectors,
+                    (i_tracks + 1) * sizeof(int) );
+        }
 
-        p_sectors[i_tracks++] = 
-            CDConvertMSFToLBA( pTrackDescriptors[i].p );
+        return i_tracks;
     }
-
-    if( i_leadout == -1 )
+    else
     {
-        msg_Err( p_this, "leadout not found" );
-        free( p_sectors );
-        freeTOC( pTOC );
-        return( NULL );
-    } 
 
-    /* set leadout sector */
-    p_sectors[i_tracks] = 
-        CDConvertMSFToLBA( pTrackDescriptors[i_leadout].p ); 
+        /*
+         *  vcd device mode
+         */
 
-    freeTOC( pTOC );
+#if defined( SYS_DARWIN )
+
+        CDTOC *pTOC;
+        int i_descriptors;
+
+        if( ( pTOC = darwin_getTOC( p_this, p_vcddev->psz_dev ) ) == NULL )
+        {
+            msg_Err( p_this, "failed to get the TOC" );
+            return 0;
+        }
+
+        i_descriptors = darwin_getNumberOfDescriptors( pTOC );
+        i_tracks = darwin_getNumberOfTracks( pTOC, i_descriptors );
+
+        if( pp_sectors )
+        {
+            int i, i_leadout = -1;
+            CDTOCDescriptor *pTrackDescriptors;
+            u_char track;
+
+            *pp_sectors = malloc( (i_tracks + 1) * sizeof(int) );
+            if( *pp_sectors == NULL )
+            {
+                msg_Err( p_this, "out of memory" );
+                darwin_freeTOC( pTOC );
+                return 0;
+            }
+
+            pTrackDescriptors = pTOC->descriptors;
+
+            for( i_tracks = 0, i = 0; i <= i_descriptors; i++ )
+            {
+                track = pTrackDescriptors[i].point;
+
+                if( track == 0xA2 )
+                    i_leadout = i;
+
+                if( track > CD_MAX_TRACK_NO || track < CD_MIN_TRACK_NO )
+                    continue;
+
+                (*pp_sectors)[i_tracks++] = 
+                    CDConvertMSFToLBA( pTrackDescriptors[i].p );
+            }
+
+            if( i_leadout == -1 )
+            {
+                msg_Err( p_this, "leadout not found" );
+                free( *pp_sectors );
+                darwin_freeTOC( pTOC );
+                return 0;
+            }
+
+            /* set leadout sector */
+            (*pp_sectors)[i_tracks] = 
+                CDConvertMSFToLBA( pTrackDescriptors[i_leadout].p );
+        }
+
+        darwin_freeTOC( pTOC );
+
+#elif defined( WIN32 )
+        if( p_vcddev->hASPI )
+        {
+            HANDLE hEvent;
+            struct SRB_ExecSCSICmd ssc;
+            byte_t p_tocheader[ 4 ];
+
+            /* Create the transfer completion event */
+            hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+            if( hEvent == NULL )
+            {
+                return -1;
+            }
+
+            memset( &ssc, 0, sizeof( ssc ) );
+
+            ssc.SRB_Cmd         = SC_EXEC_SCSI_CMD;
+            ssc.SRB_Flags       = SRB_DIR_IN | SRB_EVENT_NOTIFY;
+            ssc.SRB_HaId        = LOBYTE( p_vcddev->i_sid );
+            ssc.SRB_Target      = HIBYTE( p_vcddev->i_sid );
+            ssc.SRB_SenseLen    = SENSE_LEN;
+
+            ssc.SRB_PostProc = (LPVOID) hEvent;
+            ssc.SRB_CDBLen      = 10;
+
+            /* Operation code */
+            ssc.CDBByte[ 0 ] = READ_TOC;
+
+            /* Format */
+            ssc.CDBByte[ 2 ] = READ_TOC_FORMAT_TOC;
+
+            /* Starting track */
+            ssc.CDBByte[ 6 ] = 0;
+
+            /* Allocation length and buffer */
+            ssc.SRB_BufLen = sizeof( p_tocheader );
+            ssc.SRB_BufPointer  = p_tocheader;
+            ssc.CDBByte[ 7 ] = ( ssc.SRB_BufLen >>  8 ) & 0xff;
+            ssc.CDBByte[ 8 ] = ( ssc.SRB_BufLen       ) & 0xff;
+
+            /* Initiate transfer */
+            ResetEvent( hEvent );
+            p_vcddev->lpSendCommand( (void*) &ssc );
+
+            /* If the command has still not been processed, wait until it's
+             * finished */
+            if( ssc.SRB_Status == SS_PENDING )
+                WaitForSingleObject( hEvent, INFINITE );
+
+            /* check that the transfer went as planned */
+            if( ssc.SRB_Status != SS_COMP )
+            {
+                CloseHandle( hEvent );
+                return 0;
+            }
+
+            i_tracks = p_tocheader[3] - p_tocheader[2] + 1;
+
+            if( pp_sectors )
+            {
+                int i, i_toclength;
+                byte_t *p_fulltoc;
+
+                i_toclength = 4 /* header */ + p_tocheader[0] +
+                              ((unsigned int)p_tocheader[1] << 8);
+
+                p_fulltoc = malloc( i_toclength );
+                *pp_sectors = malloc( (i_tracks + 1) * sizeof(int) );
+
+                if( *pp_sectors == NULL || p_fulltoc == NULL )
+                {
+                    if( *pp_sectors ) free( *pp_sectors );
+                    if( p_fulltoc ) free( p_fulltoc );
+                    msg_Err( p_this, "out of memory" );
+                    CloseHandle( hEvent );
+                    return 0;
+                }
+
+                /* Allocation length and buffer */
+                ssc.SRB_BufLen = i_toclength;
+                ssc.SRB_BufPointer  = p_fulltoc;
+                ssc.CDBByte[ 7 ] = ( ssc.SRB_BufLen >>  8 ) & 0xff;
+                ssc.CDBByte[ 8 ] = ( ssc.SRB_BufLen       ) & 0xff;
+
+                /* Initiate transfer */
+                ResetEvent( hEvent );
+                p_vcddev->lpSendCommand( (void*) &ssc );
+
+                /* If the command has still not been processed, wait until it's
+                 * finished */
+                if( ssc.SRB_Status == SS_PENDING )
+                    WaitForSingleObject( hEvent, INFINITE );
+
+                /* check that the transfer went as planned */
+                if( ssc.SRB_Status != SS_COMP )
+                    i_tracks = 0;
+
+                for( i = 0 ; i <= i_tracks ; i++ )
+                {
+                    int i_index = 8 + 8 * i;
+                    (*pp_sectors)[ i ] = ((int)p_fulltoc[ i_index ] << 24) +
+                                         ((int)p_fulltoc[ i_index+1 ] << 16) +
+                                         ((int)p_fulltoc[ i_index+2 ] << 8) +
+                                         (int)p_fulltoc[ i_index+3 ];
+
+                    msg_Dbg( p_this, "p_sectors: %i, %i", i, (*pp_sectors)[i]);
+                }
+
+                free( p_fulltoc );
+            }
+
+            CloseHandle( hEvent );
+
+        }
+        else
+        {
+            DWORD dwBytesReturned;
+            CDROM_TOC cdrom_toc;
+
+            if( DeviceIoControl( p_vcddev->h_device_handle,
+                                 IOCTL_CDROM_READ_TOC,
+                                 NULL, 0, &cdrom_toc, sizeof(CDROM_TOC),
+                                 &dwBytesReturned, NULL ) == 0 )
+            {
+                msg_Err( p_this, "could not read TOCHDR" );
+                return 0;
+            }
+
+            i_tracks = cdrom_toc.LastTrack - cdrom_toc.FirstTrack + 1;
+
+            if( pp_sectors )
+            {
+                int i;
+
+                *pp_sectors = malloc( (i_tracks + 1) * sizeof(int) );
+                if( *pp_sectors == NULL )
+                {
+                    msg_Err( p_this, "out of memory" );
+                    return 0;
+                }
+
+                for( i = 0 ; i <= i_tracks ; i++ )
+                {
+                    (*pp_sectors)[ i ] = MSF_TO_LBA2(
+                                           cdrom_toc.TrackData[i].Address[1],
+                                           cdrom_toc.TrackData[i].Address[2],
+                                           cdrom_toc.TrackData[i].Address[3] );
+                    msg_Dbg( p_this, "p_sectors: %i, %i", i, (*pp_sectors)[i]);
+                }
+            }
+        }
 
 #elif defined( HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H )
-    struct ioc_read_toc_entry toc_entries;
+        struct ioc_toc_header tochdr;
+        struct ioc_read_toc_entry toc_entries;
 
-    i_tracks = ioctl_GetTrackCount( p_this, i_fd, psz_dev );
-    p_sectors = malloc( (i_tracks + 1) * sizeof(int) );
-    if( p_sectors == NULL )
-    {
-        msg_Err( p_this, "out of memory" );
-        return NULL;
-    }
+        if( ioctl( p_vcddev->i_devicd_handle, CDIOREADTOCHEADER, &tochdr )
+            == -1 )
+        {
+            msg_Err( p_this, "could not read TOCHDR" );
+            return 0;
+        }
 
-    toc_entries.address_format = CD_LBA_FORMAT;
-    toc_entries.starting_track = 0;
-    toc_entries.data_len = ( i_tracks + 1 ) * sizeof( struct cd_toc_entry ); 
-    toc_entries.data = (struct cd_toc_entry *) malloc( toc_entries.data_len );
-    if( toc_entries.data == NULL )
-    {
-        msg_Err( p_this, "out of memory" );
-        free( p_sectors );
-        return NULL;
-    }
+        i_tracks = tochdr.ending_track - tochdr.starting_track + 1;
+
+        if( pp_sectors )
+        {
+             int i;
+
+             *pp_sectors = malloc( (i_tracks + 1) * sizeof(int) );
+             if( *pp_sectors == NULL )
+             {
+                 msg_Err( p_this, "out of memory" );
+                 return NULL;
+             }
+
+             toc_entries.address_format = CD_LBA_FORMAT;
+             toc_entries.starting_track = 0;
+             toc_entries.data_len = ( i_tracks + 1 ) *
+                                        sizeof( struct cd_toc_entry ); 
+             toc_entries.data = (struct cd_toc_entry *)
+                                    malloc( toc_entries.data_len );
+             if( toc_entries.data == NULL )
+             {
+                 msg_Err( p_this, "out of memory" );
+                 free( *pp_sectors );
+                 return 0;
+             }
  
-    /* Read the TOC */
-    if( ioctl( i_fd, CDIOREADTOCENTRYS, &toc_entries ) == -1 )
-    {
-        msg_Err( p_this, "could not read the TOC" );
-        free( p_sectors );
-        free( toc_entries.data );
-        return NULL;
-    }
+             /* Read the TOC */
+             if( ioctl( p_vcddev->i_device_handle, CDIOREADTOCENTRYS,
+                        &toc_entries ) == -1 )
+             {
+                 msg_Err( p_this, "could not read the TOC" );
+                 free( *pp_sectors );
+                 free( toc_entries.data );
+                 return 0;
+             }
     
-    /* Fill the p_sectors structure with the track/sector matches */
-    for( i = 0 ; i <= i_tracks ; i++ )
-    {
-        p_sectors[ i ] = ntohl( toc_entries.data[i].addr.lba );
-    }
+             /* Fill the p_sectors structure with the track/sector matches */
+             for( i = 0 ; i <= i_tracks ; i++ )
+             {
+                 (*pp_sectors)[ i ] = ntohl( toc_entries.data[i].addr.lba );
+             }
+        }
 #else
-    struct cdrom_tochdr   tochdr;
-    struct cdrom_tocentry tocent;
-
-    /* First we read the TOC header */
-    if( ioctl( i_fd, CDROMREADTOCHDR, &tochdr ) == -1 )
-    {
-        msg_Err( p_this, "could not read TOCHDR" );
-        return NULL;
-    }
+        struct cdrom_tochdr   tochdr;
+        struct cdrom_tocentry tocent;
 
-    i_tracks = tochdr.cdth_trk1 - tochdr.cdth_trk0 + 1;
-
-    p_sectors = malloc( (i_tracks + 1) * sizeof(int) );
-    if( p_sectors == NULL )
-    {
-        msg_Err( p_this, "out of memory" );
-        return NULL;
-    }
+        /* First we read the TOC header */
+        if( ioctl( p_vcddev->i_device_handle, CDROMREADTOCHDR, &tochdr )
+            == -1 )
+        {
+            msg_Err( p_this, "could not read TOCHDR" );
+            return 0;
+        }
 
-    /* Fill the p_sectors structure with the track/sector matches */
-    for( i = 0 ; i <= i_tracks ; i++ )
-    {
-        tocent.cdte_format = CDROM_LBA;
-        tocent.cdte_track =
-            ( i == i_tracks ) ? CDROM_LEADOUT : tochdr.cdth_trk0 + i;
+        i_tracks = tochdr.cdth_trk1 - tochdr.cdth_trk0 + 1;
 
-        if( ioctl( i_fd, CDROMREADTOCENTRY, &tocent ) == -1 )
+        if( pp_sectors )
         {
-            msg_Err( p_this, "could not read TOCENTRY" );
-            free( p_sectors );
-            return NULL;
+            int i;
+
+            *pp_sectors = malloc( (i_tracks + 1) * sizeof(int) );
+            if( *pp_sectors == NULL )
+            {
+                msg_Err( p_this, "out of memory" );
+                return 0;
+            }
+
+            /* Fill the p_sectors structure with the track/sector matches */
+            for( i = 0 ; i <= i_tracks ; i++ )
+            {
+                tocent.cdte_format = CDROM_LBA;
+                tocent.cdte_track =
+                    ( i == i_tracks ) ? CDROM_LEADOUT : tochdr.cdth_trk0 + i;
+
+                if( ioctl( p_vcddev->i_device_handle, CDROMREADTOCENTRY,
+                           &tocent ) == -1 )
+                {
+                    msg_Err( p_this, "could not read TOCENTRY" );
+                    free( *pp_sectors );
+                    return 0;
+                }
+
+                (*pp_sectors)[ i ] = tocent.cdte_addr.lba;
+            }
         }
-
-        p_sectors[ i ] = tocent.cdte_addr.lba;
-    }
 #endif
 
-    return p_sectors;
+        return i_tracks;
+    }
 }
 
 /****************************************************************************
  * ioctl_ReadSector: Read a sector (2324 bytes)
  ****************************************************************************/
-int ioctl_ReadSector( vlc_object_t *p_this,
-                      int i_fd, int i_sector, byte_t * p_buffer )
+int ioctl_ReadSector( vlc_object_t *p_this, const vcddev_t *p_vcddev,
+                      int i_sector, byte_t * p_buffer )
 {
     byte_t p_block[ VCD_SECTOR_SIZE ];
 
+    if( p_vcddev->i_vcdimage_handle != -1 )
+    {
+        /*
+         *  vcd image mode
+         */
+        if( lseek( p_vcddev->i_vcdimage_handle, i_sector * VCD_SECTOR_SIZE,
+                   SEEK_SET ) == -1 )
+        {
+            msg_Err( p_this, "Could not lseek to sector %d", i_sector );
+            return -1;
+        }
+
+        if( read( p_vcddev->i_vcdimage_handle, p_block, VCD_SECTOR_SIZE )
+            == -1 )
+        {
+            // msg_Err( p_this, "Could not read sector %d", i_sector );
+            return -1;
+        }
+
+        /* We don't want to keep the header of the read sector */
+        memcpy( p_buffer, p_block + VCD_DATA_START, VCD_DATA_SIZE );
+
+        return 0;
+    }
+    else
+    {
+
+        /*
+         *  vcd device mode
+         */
+
 #if defined( SYS_DARWIN )
-    dk_cd_read_t cd_read;
+        dk_cd_read_t cd_read;
 
-    memset( &cd_read, 0, sizeof(cd_read) );
+        memset( &cd_read, 0, sizeof(cd_read) );
 
-    cd_read.offset = i_sector * VCD_SECTOR_SIZE;
-    cd_read.sectorArea = kCDSectorAreaSync | kCDSectorAreaHeader |
-                         kCDSectorAreaSubHeader | kCDSectorAreaUser |
-                         kCDSectorAreaAuxiliary;
-    cd_read.sectorType = kCDSectorTypeUnknown;
+        cd_read.offset = i_sector * VCD_SECTOR_SIZE;
+        cd_read.sectorArea = kCDSectorAreaSync | kCDSectorAreaHeader |
+                             kCDSectorAreaSubHeader | kCDSectorAreaUser |
+                             kCDSectorAreaAuxiliary;
+        cd_read.sectorType = kCDSectorTypeUnknown;
 
-    cd_read.buffer = p_block;
-    cd_read.bufferLength = sizeof(p_block);
+        cd_read.buffer = p_block;
+        cd_read.bufferLength = sizeof(p_block);
 
-    if( ioctl( i_fd, DKIOCCDREAD, &cd_read ) == -1 )
-    {
-        msg_Err( p_this, "could not read block %d", i_sector );
-        return( -1 );
-    }
+        if( ioctl( p_vcddev->i_device_handle, DKIOCCDREAD, &cd_read ) == -1 )
+        {
+            msg_Err( p_this, "could not read block %d", i_sector );
+            return -1;
+        }
+
+#elif defined( WIN32 )
+        if( p_vcddev->hASPI )
+        {
+            HANDLE hEvent;
+            struct SRB_ExecSCSICmd ssc;
+
+            /* Create the transfer completion event */
+            hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+            if( hEvent == NULL )
+            {
+                return -1;
+            }
+
+            memset( &ssc, 0, sizeof( ssc ) );
+
+            ssc.SRB_Cmd         = SC_EXEC_SCSI_CMD;
+            ssc.SRB_Flags       = SRB_DIR_IN | SRB_EVENT_NOTIFY;
+            ssc.SRB_HaId        = LOBYTE( p_vcddev->i_sid );
+            ssc.SRB_Target      = HIBYTE( p_vcddev->i_sid );
+            ssc.SRB_SenseLen    = SENSE_LEN;
+
+            ssc.SRB_PostProc = (LPVOID) hEvent;
+            ssc.SRB_CDBLen      = 12;
+
+            /* Operation code */
+            ssc.CDBByte[ 0 ] = READ_CD;
+
+            /* Start of LBA */
+            ssc.CDBByte[ 2 ] = ( i_sector >> 24 ) & 0xff;
+            ssc.CDBByte[ 3 ] = ( i_sector >> 16 ) & 0xff;
+            ssc.CDBByte[ 4 ] = ( i_sector >>  8 ) & 0xff;
+            ssc.CDBByte[ 5 ] = ( i_sector       ) & 0xff;
+
+            /* Transfer length */
+            ssc.CDBByte[ 6 ] = 0;
+            ssc.CDBByte[ 7 ] = 0;
+            ssc.CDBByte[ 8 ] = 1;
+
+            /* Data selection */
+            ssc.CDBByte[ 9 ] = READ_CD_USERDATA_MODE2;
+
+            /* Result buffer */
+            ssc.SRB_BufPointer  = p_block;
+            ssc.SRB_BufLen = VCD_SECTOR_SIZE;
+
+            /* Initiate transfer */
+            ResetEvent( hEvent );
+            p_vcddev->lpSendCommand( (void*) &ssc );
+
+            /* If the command has still not been processed, wait until it's
+             * finished */
+            if( ssc.SRB_Status == SS_PENDING )
+            {
+                WaitForSingleObject( hEvent, INFINITE );
+            }
+            CloseHandle( hEvent );
+
+            /* check that the transfer went as planned */
+            if( ssc.SRB_Status != SS_COMP )
+            {
+                return -1;
+            }
+
+            /* We don't want to keep the footer of the read sector */
+            memcpy( p_buffer, p_block, VCD_DATA_SIZE );
+            return 0;
+        }
+        else
+        {
+            DWORD dwBytesReturned;
+            RAW_READ_INFO cdrom_raw;
+
+            /* Initialize CDROM_RAW_READ structure */
+            cdrom_raw.DiskOffset.QuadPart = CD_SECTOR_SIZE * i_sector;
+            cdrom_raw.SectorCount = 1;
+            cdrom_raw.TrackMode = XAForm2;
+
+            if( DeviceIoControl( p_vcddev->h_device_handle,
+                                 IOCTL_CDROM_RAW_READ, &cdrom_raw,
+                                 sizeof(RAW_READ_INFO), p_block,
+                                 sizeof(p_block), &dwBytesReturned, NULL )
+                == 0 )
+            {
+                return -1;
+            }
+            /* We don't want to keep the header of the read sector */
+            memcpy( p_buffer, p_block + VCD_DATA_START, VCD_DATA_SIZE );
+
+            return 0;
+        }
 
 #elif defined( HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H )
-    
-    int i_size = VCD_SECTOR_SIZE;
 
-    if( ioctl( i_fd, CDRIOCSETBLOCKSIZE, &i_size ) == -1 )
+        int i_size = VCD_SECTOR_SIZE;
+
+        if( ioctl( p_vcddev->i_device_handle, CDRIOCSETBLOCKSIZE, &i_size )
+            == -1 )
+        {
+            msg_Err( p_this, "Could not set block size" );
+            return( -1 );
+        }
+
+        if( lseek( p_vcddev->i_device_handle,
+                   i_sector * VCD_SECTOR_SIZE, SEEK_SET ) == -1 )
+        {
+            msg_Err( p_this, "Could not lseek to sector %d", i_sector );
+            return( -1 );
+        }
+
+        if( read( p_vcddev->i_device_handle, p_block, VCD_SECTOR_SIZE ) == -1 )
+        {
+            msg_Err( p_this, "Could not read sector %d", i_sector );
+            return( -1 );
+        }
+
+#else
+        int i_dummy = i_sector + 2 * CD_FRAMES;
+
+#define p_msf ((struct cdrom_msf0 *)p_block)
+        p_msf->minute =   i_dummy / (CD_FRAMES * CD_SECS);
+        p_msf->second = ( i_dummy % (CD_FRAMES * CD_SECS) ) / CD_FRAMES;
+        p_msf->frame =  ( i_dummy % (CD_FRAMES * CD_SECS) ) % CD_FRAMES;
+#undef p_msf
+
+        if( ioctl(p_vcddev->i_device_handle, CDROMREADRAW, p_block) == -1 )
+        {
+            msg_Err( p_this, "could not read block %i from disc", i_sector );
+            return( -1 );
+        }
+#endif
+
+        /* We don't want to keep the header of the read sector */
+        memcpy( p_buffer, p_block + VCD_DATA_START, VCD_DATA_SIZE );
+
+        return( 0 );
+    }
+}
+
+/****************************************************************************
+ * Private functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * OpenVCDImage: try to open a vcd image from a .cue file
+ ****************************************************************************/
+static int OpenVCDImage( vlc_object_t * p_this, const char *psz_dev,
+                         vcddev_t *p_vcddev )
+{
+    int i_ret = -1;
+    char *p_pos;
+    char *psz_vcdfile = NULL;
+    char *psz_cuefile = NULL;
+    FILE *cuefile;
+    char line[1024];
+
+    /* Check if we are dealing with a .cue file */
+    p_pos = strrchr( psz_dev, '.' );
+    if( p_pos && !strcmp( p_pos, ".cue" ) )
     {
-        msg_Err( p_this, "Could not set block size" );
-        return( -1 );
+        psz_cuefile = strdup( psz_dev );
+    }
+    else
+    {
+        /* psz_dev must be the actual vcd file. Let's assume there's a .cue
+         * file with the same filename */
+        if( p_pos )
+        {
+            psz_cuefile = malloc( p_pos - psz_dev + 5 /* ".cue" */ );
+            strncpy( psz_cuefile, psz_dev, p_pos - psz_dev );
+            strcpy( psz_cuefile + (p_pos - psz_dev), ".cue");
+        }
+        else
+        {
+            psz_cuefile = malloc( strlen(psz_dev) + 5 /* ".cue" */ );
+            sprintf( psz_cuefile, "%s.cue", psz_dev );
+        }
     }
 
-    if( lseek( i_fd, i_sector * VCD_SECTOR_SIZE, SEEK_SET ) == -1 )
+    /* Open the cue file and try to parse it */
+    msg_Dbg( p_this,"using .cue file: %s", psz_cuefile );
+    cuefile = fopen( psz_cuefile, "rt" );
+    if( cuefile && fscanf( cuefile, "FILE %c", line ) &&
+        fgets( line, 1024, cuefile ) )
     {
-        msg_Err( p_this, "Could not lseek to sector %d", i_sector );
-        return( -1 );
+        p_pos = strchr( line, '"' );
+        if( p_pos )
+        {
+            *p_pos = 0;
+
+            /* Take care of path standardization */
+            if( *line != '/' && (p_pos = strrchr( psz_cuefile, '/' )) )
+            {
+                psz_vcdfile = malloc( strlen(line) +
+                                      (p_pos - psz_cuefile + 1) + 1 );
+                strncpy( psz_vcdfile, psz_cuefile, (p_pos - psz_cuefile + 1) );
+                strcpy( psz_vcdfile + (p_pos - psz_cuefile + 1), line );
+            }
+            else psz_vcdfile = strdup( line );
+        }
     }
 
-    if( read( i_fd, p_block, VCD_SECTOR_SIZE ) == -1 )
+    if( psz_vcdfile )
     {
-        msg_Err( p_this, "Could not read sector %d", i_sector );
-        return( -1 );
+        msg_Dbg( p_this,"using vcd image file: %s", psz_vcdfile );
+        p_vcddev->i_vcdimage_handle = open( psz_vcdfile,
+                                        O_RDONLY | O_NONBLOCK | O_BINARY );
+        i_ret = (p_vcddev->i_vcdimage_handle == -1) ? -1 : 0;
     }
 
-#else
-    int i_dummy = i_sector + 2 * CD_FRAMES;
+    /* Try to parse the i_tracks and p_sectors info so we can just forget
+     * about the cuefile */
+    if( i_ret == 0 )
+    {
+        int p_sectors[100];
+        int i_tracks = 0;
+        int i_num;
+        char psz_dummy[10];
 
-#define p_msf ((struct cdrom_msf0 *)p_block)
-    p_msf->minute =   i_dummy / (CD_FRAMES * CD_SECS);
-    p_msf->second = ( i_dummy % (CD_FRAMES * CD_SECS) ) / CD_FRAMES;
-    p_msf->frame =  ( i_dummy % (CD_FRAMES * CD_SECS) ) % CD_FRAMES;
-#undef p_msf
+        while( fgets( line, 1024, cuefile ) )
+        {
+            /* look for a TRACK line */
+            if( !sscanf( line, "%9s", psz_dummy ) ||
+                strcmp(psz_dummy, "TRACK") )
+                continue;
+
+            /* look for an INDEX line */
+            while( fgets( line, 1024, cuefile ) )
+            {
+                int i_min, i_sec, i_frame;
+
+                if( (sscanf( line, "%9s %2u %2u:%2u:%2u", psz_dummy, &i_num,
+                            &i_min, &i_sec, &i_frame ) != 5) || (i_num != 1) )
+                    continue;
+
+                i_tracks++;
+                p_sectors[i_tracks - 1] = MSF_TO_LBA(i_min, i_sec, i_frame);
+                msg_Dbg( p_this, "vcd track %i begins at sector:%i",
+                         i_tracks - 1, p_sectors[i_tracks - 1] );
+                break;
+            }
+        }
+
+        /* fill in the last entry */
+        p_sectors[i_tracks] = lseek(p_vcddev->i_vcdimage_handle, 0, SEEK_END)
+                                / VCD_SECTOR_SIZE;
+        msg_Dbg( p_this, "vcd track %i, begins at sector:%i",
+                 i_tracks, p_sectors[i_tracks] );
+        p_vcddev->i_tracks = i_tracks;
+        p_vcddev->p_sectors = malloc( (i_tracks + 1) * sizeof(int) );
+        memcpy( p_vcddev->p_sectors, p_sectors, (i_tracks + 1) * sizeof(int) );
 
-    if( ioctl(i_fd, CDROMREADRAW, p_block) == -1 )
-    {
-        msg_Err( p_this, "could not read block %i from disc", i_sector );
-        return( -1 );
     }
-#endif
 
-    /* We don't want to keep the header of the read sector */
-    memcpy( p_buffer, p_block + VCD_DATA_START, VCD_DATA_SIZE );
+    if( cuefile ) fclose( cuefile );
+    if( psz_cuefile ) free( psz_cuefile );
+    if( psz_vcdfile ) free( psz_vcdfile );
 
-    return( 0 );
+    return i_ret;
+}
+
+/****************************************************************************
+ * CloseVCDImage: closes a vcd image opened by OpenVCDImage
+ ****************************************************************************/
+static void CloseVCDImage( vlc_object_t * p_this, vcddev_t *p_vcddev )
+{
+    if( p_vcddev->i_vcdimage_handle != -1 )
+        close( p_vcddev->i_vcdimage_handle );
+    else
+        return;
+
+    if( p_vcddev->p_sectors )
+        free( p_vcddev->p_sectors );
 }
 
 #if defined( SYS_DARWIN )
 /****************************************************************************
- * getTOC: get the TOC
+ * darwin_getTOC: get the TOC
  ****************************************************************************/
-CDTOC *getTOC( vlc_object_t * p_this, const char *psz_dev )
+static CDTOC *darwin_getTOC( vlc_object_t * p_this, vcddev_t *p_vcddev )
 {
     mach_port_t port;
     char *psz_devname;
@@ -345,17 +879,11 @@ CDTOC *getTOC( vlc_object_t * p_this, const char *psz_dev )
     CFDictionaryRef properties;
     CFDataRef data;
 
-    if( psz_dev == NULL )
-    {
-        msg_Err( p_this, "invalid device path" );
-        return( NULL );
-    }
-
     /* get the device name */
-    if( ( psz_devname = strrchr( psz_dev, '/') ) != NULL )
+    if( ( psz_devname = strrchr( p_vcddev->psz_dev, '/') ) != NULL )
         ++psz_devname;
     else
-        psz_devname = (char *)psz_dev;
+        psz_devname = p_vcddev->psz_dev;
 
     /* unraw the device name */
     if( *psz_devname == 'r' )
@@ -439,9 +967,9 @@ CDTOC *getTOC( vlc_object_t * p_this, const char *psz_dev )
 }
 
 /****************************************************************************
- * getNumberOfDescriptors: get number of descriptors in TOC 
+ * darwin_getNumberOfDescriptors: get number of descriptors in TOC 
  ****************************************************************************/
-int getNumberOfDescriptors( CDTOC *pTOC )
+static int darwin_getNumberOfDescriptors( CDTOC *pTOC )
 {
     int i_descriptors;
 
@@ -459,9 +987,9 @@ int getNumberOfDescriptors( CDTOC *pTOC )
 }
 
 /****************************************************************************
- * getNumberOfTracks: get number of tracks in TOC 
+ * darwin_getNumberOfTracks: get number of tracks in TOC 
  ****************************************************************************/
-int getNumberOfTracks( CDTOC *pTOC, int i_descriptors )
+static int darwin_getNumberOfTracks( CDTOC *pTOC, int i_descriptors )
 {
     u_char track;
     int i, i_tracks = 0; 
@@ -481,4 +1009,146 @@ int getNumberOfTracks( CDTOC *pTOC, int i_descriptors )
 
     return( i_tracks );
 }
-#endif
+#endif /* SYS_DARWIN */
+
+#if defined( WIN32 )
+/*****************************************************************************
+ * win32_vcd_open: open vcd drive
+ *****************************************************************************
+ * Load and use aspi if it is available, otherwise use IOCTLs on WinNT/2K/XP.
+ *****************************************************************************/
+static int win32_vcd_open( vlc_object_t * p_this, const char *psz_dev,
+                           vcddev_t *p_vcddev )
+{
+    /* Initializations */
+    p_vcddev->h_device_handle = NULL;
+    p_vcddev->i_sid = 0;
+    p_vcddev->hASPI = 0;
+    p_vcddev->lpSendCommand = 0;
+
+    if( WIN_NT )
+    {
+        char psz_win32_drive[7];
+
+        msg_Dbg( p_this, "using winNT/2K/XP ioctl layer" );
+
+        sprintf( psz_win32_drive, "\\\\.\\%c:", psz_dev[0] );
+
+        p_vcddev->h_device_handle = CreateFile( psz_win32_drive, GENERIC_READ,
+                                            FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                            NULL, OPEN_EXISTING,
+                                            FILE_FLAG_NO_BUFFERING |
+                                            FILE_FLAG_RANDOM_ACCESS, NULL );
+        return (p_vcddev->h_device_handle == NULL) ? -1 : 0;
+    }
+    else
+    {
+        HMODULE hASPI = NULL;
+        long (*lpGetSupport)( void ) = NULL;
+        long (*lpSendCommand)( void* ) = NULL;
+        DWORD dwSupportInfo;
+        int i, j, i_hostadapters;
+        char c_drive = psz_dev[0];
+
+        hASPI = LoadLibrary( "wnaspi32.dll" );
+        if( hASPI != NULL )
+        {
+            (FARPROC) lpGetSupport = GetProcAddress( hASPI,
+                                                     "GetASPI32SupportInfo" );
+            (FARPROC) lpSendCommand = GetProcAddress( hASPI,
+                                                      "SendASPI32Command" );
+        }
+
+        if( hASPI == NULL || lpGetSupport == NULL || lpSendCommand == NULL )
+        {
+            msg_Dbg( p_this,
+                     "unable to load aspi or get aspi function pointers" );
+            if( hASPI ) FreeLibrary( hASPI );
+            return -1;
+        }
+
+        /* ASPI support seems to be there */
+
+        dwSupportInfo = lpGetSupport();
+
+        if( HIBYTE( LOWORD ( dwSupportInfo ) ) == SS_NO_ADAPTERS )
+        {
+            msg_Dbg( p_this, "no host adapters found (aspi)" );
+            FreeLibrary( hASPI );
+            return -1;
+        }
+
+        if( HIBYTE( LOWORD ( dwSupportInfo ) ) != SS_COMP )
+        {
+            msg_Dbg( p_this, "unable to initalize aspi layer" );
+            FreeLibrary( hASPI );
+            return -1;
+        }
+
+        i_hostadapters = LOBYTE( LOWORD( dwSupportInfo ) );
+        if( i_hostadapters == 0 )
+        {
+            FreeLibrary( hASPI );
+            return -1;
+        }
+
+        c_drive = c_drive > 'Z' ? c_drive - 'a' : c_drive - 'A';
+
+        for( i = 0; i < i_hostadapters; i++ )
+        {
+          for( j = 0; j < 15; j++ )
+          {
+              struct SRB_GetDiskInfo srbDiskInfo;
+
+              srbDiskInfo.SRB_Cmd         = SC_GET_DISK_INFO;
+              srbDiskInfo.SRB_HaId        = i;
+              srbDiskInfo.SRB_Flags       = 0;
+              srbDiskInfo.SRB_Hdr_Rsvd    = 0;
+              srbDiskInfo.SRB_Target      = j;
+              srbDiskInfo.SRB_Lun         = 0;
+
+              lpSendCommand( (void*) &srbDiskInfo );
+
+              if( (srbDiskInfo.SRB_Status == SS_COMP) &&
+                  (srbDiskInfo.SRB_Int13HDriveInfo == c_drive) )
+              {
+                  /* Make sure this is a cdrom device */
+                  struct SRB_GDEVBlock   srbGDEVBlock;
+
+                  memset( &srbGDEVBlock, 0, sizeof(struct SRB_GDEVBlock) );
+                  srbGDEVBlock.SRB_Cmd    = SC_GET_DEV_TYPE;
+                  srbGDEVBlock.SRB_HaId   = i;
+                  srbGDEVBlock.SRB_Target = j;
+
+                  lpSendCommand( (void*) &srbGDEVBlock );
+
+                  if( ( srbGDEVBlock.SRB_Status == SS_COMP ) &&
+                      ( srbGDEVBlock.SRB_DeviceType == DTYPE_CDROM ) )
+                  {
+                      p_vcddev->i_sid = MAKEWORD( i, j );
+                      p_vcddev->hASPI = (long)hASPI;
+                      p_vcddev->lpSendCommand = lpSendCommand;
+                      msg_Dbg( p_this, "using aspi layer" );
+
+                      return 0;
+                  }
+                  else
+                  {
+                      FreeLibrary( hASPI );
+                      msg_Dbg( p_this, "%s: is not a cdrom drive",
+                               psz_dev[0] );
+                      return -1;
+                  }
+              }
+          }
+        }
+
+        FreeLibrary( hASPI );
+        msg_Dbg( p_this, "unable to get haid and target (aspi)" );
+
+    }
+
+    return -1;
+}
+
+#endif /* WIN32 */
index 876291e..cd40b26 100644 (file)
@@ -2,9 +2,10 @@
  * cdrom.h: cdrom tools header
  *****************************************************************************
  * Copyright (C) 1998-2001 VideoLAN
- * $Id: cdrom.h,v 1.2 2002/08/08 22:28:22 sam Exp $
+ * $Id: cdrom.h,v 1.3 2002/10/15 19:56:59 gbazin Exp $
  *
- * Author: Johan Bilien <jobi@via.ecp.fr>
+ * Authors: Johan Bilien <jobi@via.ecp.fr>
+ *          Gildas Bazin <gbazin@netcourrier.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  *****************************************************************************/
 
-/* where the data start on a VCD sector */
-#define VCD_DATA_START 24
-/* size of the availablr data on a VCD sector */
-#define VCD_DATA_SIZE 2324
-/* size of a VCD sector, header and tail included */
-#define VCD_SECTOR_SIZE 2352
+/*****************************************************************************
+ * The vcddev structure
+ *****************************************************************************/
+typedef struct vcddev_s
+{
+    char   *psz_dev;                                      /* vcd device name */
+
+    /* Section used in vcd image mode */
+    int    i_vcdimage_handle;                   /* vcd image file descriptor */
+    int    i_tracks;                          /* number of tracks of the vcd */
+    int    *p_sectors;                           /* tracks layout on the vcd */
+
+    /* Section used in vcd device mode */
+
+#ifdef WIN32
+    HANDLE h_device_handle;                         /* vcd device descriptor */
+    long  hASPI;
+    short i_sid;
+    long  (*lpSendCommand)( void* );
+
+#else
+    int    i_device_handle;                         /* vcd device descriptor */
+#endif
+
+} vcddev_t;
+
+
+/*****************************************************************************
+ * Misc. Macros
+ *****************************************************************************/
+/* LBA = msf.frame + 75 * ( msf.second + 60 * msf.minute ) */
+#define MSF_TO_LBA(min, sec, frame) ((int)frame + 75 * (sec + 60 * min))
+/* LBA = msf.frame + 75 * ( msf.second - 2 + 60 * msf.minute ) */
+#define MSF_TO_LBA2(min, sec, frame) ((int)frame + 75 * (sec -2 + 60 * min))
+
+#ifndef O_BINARY
+#   define O_BINARY 0
+#endif
+
+#define VCDDEV_T 1
+
+/*****************************************************************************
+ * Platform specifics
+ *****************************************************************************/
+#if defined( SYS_DARWIN )
+#define darwin_freeTOC( p ) free( (void*)p )
+#define CD_MIN_TRACK_NO 01
+#define CD_MAX_TRACK_NO 99
+#endif
+
+#if defined( WIN32 )
+
+/* Win32 DeviceIoControl specifics */
+#ifndef MAXIMUM_NUMBER_TRACKS
+#    define MAXIMUM_NUMBER_TRACKS 100
+#endif
+typedef struct _TRACK_DATA {
+    UCHAR Reserved;
+    UCHAR Control : 4;
+    UCHAR Adr : 4;
+    UCHAR TrackNumber;
+    UCHAR Reserved1;
+    UCHAR Address[4];
+} TRACK_DATA, *PTRACK_DATA;
+typedef struct _CDROM_TOC {
+    UCHAR Length[2];
+    UCHAR FirstTrack;
+    UCHAR LastTrack;
+    TRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS];
+} CDROM_TOC, *PCDROM_TOC;
+typedef enum _TRACK_MODE_TYPE {
+    YellowMode2,
+    XAForm2,
+    CDDA
+} TRACK_MODE_TYPE, *PTRACK_MODE_TYPE;
+typedef struct __RAW_READ_INFO {
+    LARGE_INTEGER DiskOffset;
+    ULONG SectorCount;
+    TRACK_MODE_TYPE TrackMode;
+} RAW_READ_INFO, *PRAW_READ_INFO;
+
+#ifndef IOCTL_CDROM_BASE
+#    define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM
+#endif
+#ifndef IOCTL_CDROM_READ_TOC
+#    define IOCTL_CDROM_READ_TOC CTL_CODE(IOCTL_CDROM_BASE, 0x0000, \
+                                          METHOD_BUFFERED, FILE_READ_ACCESS)
+#endif
+#ifndef IOCTL_CDROM_RAW_READ
+#define IOCTL_CDROM_RAW_READ CTL_CODE(IOCTL_CDROM_BASE, 0x000F, \
+                                      METHOD_OUT_DIRECT, FILE_READ_ACCESS)
+#endif
+
+/* Win32 aspi specific */
+#define WIN_NT               ( GetVersion() < 0x80000000 )
+#define ASPI_HAID           0
+#define ASPI_TARGET         0
+#define DTYPE_CDROM         0x05
+
+#define SENSE_LEN           0x0E
+#define SC_GET_DEV_TYPE     0x01
+#define SC_EXEC_SCSI_CMD    0x02
+#define SC_GET_DISK_INFO    0x06
+#define SS_COMP             0x01
+#define SS_PENDING          0x00
+#define SS_NO_ADAPTERS      0xE8
+#define SRB_DIR_IN          0x08
+#define SRB_DIR_OUT         0x10
+#define SRB_EVENT_NOTIFY    0x40
+
+#define READ_CD 0xbe
+#define SECTOR_TYPE_MODE2 0x14
+#define READ_CD_USERDATA_MODE2 0x10
+
+#define READ_TOC 0x43
+#define READ_TOC_FORMAT_TOC 0x0
+
+#pragma pack(1)
+
+struct SRB_GetDiskInfo
+{
+    unsigned char   SRB_Cmd;
+    unsigned char   SRB_Status;
+    unsigned char   SRB_HaId;
+    unsigned char   SRB_Flags;
+    unsigned long   SRB_Hdr_Rsvd;
+    unsigned char   SRB_Target;
+    unsigned char   SRB_Lun;
+    unsigned char   SRB_DriveFlags;
+    unsigned char   SRB_Int13HDriveInfo;
+    unsigned char   SRB_Heads;
+    unsigned char   SRB_Sectors;
+    unsigned char   SRB_Rsvd1[22];
+};
+
+struct SRB_GDEVBlock
+{
+    unsigned char SRB_Cmd;
+    unsigned char SRB_Status;
+    unsigned char SRB_HaId;
+    unsigned char SRB_Flags;
+    unsigned long SRB_Hdr_Rsvd;
+    unsigned char SRB_Target;
+    unsigned char SRB_Lun;
+    unsigned char SRB_DeviceType;
+    unsigned char SRB_Rsvd1;
+};
+
+struct SRB_ExecSCSICmd
+{
+    unsigned char   SRB_Cmd;
+    unsigned char   SRB_Status;
+    unsigned char   SRB_HaId;
+    unsigned char   SRB_Flags;
+    unsigned long   SRB_Hdr_Rsvd;
+    unsigned char   SRB_Target;
+    unsigned char   SRB_Lun;
+    unsigned short  SRB_Rsvd1;
+    unsigned long   SRB_BufLen;
+    unsigned char   *SRB_BufPointer;
+    unsigned char   SRB_SenseLen;
+    unsigned char   SRB_CDBLen;
+    unsigned char   SRB_HaStat;
+    unsigned char   SRB_TargStat;
+    unsigned long   *SRB_PostProc;
+    unsigned char   SRB_Rsvd2[20];
+    unsigned char   CDBByte[16];
+    unsigned char   SenseArea[SENSE_LEN+2];
+};
+
+#pragma pack()
+#endif /* WIN32 */
+
+
+/*****************************************************************************
+ * Local Prototypes
+ *****************************************************************************/
+static int    OpenVCDImage( vlc_object_t *, const char *, vcddev_t * );
+static void   CloseVCDImage( vlc_object_t *, vcddev_t * );
 
-/******************************************************************************
-* Prototypes                                                                  *
-******************************************************************************/
-int   ioctl_GetTrackCount ( vlc_object_t *, int, const char *psz_dev );
-int * ioctl_GetSectors    ( vlc_object_t *, int, const char *psz_dev );
-int   ioctl_ReadSector    ( vlc_object_t *, int, int, byte_t * );
+#if defined( SYS_DARWIN )
+static CDTOC *darwin_getTOC( vlc_object_t *, const char * );
+static int    darwin_getNumberOfDescriptors( CDTOC * );
+static int    darwin_getNumberOfTracks( CDTOC *, int );
 
+#elif defined( WIN32 )
+static int    win32_vcd_open( vlc_object_t *, const char *, vcddev_t * );
+#endif
index b03b259..9011706 100644 (file)
@@ -2,7 +2,7 @@
  * vcd.c : VCD input module for vlc
  *****************************************************************************
  * Copyright (C) 2000 VideoLAN
- * $Id: vcd.c,v 1.6 2002/10/04 18:07:21 sam Exp $
+ * $Id: vcd.c,v 1.7 2002/10/15 19:56:59 gbazin Exp $
  *
  * Author: Johan Bilien <jobi@via.ecp.fr>
  *
 #   include <unistd.h>
 #endif
 
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <string.h>
-#include <errno.h>
-
-#if defined( WIN32 )
-#   include <io.h>                                                 /* read() */
-#endif
 
 #include "vcd.h"
-#include "cdrom.h"
 
 /* how many blocks VCDRead will read in each loop */
 #define VCD_BLOCKS_ONCE 20
 #define VCD_DATA_ONCE   (VCD_BLOCKS_ONCE * VCD_DATA_SIZE)
 
+/*****************************************************************************
+ * thread_vcd_data_t: VCD information
+ *****************************************************************************/
+typedef struct thread_vcd_data_s
+{
+    vcddev_t    *vcddev;                            /* vcd device descriptor */
+    int         nb_tracks;                          /* Nb of tracks (titles) */
+    int         i_track;                                    /* Current track */
+    int         i_sector;                                  /* Current Sector */
+    int *       p_sectors;                                  /* Track sectors */
+    vlc_bool_t  b_end_of_track;           /* If the end of track was reached */
+
+} thread_vcd_data_t;
+
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
@@ -87,7 +92,6 @@ static int VCDOpen( vlc_object_t *p_this )
     char *                  psz_parser;
     char *                  psz_source;
     char *                  psz_next;
-    struct stat             stat_info;
     thread_vcd_data_t *     p_vcd;
     int                     i;
     input_area_t *          p_area;
@@ -99,6 +103,12 @@ static int VCDOpen( vlc_object_t *p_this )
     p_input->pf_set_area = VCDSetArea;
     p_input->pf_set_program = VCDSetProgram;
 
+#ifdef WIN32
+    /* On Win32 we want the VCD access plugin to be explicitly requested,
+     * we end up with lots of problems otherwise */
+    if( !p_input->psz_access || !*p_input->psz_access ) return( -1 );
+#endif
+
     /* parse the options passed in command line : */
     psz_orig = psz_parser = psz_source = strdup( p_input->psz_name );
     
@@ -137,29 +147,15 @@ static int VCDOpen( vlc_object_t *p_this )
             return -1;
         }
         psz_source = config_GetPsz( p_input, "vcd" );
+        if( !psz_source ) return -1;
     }
 
-    /* test the type of file given */
-    
-    if( stat( psz_source, &stat_info ) == -1 )
-    {
-        msg_Err( p_input, "cannot stat() source `%s' (%s)",
-                          psz_source, strerror(errno));
-        return( -1 );
-    }
-    
-    if( !S_ISBLK(stat_info.st_mode) && !S_ISCHR(stat_info.st_mode))
-    {
-        msg_Warn( p_input, "vcd module discarded (not a valid drive)" );
-        return -1;
-    }
-    
-    
     p_vcd = malloc( sizeof(thread_vcd_data_t) );
 
     if( p_vcd == NULL )
     {
         msg_Err( p_input, "out of memory" );
+        free( psz_source );
         return -1;
     }
     
@@ -177,39 +173,26 @@ static int VCDOpen( vlc_object_t *p_this )
 
     vlc_mutex_unlock( &p_input->stream.stream_lock );
 
-    p_vcd->i_handle = open( psz_source, O_RDONLY | O_NONBLOCK );
-
-    if( p_vcd->i_handle == -1 )
+    if( !(p_vcd->vcddev = ioctl_Open( p_this, psz_source )) )
     {
         msg_Err( p_input, "could not open %s", psz_source );
-        free (p_vcd);
+        free( psz_source );
+        free( p_vcd );
         return -1;
     }
 
     /* We read the Table Of Content information */
-    p_vcd->nb_tracks = ioctl_GetTrackCount( VLC_OBJECT( p_input),
-                                            p_vcd->i_handle, psz_source );
+    p_vcd->nb_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input),
+                                           p_vcd->vcddev, &p_vcd->p_sectors );
+    free( psz_source );
     if( p_vcd->nb_tracks < 0 )
-    {
         msg_Err( p_input, "unable to count tracks" );
-        close( p_vcd->i_handle );
-        free( p_vcd );
-        return -1;
-    }
     else if( p_vcd->nb_tracks <= 1 )
-    {
         msg_Err( p_input, "no movie tracks found" );
-        close( p_vcd->i_handle );
-        free( p_vcd );
-        return -1;
-    }
-
-    p_vcd->p_sectors = ioctl_GetSectors( VLC_OBJECT( p_input),
-                                         p_vcd->i_handle, psz_source );
-    if( p_vcd->p_sectors == NULL )
+    if( p_vcd->nb_tracks <= 1)
     {
-        input_BuffersEnd( p_input, p_input->p_method_data );
-        close( p_vcd->i_handle );
+        //input_BuffersEnd( p_input, p_input->p_method_data ); /* ??? */
+        ioctl_Close( p_this, p_vcd->vcddev );
         free( p_vcd );
         return -1;
     }
@@ -263,7 +246,7 @@ static void VCDClose( vlc_object_t *p_this )
     input_thread_t *   p_input = (input_thread_t *)p_this;
     thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
 
-    close( p_vcd->i_handle );
+    ioctl_Close( p_this, p_vcd->vcddev );
     free( p_vcd );
 }
 
@@ -292,7 +275,7 @@ static int VCDRead( input_thread_t * p_input, byte_t * p_buffer,
 
     for ( i_index = 0 ; i_index < i_blocks ; i_index++ ) 
     {
-        if ( ioctl_ReadSector( VLC_OBJECT(p_input), p_vcd->i_handle,
+        if ( ioctl_ReadSector( VLC_OBJECT(p_input), p_vcd->vcddev,
                     p_vcd->i_sector, p_buffer + i_index * VCD_DATA_SIZE ) < 0 )
         {
             msg_Err( p_input, "could not read sector %d", p_vcd->i_sector );
@@ -321,7 +304,7 @@ static int VCDRead( input_thread_t * p_input, byte_t * p_buffer,
     
     if ( i_len % VCD_DATA_SIZE ) /* this should not happen */
     { 
-        if ( ioctl_ReadSector( VLC_OBJECT(p_input), p_vcd->i_handle,
+        if ( ioctl_ReadSector( VLC_OBJECT(p_input), p_vcd->vcddev,
                                p_vcd->i_sector, p_last_sector ) < 0 )
         {
             msg_Err( p_input, "could not read sector %d", p_vcd->i_sector );
index a15201b..e591e80 100644 (file)
@@ -2,7 +2,7 @@
  * vcd.h: thread structure of the VCD plugin
  *****************************************************************************
  * Copyright (C) 1999-2001 VideoLAN
- * $Id: vcd.h,v 1.1 2002/08/04 17:23:42 sam Exp $
+ * $Id: vcd.h,v 1.2 2002/10/15 19:56:59 gbazin Exp $
  *
  * Author: Johan Bilien <jobi@via.ecp.fr>
  *
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  *****************************************************************************/
 
-/*****************************************************************************
- * thread_vcd_data_t: VCD information
- *****************************************************************************/
-typedef struct thread_vcd_data_s
-{
-    int         i_handle;                                 /* File descriptor */
-    int         nb_tracks;                          /* Nb of tracks (titles) */
-    int         i_track;                                    /* Current track */
-    int         i_sector;                                  /* Current Sector */
-    int *       p_sectors;                                  /* Track sectors */
-    vlc_bool_t  b_end_of_track;           /* If the end of track was reached */
+/* where the data start on a VCD sector */
+#define VCD_DATA_START 24
+/* size of the availablr data on a VCD sector */
+#define VCD_DATA_SIZE 2324
+/* size of a VCD sector, header and tail included */
+#define VCD_SECTOR_SIZE 2352
+/* size of a CD sector */
+#define CD_SECTOR_SIZE 2048
 
-} thread_vcd_data_t;
+#ifndef VCDDEV_T
+typedef struct vcddev_s vcddev_t;
+#endif
 
+/*****************************************************************************
+ * Prototypes
+ *****************************************************************************/
+vcddev_t *ioctl_Open         ( vlc_object_t *, const char * );
+void      ioctl_Close        ( vlc_object_t *, vcddev_t * );
+int       ioctl_GetTracksMap ( vlc_object_t *, const vcddev_t *, int ** );
+int       ioctl_ReadSector   ( vlc_object_t *, const vcddev_t *,
+                              int, byte_t * );