cdrom.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:39k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /****************************************************************************
  2.  * cdrom.c: cdrom tools
  3.  *****************************************************************************
  4.  * Copyright (C) 1998-2001 VideoLAN
  5.  * $Id: cdrom.c 6961 2004-03-05 17:34:23Z sam $
  6.  *
  7.  * Authors: Johan Bilien <jobi@via.ecp.fr>
  8.  *          Gildas Bazin <gbazin@netcourrier.com>
  9.  *          Jon Lech Johansen <jon-vl@nanocrew.net>
  10.  *
  11.  * This program is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  *
  16.  * This program is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  24.  *****************************************************************************/
  25. /*****************************************************************************
  26.  * Preamble
  27.  *****************************************************************************/
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <vlc/vlc.h>
  31. #ifdef HAVE_UNISTD_H
  32. #   include <unistd.h>
  33. #endif
  34. #include <fcntl.h>
  35. #include <sys/types.h>
  36. #include <sys/stat.h>
  37. #include <string.h>
  38. #include <errno.h>
  39. #ifdef HAVE_SYS_IOCTL_H
  40. #   include <sys/ioctl.h>
  41. #endif
  42. #if defined( SYS_BSDI )
  43. #   include <dvd.h>
  44. #elif defined ( SYS_DARWIN )
  45. #   include <CoreFoundation/CFBase.h>
  46. #   include <IOKit/IOKitLib.h>
  47. #   include <IOKit/storage/IOCDTypes.h>
  48. #   include <IOKit/storage/IOCDMedia.h>
  49. #   include <IOKit/storage/IOCDMediaBSDClient.h>
  50. #elif defined( HAVE_SCSIREQ_IN_SYS_SCSIIO_H )
  51. #   include <sys/inttypes.h>
  52. #   include <sys/cdio.h>
  53. #   include <sys/scsiio.h>
  54. #elif defined( HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H )
  55. #   include <sys/cdio.h>
  56. #   include <sys/cdrio.h>
  57. #elif defined( WIN32 )
  58. #   include <windows.h>
  59. #   include <winioctl.h>
  60. #else
  61. #   include <linux/cdrom.h>
  62. #endif
  63. #include "cdrom_internals.h"
  64. #include "cdrom.h"
  65. /*****************************************************************************
  66.  * ioctl_Open: Opens a VCD device or file and returns an opaque handle
  67.  *****************************************************************************/
  68. vcddev_t *ioctl_Open( vlc_object_t *p_this, const char *psz_dev )
  69. {
  70.     int i_ret;
  71.     int b_is_file;
  72.     vcddev_t *p_vcddev;
  73. #ifndef WIN32
  74.     struct stat fileinfo;
  75. #endif
  76.     if( !psz_dev ) return NULL;
  77.     /*
  78.      *  Initialize structure with default values
  79.      */
  80.     p_vcddev = (vcddev_t *)malloc( sizeof(vcddev_t) );
  81.     if( p_vcddev == NULL )
  82.     {
  83.         msg_Err( p_this, "out of memory" );
  84.         return NULL;
  85.     }
  86.     p_vcddev->i_vcdimage_handle = -1;
  87.     p_vcddev->psz_dev = NULL;
  88.     b_is_file = 1;
  89.     /*
  90.      *  Check if we are dealing with a device or a file (vcd image)
  91.      */
  92. #ifdef WIN32
  93.     if( (strlen( psz_dev ) == 2 && psz_dev[1] == ':') )
  94.     {
  95.         b_is_file = 0;
  96.     }
  97. #else
  98.     if( stat( psz_dev, &fileinfo ) < 0 )
  99.     {
  100.         free( p_vcddev );
  101.         return NULL;
  102.     }
  103.     /* Check if this is a block/char device */
  104.     if( S_ISBLK( fileinfo.st_mode ) || S_ISCHR( fileinfo.st_mode ) )
  105.         b_is_file = 0;
  106. #endif
  107.     if( b_is_file )
  108.     {
  109.         i_ret = OpenVCDImage( p_this, psz_dev, p_vcddev );
  110.     }
  111.     else
  112.     {
  113.         /*
  114.          *  open the vcd device
  115.          */
  116. #ifdef WIN32
  117.         i_ret = win32_vcd_open( p_this, psz_dev, p_vcddev );
  118. #else
  119.         p_vcddev->i_device_handle = -1;
  120.         p_vcddev->i_device_handle = open( psz_dev, O_RDONLY | O_NONBLOCK );
  121.         i_ret = (p_vcddev->i_device_handle == -1) ? -1 : 0;
  122. #endif
  123.     }
  124.     if( i_ret == 0 )
  125.     {
  126.         p_vcddev->psz_dev = (char *)strdup( psz_dev );
  127.     }
  128.     else
  129.     {
  130.         free( p_vcddev );
  131.         p_vcddev = NULL;
  132.     }
  133.     return p_vcddev;
  134. }
  135. /*****************************************************************************
  136.  * ioctl_Close: Closes an already opened VCD device or file.
  137.  *****************************************************************************/
  138. void ioctl_Close( vlc_object_t * p_this, vcddev_t *p_vcddev )
  139. {
  140.     if( p_vcddev->psz_dev ) free( p_vcddev->psz_dev );
  141.     if( p_vcddev->i_vcdimage_handle != -1 )
  142.     {
  143.         /*
  144.          *  vcd image mode
  145.          */
  146.         CloseVCDImage( p_this, p_vcddev );
  147.         return;
  148.     }
  149.     /*
  150.      *  vcd device mode
  151.      */
  152. #ifdef WIN32
  153.     if( p_vcddev->h_device_handle )
  154.         CloseHandle( p_vcddev->h_device_handle );
  155.     if( p_vcddev->hASPI )
  156.         FreeLibrary( (HMODULE)p_vcddev->hASPI );
  157. #else
  158.     if( p_vcddev->i_device_handle != -1 )
  159.         close( p_vcddev->i_device_handle );
  160. #endif
  161. }
  162. /*****************************************************************************
  163.  * ioctl_GetTracksMap: Read the Table of Content, fill in the pp_sectors map
  164.  *                     if pp_sectors is not null and return the number of
  165.  *                     tracks available.
  166.  *****************************************************************************/
  167. int ioctl_GetTracksMap( vlc_object_t *p_this, const vcddev_t *p_vcddev,
  168.                         int **pp_sectors )
  169. {
  170.     int i_tracks = 0;
  171.     if( p_vcddev->i_vcdimage_handle != -1 )
  172.     {
  173.         /*
  174.          *  vcd image mode
  175.          */
  176.         i_tracks = p_vcddev->i_tracks;
  177.         if( pp_sectors )
  178.         {
  179.             *pp_sectors = malloc( (i_tracks + 1) * sizeof(int) );
  180.             if( *pp_sectors == NULL )
  181.             {
  182.                 msg_Err( p_this, "out of memory" );
  183.                 return 0;
  184.             }
  185.             memcpy( *pp_sectors, p_vcddev->p_sectors,
  186.                     (i_tracks + 1) * sizeof(int) );
  187.         }
  188.         return i_tracks;
  189.     }
  190.     else
  191.     {
  192.         /*
  193.          *  vcd device mode
  194.          */
  195. #if defined( SYS_DARWIN )
  196.         CDTOC *pTOC;
  197.         int i_descriptors;
  198.         if( ( pTOC = darwin_getTOC( p_this, p_vcddev ) ) == NULL )
  199.         {
  200.             msg_Err( p_this, "failed to get the TOC" );
  201.             return 0;
  202.         }
  203.         i_descriptors = darwin_getNumberOfDescriptors( pTOC );
  204.         i_tracks = darwin_getNumberOfTracks( pTOC, i_descriptors );
  205.         if( pp_sectors )
  206.         {
  207.             int i, i_leadout = -1;
  208.             CDTOCDescriptor *pTrackDescriptors;
  209.             u_char track;
  210.             *pp_sectors = malloc( (i_tracks + 1) * sizeof(int) );
  211.             if( *pp_sectors == NULL )
  212.             {
  213.                 msg_Err( p_this, "out of memory" );
  214.                 darwin_freeTOC( pTOC );
  215.                 return 0;
  216.             }
  217.             pTrackDescriptors = pTOC->descriptors;
  218.             for( i_tracks = 0, i = 0; i <= i_descriptors; i++ )
  219.             {
  220.                 track = pTrackDescriptors[i].point;
  221.                 if( track == 0xA2 )
  222.                     i_leadout = i;
  223.                 if( track > CD_MAX_TRACK_NO || track < CD_MIN_TRACK_NO )
  224.                     continue;
  225.                 (*pp_sectors)[i_tracks++] =
  226.                     CDConvertMSFToLBA( pTrackDescriptors[i].p );
  227.             }
  228.             if( i_leadout == -1 )
  229.             {
  230.                 msg_Err( p_this, "leadout not found" );
  231.                 free( *pp_sectors );
  232.                 darwin_freeTOC( pTOC );
  233.                 return 0;
  234.             }
  235.             /* set leadout sector */
  236.             (*pp_sectors)[i_tracks] =
  237.                 CDConvertMSFToLBA( pTrackDescriptors[i_leadout].p );
  238.         }
  239.         darwin_freeTOC( pTOC );
  240. #elif defined( WIN32 )
  241.         if( p_vcddev->hASPI )
  242.         {
  243.             HANDLE hEvent;
  244.             struct SRB_ExecSCSICmd ssc;
  245.             byte_t p_tocheader[ 4 ];
  246.             /* Create the transfer completion event */
  247.             hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  248.             if( hEvent == NULL )
  249.             {
  250.                 return -1;
  251.             }
  252.             memset( &ssc, 0, sizeof( ssc ) );
  253.             ssc.SRB_Cmd         = SC_EXEC_SCSI_CMD;
  254.             ssc.SRB_Flags       = SRB_DIR_IN | SRB_EVENT_NOTIFY;
  255.             ssc.SRB_HaId        = LOBYTE( p_vcddev->i_sid );
  256.             ssc.SRB_Target      = HIBYTE( p_vcddev->i_sid );
  257.             ssc.SRB_SenseLen    = SENSE_LEN;
  258.             ssc.SRB_PostProc = (LPVOID) hEvent;
  259.             ssc.SRB_CDBLen      = 10;
  260.             /* Operation code */
  261.             ssc.CDBByte[ 0 ] = READ_TOC;
  262.             /* Format */
  263.             ssc.CDBByte[ 2 ] = READ_TOC_FORMAT_TOC;
  264.             /* Starting track */
  265.             ssc.CDBByte[ 6 ] = 0;
  266.             /* Allocation length and buffer */
  267.             ssc.SRB_BufLen = sizeof( p_tocheader );
  268.             ssc.SRB_BufPointer  = p_tocheader;
  269.             ssc.CDBByte[ 7 ] = ( ssc.SRB_BufLen >>  8 ) & 0xff;
  270.             ssc.CDBByte[ 8 ] = ( ssc.SRB_BufLen       ) & 0xff;
  271.             /* Initiate transfer */
  272.             ResetEvent( hEvent );
  273.             p_vcddev->lpSendCommand( (void*) &ssc );
  274.             /* If the command has still not been processed, wait until it's
  275.              * finished */
  276.             if( ssc.SRB_Status == SS_PENDING )
  277.                 WaitForSingleObject( hEvent, INFINITE );
  278.             /* check that the transfer went as planned */
  279.             if( ssc.SRB_Status != SS_COMP )
  280.             {
  281.                 CloseHandle( hEvent );
  282.                 return 0;
  283.             }
  284.             i_tracks = p_tocheader[3] - p_tocheader[2] + 1;
  285.             if( pp_sectors )
  286.             {
  287.                 int i, i_toclength;
  288.                 byte_t *p_fulltoc;
  289.                 i_toclength = 4 /* header */ + p_tocheader[0] +
  290.                               ((unsigned int)p_tocheader[1] << 8);
  291.                 p_fulltoc = malloc( i_toclength );
  292.                 *pp_sectors = malloc( (i_tracks + 1) * sizeof(int) );
  293.                 if( *pp_sectors == NULL || p_fulltoc == NULL )
  294.                 {
  295.                     if( *pp_sectors ) free( *pp_sectors );
  296.                     if( p_fulltoc ) free( p_fulltoc );
  297.                     msg_Err( p_this, "out of memory" );
  298.                     CloseHandle( hEvent );
  299.                     return 0;
  300.                 }
  301.                 /* Allocation length and buffer */
  302.                 ssc.SRB_BufLen = i_toclength;
  303.                 ssc.SRB_BufPointer  = p_fulltoc;
  304.                 ssc.CDBByte[ 7 ] = ( ssc.SRB_BufLen >>  8 ) & 0xff;
  305.                 ssc.CDBByte[ 8 ] = ( ssc.SRB_BufLen       ) & 0xff;
  306.                 /* Initiate transfer */
  307.                 ResetEvent( hEvent );
  308.                 p_vcddev->lpSendCommand( (void*) &ssc );
  309.                 /* If the command has still not been processed, wait until it's
  310.                  * finished */
  311.                 if( ssc.SRB_Status == SS_PENDING )
  312.                     WaitForSingleObject( hEvent, INFINITE );
  313.                 /* check that the transfer went as planned */
  314.                 if( ssc.SRB_Status != SS_COMP )
  315.                     i_tracks = 0;
  316.                 for( i = 0 ; i <= i_tracks ; i++ )
  317.                 {
  318.                     int i_index = 8 + 8 * i;
  319.                     (*pp_sectors)[ i ] = ((int)p_fulltoc[ i_index ] << 24) +
  320.                                          ((int)p_fulltoc[ i_index+1 ] << 16) +
  321.                                          ((int)p_fulltoc[ i_index+2 ] << 8) +
  322.                                          (int)p_fulltoc[ i_index+3 ];
  323.                     msg_Dbg( p_this, "p_sectors: %i, %i", i, (*pp_sectors)[i]);
  324.                 }
  325.                 free( p_fulltoc );
  326.             }
  327.             CloseHandle( hEvent );
  328.         }
  329.         else
  330.         {
  331.             DWORD dwBytesReturned;
  332.             CDROM_TOC cdrom_toc;
  333.             if( DeviceIoControl( p_vcddev->h_device_handle,
  334.                                  IOCTL_CDROM_READ_TOC,
  335.                                  NULL, 0, &cdrom_toc, sizeof(CDROM_TOC),
  336.                                  &dwBytesReturned, NULL ) == 0 )
  337.             {
  338.                 msg_Err( p_this, "could not read TOCHDR" );
  339.                 return 0;
  340.             }
  341.             i_tracks = cdrom_toc.LastTrack - cdrom_toc.FirstTrack + 1;
  342.             if( pp_sectors )
  343.             {
  344.                 int i;
  345.                 *pp_sectors = malloc( (i_tracks + 1) * sizeof(int) );
  346.                 if( *pp_sectors == NULL )
  347.                 {
  348.                     msg_Err( p_this, "out of memory" );
  349.                     return 0;
  350.                 }
  351.                 for( i = 0 ; i <= i_tracks ; i++ )
  352.                 {
  353.                     (*pp_sectors)[ i ] = MSF_TO_LBA2(
  354.                                            cdrom_toc.TrackData[i].Address[1],
  355.                                            cdrom_toc.TrackData[i].Address[2],
  356.                                            cdrom_toc.TrackData[i].Address[3] );
  357.                     msg_Dbg( p_this, "p_sectors: %i, %i", i, (*pp_sectors)[i]);
  358.                 }
  359.             }
  360.         }
  361. #elif defined( HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H ) 
  362.        || defined( HAVE_SCSIREQ_IN_SYS_SCSIIO_H )
  363.         struct ioc_toc_header tochdr;
  364.         struct ioc_read_toc_entry toc_entries;
  365.         if( ioctl( p_vcddev->i_device_handle, CDIOREADTOCHEADER, &tochdr )
  366.             == -1 )
  367.         {
  368.             msg_Err( p_this, "could not read TOCHDR" );
  369.             return 0;
  370.         }
  371.         i_tracks = tochdr.ending_track - tochdr.starting_track + 1;
  372.         if( pp_sectors )
  373.         {
  374.              int i;
  375.              *pp_sectors = malloc( (i_tracks + 1) * sizeof(int) );
  376.              if( *pp_sectors == NULL )
  377.              {
  378.                  msg_Err( p_this, "out of memory" );
  379.                  return NULL;
  380.              }
  381.              toc_entries.address_format = CD_LBA_FORMAT;
  382.              toc_entries.starting_track = 0;
  383.              toc_entries.data_len = ( i_tracks + 1 ) *
  384.                                         sizeof( struct cd_toc_entry );
  385.              toc_entries.data = (struct cd_toc_entry *)
  386.                                     malloc( toc_entries.data_len );
  387.              if( toc_entries.data == NULL )
  388.              {
  389.                  msg_Err( p_this, "out of memory" );
  390.                  free( *pp_sectors );
  391.                  return 0;
  392.              }
  393.              /* Read the TOC */
  394.              if( ioctl( p_vcddev->i_device_handle, CDIOREADTOCENTRYS,
  395.                         &toc_entries ) == -1 )
  396.              {
  397.                  msg_Err( p_this, "could not read the TOC" );
  398.                  free( *pp_sectors );
  399.                  free( toc_entries.data );
  400.                  return 0;
  401.              }
  402.              /* Fill the p_sectors structure with the track/sector matches */
  403.              for( i = 0 ; i <= i_tracks ; i++ )
  404.              {
  405. #if defined( HAVE_SCSIREQ_IN_SYS_SCSIIO_H )
  406.                  /* FIXME: is this ok? */
  407.                  (*pp_sectors)[ i ] = toc_entries.data[i].addr.lba;
  408. #else
  409.                  (*pp_sectors)[ i ] = ntohl( toc_entries.data[i].addr.lba );
  410. #endif
  411.              }
  412.         }
  413. #else
  414.         struct cdrom_tochdr   tochdr;
  415.         struct cdrom_tocentry tocent;
  416.         /* First we read the TOC header */
  417.         if( ioctl( p_vcddev->i_device_handle, CDROMREADTOCHDR, &tochdr )
  418.             == -1 )
  419.         {
  420.             msg_Err( p_this, "could not read TOCHDR" );
  421.             return 0;
  422.         }
  423.         i_tracks = tochdr.cdth_trk1 - tochdr.cdth_trk0 + 1;
  424.         if( pp_sectors )
  425.         {
  426.             int i;
  427.             *pp_sectors = malloc( (i_tracks + 1) * sizeof(int) );
  428.             if( *pp_sectors == NULL )
  429.             {
  430.                 msg_Err( p_this, "out of memory" );
  431.                 return 0;
  432.             }
  433.             /* Fill the p_sectors structure with the track/sector matches */
  434.             for( i = 0 ; i <= i_tracks ; i++ )
  435.             {
  436.                 tocent.cdte_format = CDROM_LBA;
  437.                 tocent.cdte_track =
  438.                     ( i == i_tracks ) ? CDROM_LEADOUT : tochdr.cdth_trk0 + i;
  439.                 if( ioctl( p_vcddev->i_device_handle, CDROMREADTOCENTRY,
  440.                            &tocent ) == -1 )
  441.                 {
  442.                     msg_Err( p_this, "could not read TOCENTRY" );
  443.                     free( *pp_sectors );
  444.                     return 0;
  445.                 }
  446.                 (*pp_sectors)[ i ] = tocent.cdte_addr.lba;
  447.             }
  448.         }
  449. #endif
  450.         return i_tracks;
  451.     }
  452. }
  453. /****************************************************************************
  454.  * ioctl_ReadSector: Read VCD or CDDA sectors
  455.  ****************************************************************************/
  456. int ioctl_ReadSectors( vlc_object_t *p_this, const vcddev_t *p_vcddev,
  457.                        int i_sector, byte_t * p_buffer, int i_nb, int i_type )
  458. {
  459.     byte_t *p_block;
  460.     int i;
  461.     if( i_type == VCD_TYPE ) p_block = malloc( VCD_SECTOR_SIZE * i_nb );
  462.     else p_block = p_buffer;
  463.     if( p_vcddev->i_vcdimage_handle != -1 )
  464.     {
  465.         /*
  466.          *  vcd image mode
  467.          */
  468.         if( lseek( p_vcddev->i_vcdimage_handle, i_sector * VCD_SECTOR_SIZE,
  469.                    SEEK_SET ) == -1 )
  470.         {
  471.             msg_Err( p_this, "Could not lseek to sector %d", i_sector );
  472.             if( i_type == VCD_TYPE ) free( p_block );
  473.             return -1;
  474.         }
  475.         if( read( p_vcddev->i_vcdimage_handle, p_block, VCD_SECTOR_SIZE * i_nb)
  476.             == -1 )
  477.         {
  478.             msg_Err( p_this, "Could not read sector %d", i_sector );
  479.             if( i_type == VCD_TYPE ) free( p_block );
  480.             return -1;
  481.         }
  482.     }
  483.     else
  484.     {
  485.         /*
  486.          *  vcd device mode
  487.          */
  488. #if defined( SYS_DARWIN )
  489.         dk_cd_read_t cd_read;
  490.         memset( &cd_read, 0, sizeof(cd_read) );
  491.         cd_read.offset = i_sector * VCD_SECTOR_SIZE;
  492.         cd_read.sectorArea = kCDSectorAreaSync | kCDSectorAreaHeader |
  493.                              kCDSectorAreaSubHeader | kCDSectorAreaUser |
  494.                              kCDSectorAreaAuxiliary;
  495.         cd_read.sectorType = kCDSectorTypeUnknown;
  496.         cd_read.buffer = p_block;
  497.         cd_read.bufferLength = VCD_SECTOR_SIZE * i_nb;
  498.         if( ioctl( p_vcddev->i_device_handle, DKIOCCDREAD, &cd_read ) == -1 )
  499.         {
  500.             msg_Err( p_this, "could not read block %d", i_sector );
  501.             if( i_type == VCD_TYPE ) free( p_block );
  502.             return -1;
  503.         }
  504. #elif defined( WIN32 )
  505.         if( p_vcddev->hASPI )
  506.         {
  507.             HANDLE hEvent;
  508.             struct SRB_ExecSCSICmd ssc;
  509.             /* Create the transfer completion event */
  510.             hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  511.             if( hEvent == NULL )
  512.             {
  513.                 if( i_type == VCD_TYPE ) free( p_block );
  514.                 return -1;
  515.             }
  516.             memset( &ssc, 0, sizeof( ssc ) );
  517.             ssc.SRB_Cmd         = SC_EXEC_SCSI_CMD;
  518.             ssc.SRB_Flags       = SRB_DIR_IN | SRB_EVENT_NOTIFY;
  519.             ssc.SRB_HaId        = LOBYTE( p_vcddev->i_sid );
  520.             ssc.SRB_Target      = HIBYTE( p_vcddev->i_sid );
  521.             ssc.SRB_SenseLen    = SENSE_LEN;
  522.             ssc.SRB_PostProc = (LPVOID) hEvent;
  523.             ssc.SRB_CDBLen      = 12;
  524.             /* Operation code */
  525.             ssc.CDBByte[ 0 ] = READ_CD;
  526.             /* Sector type */
  527.             ssc.CDBByte[ 1 ] = i_type == VCD_TYPE ? SECTOR_TYPE_MODE2_FORM2 :
  528.                                                     SECTOR_TYPE_CDDA;
  529.             /* Start of LBA */
  530.             ssc.CDBByte[ 2 ] = ( i_sector >> 24 ) & 0xff;
  531.             ssc.CDBByte[ 3 ] = ( i_sector >> 16 ) & 0xff;
  532.             ssc.CDBByte[ 4 ] = ( i_sector >>  8 ) & 0xff;
  533.             ssc.CDBByte[ 5 ] = ( i_sector       ) & 0xff;
  534.             /* Transfer length */
  535.             ssc.CDBByte[ 6 ] = ( i_nb >> 16 ) & 0xff;
  536.             ssc.CDBByte[ 7 ] = ( i_nb >> 8  ) & 0xff;
  537.             ssc.CDBByte[ 8 ] = ( i_nb       ) & 0xff;
  538.             /* Data selection */
  539.             ssc.CDBByte[ 9 ] = i_type == VCD_TYPE ? READ_CD_RAW_MODE2 :
  540.                                                     READ_CD_USERDATA;
  541.             /* Result buffer */
  542.             ssc.SRB_BufPointer  = p_block;
  543.             ssc.SRB_BufLen = VCD_SECTOR_SIZE * i_nb;
  544.             /* Initiate transfer */
  545.             ResetEvent( hEvent );
  546.             p_vcddev->lpSendCommand( (void*) &ssc );
  547.             /* If the command has still not been processed, wait until it's
  548.              * finished */
  549.             if( ssc.SRB_Status == SS_PENDING )
  550.             {
  551.                 WaitForSingleObject( hEvent, INFINITE );
  552.             }
  553.             CloseHandle( hEvent );
  554.             /* check that the transfer went as planned */
  555.             if( ssc.SRB_Status != SS_COMP )
  556.             {
  557.                 if( i_type == VCD_TYPE ) free( p_block );
  558.                 return -1;
  559.             }
  560.         }
  561.         else
  562.         {
  563.             DWORD dwBytesReturned;
  564.             RAW_READ_INFO cdrom_raw;
  565.             /* Initialize CDROM_RAW_READ structure */
  566.             cdrom_raw.DiskOffset.QuadPart = CD_SECTOR_SIZE * i_sector;
  567.             cdrom_raw.SectorCount = i_nb;
  568.             cdrom_raw.TrackMode =  i_type == VCD_TYPE ? XAForm2 : CDDA;
  569.             if( DeviceIoControl( p_vcddev->h_device_handle,
  570.                                  IOCTL_CDROM_RAW_READ, &cdrom_raw,
  571.                                  sizeof(RAW_READ_INFO), p_block,
  572.                                  VCD_SECTOR_SIZE * i_nb, &dwBytesReturned,
  573.                                  NULL ) == 0 )
  574.             {
  575.                 if( i_type == VCD_TYPE )
  576.                 {
  577.                     /* Retry in YellowMode2 */
  578.                     cdrom_raw.TrackMode = YellowMode2;
  579.                     if( DeviceIoControl( p_vcddev->h_device_handle,
  580.                                  IOCTL_CDROM_RAW_READ, &cdrom_raw,
  581.                                  sizeof(RAW_READ_INFO), p_block,
  582.                                  VCD_SECTOR_SIZE * i_nb, &dwBytesReturned,
  583.                                  NULL ) == 0 )
  584.                     {
  585.                         free( p_block );
  586.                         return -1;
  587.                     }
  588.                 }
  589.                 else return -1;
  590.             }
  591.         }
  592. #elif defined( HAVE_SCSIREQ_IN_SYS_SCSIIO_H )
  593.         struct scsireq  sc;
  594.         int i_ret;
  595.         memset( &sc, 0, sizeof(sc) );
  596.         sc.cmd[0] = 0xBE;
  597.         sc.cmd[1] = i_type == VCD_TYPE ? SECTOR_TYPE_MODE2_FORM2:
  598.                                          SECTOR_TYPE_CDDA;
  599.         sc.cmd[2] = (i_sector >> 24) & 0xff;
  600.         sc.cmd[3] = (i_sector >> 16) & 0xff;
  601.         sc.cmd[4] = (i_sector >>  8) & 0xff;
  602.         sc.cmd[5] = (i_sector >>  0) & 0xff;
  603.         sc.cmd[6] = (i_nb >> 16) & 0xff;
  604.         sc.cmd[7] = (i_nb >>  8) & 0xff;
  605.         sc.cmd[8] = (i_nb      ) & 0xff;
  606.         sc.cmd[9] = i_type == VCD_TYPE ? READ_CD_RAW_MODE2 : READ_CD_USERDATA;
  607.         sc.cmd[10] = 0; /* sub channel */
  608.         sc.cmdlen = 12;
  609.         sc.databuf = (caddr_t)p_block;
  610.         sc.datalen = VCD_SECTOR_SIZE * i_nb;
  611.         sc.senselen = sizeof( sc.sense );
  612.         sc.flags = SCCMD_READ;
  613.         sc.timeout = 10000;
  614.         i_ret = ioctl( i_fd, SCIOCCOMMAND, &sc );
  615.         if( i_ret == -1 )
  616.         {
  617.             msg_Err( p_this, "SCIOCCOMMAND failed" );
  618.             if( i_type == VCD_TYPE ) free( p_block );
  619.             return -1;
  620.         }
  621.         if( sc.retsts || sc.error )
  622.         {
  623.             msg_Err( p_this, "SCSI command failed: status %d error %dn",
  624.                              sc.retsts, sc.error );
  625.             if( i_type == VCD_TYPE ) free( p_block );
  626.            return -1;
  627.         }
  628. #elif defined( HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H )
  629.         int i_size = VCD_SECTOR_SIZE;
  630.         if( ioctl( p_vcddev->i_device_handle, CDRIOCSETBLOCKSIZE, &i_size )
  631.             == -1 )
  632.         {
  633.             msg_Err( p_this, "Could not set block size" );
  634.             if( i_type == VCD_TYPE ) free( p_block );
  635.             return( -1 );
  636.         }
  637.         if( lseek( p_vcddev->i_device_handle,
  638.                    i_sector * VCD_SECTOR_SIZE, SEEK_SET ) == -1 )
  639.         {
  640.             msg_Err( p_this, "Could not lseek to sector %d", i_sector );
  641.             if( i_type == VCD_TYPE ) free( p_block );
  642.             return( -1 );
  643.         }
  644.         if( read( p_vcddev->i_device_handle,
  645.                   p_block, VCD_SECTOR_SIZE * i_nb ) == -1 )
  646.         {
  647.             msg_Err( p_this, "Could not read sector %d", i_sector );
  648.             if( i_type == VCD_TYPE ) free( p_block );
  649.             return( -1 );
  650.         }
  651. #else
  652.         for( i = 0; i < i_nb; i++ )
  653.         {
  654.             int i_dummy = i_sector + i + 2 * CD_FRAMES;
  655. #define p_msf ((struct cdrom_msf0 *)(p_block + i * VCD_SECTOR_SIZE))
  656.             p_msf->minute =   i_dummy / (CD_FRAMES * CD_SECS);
  657.             p_msf->second = ( i_dummy % (CD_FRAMES * CD_SECS) ) / CD_FRAMES;
  658.             p_msf->frame =  ( i_dummy % (CD_FRAMES * CD_SECS) ) % CD_FRAMES;
  659. #undef p_msf
  660.             if( ioctl( p_vcddev->i_device_handle, CDROMREADRAW,
  661.                        p_block + i * VCD_SECTOR_SIZE ) == -1 )
  662.             {
  663.                 msg_Err( p_this, "could not read block %i from disc",
  664.                          i_sector );
  665.                 if( i == 0 )
  666.                 {
  667.                     if( i_type == VCD_TYPE ) free( p_block );
  668.                     return( -1 );
  669.                 }
  670.                 else break;
  671.             }
  672.         }
  673. #endif
  674.     }
  675.     /* For VCDs, we don't want to keep the header and footer of the
  676.      * sectors read */
  677.     if( i_type == VCD_TYPE )
  678.     {
  679.         for( i = 0; i < i_nb; i++ )
  680.         {
  681.             memcpy( p_buffer + i * VCD_DATA_SIZE,
  682.                     p_block + i * VCD_SECTOR_SIZE + VCD_DATA_START,
  683.                     VCD_DATA_SIZE );
  684.         }
  685.         free( p_block );
  686.     }
  687.     return( 0 );
  688. }
  689. /****************************************************************************
  690.  * Private functions
  691.  ****************************************************************************/
  692. /****************************************************************************
  693.  * OpenVCDImage: try to open a vcd image from a .cue file
  694.  ****************************************************************************/
  695. static int OpenVCDImage( vlc_object_t * p_this, const char *psz_dev,
  696.                          vcddev_t *p_vcddev )
  697. {
  698.     int i_ret = -1;
  699.     char *p_pos;
  700.     char *psz_vcdfile = NULL;
  701.     char *psz_cuefile = NULL;
  702.     FILE *cuefile;
  703.     char line[1024];
  704.     /* Check if we are dealing with a .cue file */
  705.     p_pos = strrchr( psz_dev, '.' );
  706.     if( p_pos && !strcmp( p_pos, ".cue" ) )
  707.     {
  708.         psz_cuefile = strdup( psz_dev );
  709.     }
  710.     else
  711.     {
  712.         /* psz_dev must be the actual vcd file. Let's assume there's a .cue
  713.          * file with the same filename */
  714.         if( p_pos )
  715.         {
  716.             psz_cuefile = malloc( p_pos - psz_dev + 5 /* ".cue" */ );
  717.             strncpy( psz_cuefile, psz_dev, p_pos - psz_dev );
  718.             strcpy( psz_cuefile + (p_pos - psz_dev), ".cue");
  719.         }
  720.         else
  721.         {
  722.             psz_cuefile = malloc( strlen(psz_dev) + 5 /* ".cue" */ );
  723.             sprintf( psz_cuefile, "%s.cue", psz_dev );
  724.         }
  725.     }
  726.     /* Open the cue file and try to parse it */
  727.     msg_Dbg( p_this,"trying .cue file: %s", psz_cuefile );
  728.     cuefile = fopen( psz_cuefile, "rt" );
  729.     if( cuefile && fscanf( cuefile, "FILE %c", line ) &&
  730.         fgets( line, 1024, cuefile ) )
  731.     {
  732.         p_pos = strchr( line, '"' );
  733.         if( p_pos )
  734.         {
  735.             *p_pos = 0;
  736.             /* Take care of path standardization */
  737.             if( *line != '/' && ((p_pos = strrchr( psz_cuefile, '/' ))
  738.                 || (p_pos = strrchr( psz_cuefile, '\' ) )) )
  739.             {
  740.                 psz_vcdfile = malloc( strlen(line) +
  741.                                       (p_pos - psz_cuefile + 1) + 1 );
  742.                 strncpy( psz_vcdfile, psz_cuefile, (p_pos - psz_cuefile + 1) );
  743.                 strcpy( psz_vcdfile + (p_pos - psz_cuefile + 1), line );
  744.             }
  745.             else psz_vcdfile = strdup( line );
  746.         }
  747.     }
  748.     if( psz_vcdfile )
  749.     {
  750.         msg_Dbg( p_this,"using vcd image file: %s", psz_vcdfile );
  751.         p_vcddev->i_vcdimage_handle = open( psz_vcdfile,
  752.                                         O_RDONLY | O_NONBLOCK | O_BINARY );
  753.         i_ret = (p_vcddev->i_vcdimage_handle == -1) ? -1 : 0;
  754.     }
  755.     /* Try to parse the i_tracks and p_sectors info so we can just forget
  756.      * about the cuefile */
  757.     if( i_ret == 0 )
  758.     {
  759.         int p_sectors[100];
  760.         int i_tracks = 0;
  761.         int i_num;
  762.         char psz_dummy[10];
  763.         while( fgets( line, 1024, cuefile ) )
  764.         {
  765.             /* look for a TRACK line */
  766.             if( !sscanf( line, "%9s", psz_dummy ) ||
  767.                 strcmp(psz_dummy, "TRACK") )
  768.                 continue;
  769.             /* look for an INDEX line */
  770.             while( fgets( line, 1024, cuefile ) )
  771.             {
  772.                 int i_min, i_sec, i_frame;
  773.                 if( (sscanf( line, "%9s %2u %2u:%2u:%2u", psz_dummy, &i_num,
  774.                             &i_min, &i_sec, &i_frame ) != 5) || (i_num != 1) )
  775.                     continue;
  776.                 i_tracks++;
  777.                 p_sectors[i_tracks - 1] = MSF_TO_LBA(i_min, i_sec, i_frame);
  778.                 msg_Dbg( p_this, "vcd track %i begins at sector:%i",
  779.                          i_tracks - 1, p_sectors[i_tracks - 1] );
  780.                 break;
  781.             }
  782.         }
  783.         /* fill in the last entry */
  784.         p_sectors[i_tracks] = lseek(p_vcddev->i_vcdimage_handle, 0, SEEK_END)
  785.                                 / VCD_SECTOR_SIZE;
  786.         msg_Dbg( p_this, "vcd track %i, begins at sector:%i",
  787.                  i_tracks, p_sectors[i_tracks] );
  788.         p_vcddev->i_tracks = i_tracks;
  789.         p_vcddev->p_sectors = malloc( (i_tracks + 1) * sizeof(int) );
  790.         memcpy( p_vcddev->p_sectors, p_sectors, (i_tracks + 1) * sizeof(int) );
  791.     }
  792.     if( cuefile ) fclose( cuefile );
  793.     if( psz_cuefile ) free( psz_cuefile );
  794.     if( psz_vcdfile ) free( psz_vcdfile );
  795.     return i_ret;
  796. }
  797. /****************************************************************************
  798.  * CloseVCDImage: closes a vcd image opened by OpenVCDImage
  799.  ****************************************************************************/
  800. static void CloseVCDImage( vlc_object_t * p_this, vcddev_t *p_vcddev )
  801. {
  802.     if( p_vcddev->i_vcdimage_handle != -1 )
  803.         close( p_vcddev->i_vcdimage_handle );
  804.     else
  805.         return;
  806.     if( p_vcddev->p_sectors )
  807.         free( p_vcddev->p_sectors );
  808. }
  809. #if defined( SYS_DARWIN )
  810. /****************************************************************************
  811.  * darwin_getTOC: get the TOC
  812.  ****************************************************************************/
  813. static CDTOC *darwin_getTOC( vlc_object_t * p_this, const vcddev_t *p_vcddev )
  814. {
  815.     mach_port_t port;
  816.     char *psz_devname;
  817.     kern_return_t ret;
  818.     CDTOC *pTOC = NULL;
  819.     io_iterator_t iterator;
  820.     io_registry_entry_t service;
  821.     CFMutableDictionaryRef properties;
  822.     CFDataRef data;
  823.     /* get the device name */
  824.     if( ( psz_devname = strrchr( p_vcddev->psz_dev, '/') ) != NULL )
  825.         ++psz_devname;
  826.     else
  827.         psz_devname = p_vcddev->psz_dev;
  828.     /* unraw the device name */
  829.     if( *psz_devname == 'r' )
  830.         ++psz_devname;
  831.     /* get port for IOKit communication */
  832.     if( ( ret = IOMasterPort( MACH_PORT_NULL, &port ) ) != KERN_SUCCESS )
  833.     {
  834.         msg_Err( p_this, "IOMasterPort: 0x%08x", ret );
  835.         return( NULL );
  836.     }
  837.     /* get service iterator for the device */
  838.     if( ( ret = IOServiceGetMatchingServices( 
  839.                     port, IOBSDNameMatching( port, 0, psz_devname ),
  840.                     &iterator ) ) != KERN_SUCCESS )
  841.     {
  842.         msg_Err( p_this, "IOServiceGetMatchingServices: 0x%08x", ret );
  843.         return( NULL );
  844.     }
  845.     /* first service */
  846.     service = IOIteratorNext( iterator );
  847.     IOObjectRelease( iterator );
  848.     /* search for kIOCDMediaClass */ 
  849.     while( service && !IOObjectConformsTo( service, kIOCDMediaClass ) )
  850.     {
  851.         if( ( ret = IORegistryEntryGetParentIterator( service, 
  852.                         kIOServicePlane, &iterator ) ) != KERN_SUCCESS )
  853.         {
  854.             msg_Err( p_this, "IORegistryEntryGetParentIterator: 0x%08x", ret );
  855.             IOObjectRelease( service );
  856.             return( NULL );
  857.         }
  858.         IOObjectRelease( service );
  859.         service = IOIteratorNext( iterator );
  860.         IOObjectRelease( iterator );
  861.     }
  862.     if( service == NULL )
  863.     {
  864.         msg_Err( p_this, "search for kIOCDMediaClass came up empty" );
  865.         return( NULL );
  866.     }
  867.     /* create a CF dictionary containing the TOC */
  868.     if( ( ret = IORegistryEntryCreateCFProperties( service, &properties,
  869.                     kCFAllocatorDefault, kNilOptions ) ) != KERN_SUCCESS )
  870.     {
  871.         msg_Err( p_this, "IORegistryEntryCreateCFProperties: 0x%08x", ret );
  872.         IOObjectRelease( service );
  873.         return( NULL );
  874.     }
  875.     /* get the TOC from the dictionary */
  876.     if( ( data = (CFDataRef) CFDictionaryGetValue( properties,
  877.                                     CFSTR(kIOCDMediaTOCKey) ) ) != NULL )
  878.     {
  879.         CFRange range;
  880.         CFIndex buf_len;
  881.         buf_len = CFDataGetLength( data ) + 1;
  882.         range = CFRangeMake( 0, buf_len );
  883.         if( ( pTOC = (CDTOC *)malloc( buf_len ) ) != NULL )
  884.         {
  885.             CFDataGetBytes( data, range, (u_char *)pTOC );
  886.         }
  887.     }
  888.     else
  889.     {
  890.         msg_Err( p_this, "CFDictionaryGetValue failed" );
  891.     }
  892.     CFRelease( properties );
  893.     IOObjectRelease( service ); 
  894.     return( pTOC ); 
  895. }
  896. /****************************************************************************
  897.  * darwin_getNumberOfDescriptors: get number of descriptors in TOC 
  898.  ****************************************************************************/
  899. static int darwin_getNumberOfDescriptors( CDTOC *pTOC )
  900. {
  901.     int i_descriptors;
  902.     /* get TOC length */
  903.     i_descriptors = pTOC->length;
  904.     /* remove the first and last session */
  905.     i_descriptors -= ( sizeof(pTOC->sessionFirst) +
  906.                        sizeof(pTOC->sessionLast) );
  907.     /* divide the length by the size of a single descriptor */
  908.     i_descriptors /= sizeof(CDTOCDescriptor);
  909.     return( i_descriptors );
  910. }
  911. /****************************************************************************
  912.  * darwin_getNumberOfTracks: get number of tracks in TOC 
  913.  ****************************************************************************/
  914. static int darwin_getNumberOfTracks( CDTOC *pTOC, int i_descriptors )
  915. {
  916.     u_char track;
  917.     int i, i_tracks = 0; 
  918.     CDTOCDescriptor *pTrackDescriptors;
  919.     pTrackDescriptors = pTOC->descriptors;
  920.     for( i = i_descriptors; i >= 0; i-- )
  921.     {
  922.         track = pTrackDescriptors[i].point;
  923.         if( track > CD_MAX_TRACK_NO || track < CD_MIN_TRACK_NO )
  924.             continue;
  925.         i_tracks++; 
  926.     }
  927.     return( i_tracks );
  928. }
  929. #endif /* SYS_DARWIN */
  930. #if defined( WIN32 )
  931. /*****************************************************************************
  932.  * win32_vcd_open: open vcd drive
  933.  *****************************************************************************
  934.  * Load and use aspi if it is available, otherwise use IOCTLs on WinNT/2K/XP.
  935.  *****************************************************************************/
  936. static int win32_vcd_open( vlc_object_t * p_this, const char *psz_dev,
  937.                            vcddev_t *p_vcddev )
  938. {
  939.     /* Initializations */
  940.     p_vcddev->h_device_handle = NULL;
  941.     p_vcddev->i_sid = 0;
  942.     p_vcddev->hASPI = 0;
  943.     p_vcddev->lpSendCommand = 0;
  944.     if( WIN_NT )
  945.     {
  946.         char psz_win32_drive[7];
  947.         msg_Dbg( p_this, "using winNT/2K/XP ioctl layer" );
  948.         sprintf( psz_win32_drive, "\\.\%c:", psz_dev[0] );
  949.         p_vcddev->h_device_handle = CreateFile( psz_win32_drive, GENERIC_READ,
  950.                                             FILE_SHARE_READ | FILE_SHARE_WRITE,
  951.                                             NULL, OPEN_EXISTING,
  952.                                             FILE_FLAG_NO_BUFFERING |
  953.                                             FILE_FLAG_RANDOM_ACCESS, NULL );
  954.         return (p_vcddev->h_device_handle == NULL) ? -1 : 0;
  955.     }
  956.     else
  957.     {
  958.         HMODULE hASPI = NULL;
  959.         long (*lpGetSupport)( void ) = NULL;
  960.         long (*lpSendCommand)( void* ) = NULL;
  961.         DWORD dwSupportInfo;
  962.         int i, j, i_hostadapters;
  963.         char c_drive = psz_dev[0];
  964.         hASPI = LoadLibrary( "wnaspi32.dll" );
  965.         if( hASPI != NULL )
  966.         {
  967.             (FARPROC) lpGetSupport = GetProcAddress( hASPI,
  968.                                                      "GetASPI32SupportInfo" );
  969.             (FARPROC) lpSendCommand = GetProcAddress( hASPI,
  970.                                                       "SendASPI32Command" );
  971.         }
  972.         if( hASPI == NULL || lpGetSupport == NULL || lpSendCommand == NULL )
  973.         {
  974.             msg_Dbg( p_this,
  975.                      "unable to load aspi or get aspi function pointers" );
  976.             if( hASPI ) FreeLibrary( hASPI );
  977.             return -1;
  978.         }
  979.         /* ASPI support seems to be there */
  980.         dwSupportInfo = lpGetSupport();
  981.         if( HIBYTE( LOWORD ( dwSupportInfo ) ) == SS_NO_ADAPTERS )
  982.         {
  983.             msg_Dbg( p_this, "no host adapters found (aspi)" );
  984.             FreeLibrary( hASPI );
  985.             return -1;
  986.         }
  987.         if( HIBYTE( LOWORD ( dwSupportInfo ) ) != SS_COMP )
  988.         {
  989.             msg_Dbg( p_this, "unable to initalize aspi layer" );
  990.             FreeLibrary( hASPI );
  991.             return -1;
  992.         }
  993.         i_hostadapters = LOBYTE( LOWORD( dwSupportInfo ) );
  994.         if( i_hostadapters == 0 )
  995.         {
  996.             FreeLibrary( hASPI );
  997.             return -1;
  998.         }
  999.         c_drive = c_drive > 'Z' ? c_drive - 'a' : c_drive - 'A';
  1000.         for( i = 0; i < i_hostadapters; i++ )
  1001.         {
  1002.           for( j = 0; j < 15; j++ )
  1003.           {
  1004.               struct SRB_GetDiskInfo srbDiskInfo;
  1005.               srbDiskInfo.SRB_Cmd         = SC_GET_DISK_INFO;
  1006.               srbDiskInfo.SRB_HaId        = i;
  1007.               srbDiskInfo.SRB_Flags       = 0;
  1008.               srbDiskInfo.SRB_Hdr_Rsvd    = 0;
  1009.               srbDiskInfo.SRB_Target      = j;
  1010.               srbDiskInfo.SRB_Lun         = 0;
  1011.               lpSendCommand( (void*) &srbDiskInfo );
  1012.               if( (srbDiskInfo.SRB_Status == SS_COMP) &&
  1013.                   (srbDiskInfo.SRB_Int13HDriveInfo == c_drive) )
  1014.               {
  1015.                   /* Make sure this is a cdrom device */
  1016.                   struct SRB_GDEVBlock   srbGDEVBlock;
  1017.                   memset( &srbGDEVBlock, 0, sizeof(struct SRB_GDEVBlock) );
  1018.                   srbGDEVBlock.SRB_Cmd    = SC_GET_DEV_TYPE;
  1019.                   srbGDEVBlock.SRB_HaId   = i;
  1020.                   srbGDEVBlock.SRB_Target = j;
  1021.                   lpSendCommand( (void*) &srbGDEVBlock );
  1022.                   if( ( srbGDEVBlock.SRB_Status == SS_COMP ) &&
  1023.                       ( srbGDEVBlock.SRB_DeviceType == DTYPE_CDROM ) )
  1024.                   {
  1025.                       p_vcddev->i_sid = MAKEWORD( i, j );
  1026.                       p_vcddev->hASPI = (long)hASPI;
  1027.                       p_vcddev->lpSendCommand = lpSendCommand;
  1028.                       msg_Dbg( p_this, "using aspi layer" );
  1029.                       return 0;
  1030.                   }
  1031.                   else
  1032.                   {
  1033.                       FreeLibrary( hASPI );
  1034.                       msg_Dbg( p_this, "%c: is not a cdrom drive",
  1035.                                psz_dev[0] );
  1036.                       return -1;
  1037.                   }
  1038.               }
  1039.           }
  1040.         }
  1041.         FreeLibrary( hASPI );
  1042.         msg_Dbg( p_this, "unable to get haid and target (aspi)" );
  1043.     }
  1044.     return -1;
  1045. }
  1046. #endif /* WIN32 */