#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <dirent.h>
#include <mntopts.h>
#include <mach/mach_init.h>
#include <servers/netname.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/sysctl.h>
#include <sys/disk.h>
#include <sys/errno.h>
#include <sys/param.h>
#include <sys/paths.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/mount.h>
#include <sys/loadable_fs.h>
#include <libkern/OSByteOrder.h>
#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CFPriv.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/storage/IOCDTypes.h>
#include <IOKit/storage/IOCDMedia.h>
#include "cddafs_util.h"
#include "AppleCDDAFileSystemDefines.h"
#include "CDDATrackName.h"
#define DEBUG 0
#define DEBUG_LEVEL 0
#ifndef DEBUG_ASSERT_COMPONENT_NAME_STRING
#define DEBUG_ASSERT_COMPONENT_NAME_STRING "cddafs.util"
#endif
#include <AssertMacros.h>
#if (DEBUG_LEVEL > 3)
#define DebugLog(x) printf x
#else
#define DebugLog(x)
#endif
static int
UtilityMain ( int argc, const char * argv[] );
static int
MountMain ( int argc, const char * argv[] );
static CFDataRef
GetTrackData ( const char * bsdDevNode,
const QTOCDataFormat10Ptr TOCData );
struct mntopt gMountOptions[] =
{
MOPT_STDOPTS,
{ NULL }
};
static char gAppleCDDAName[MFSNAMELEN] = "cddafs";
static char gFileSuffix[] = ".aiff";
#define kMaxPrefixSize 3
#define kASCIINumberZero 0x30
#define kASCIISpace 0x20
int
main ( int argc, const char * argv[] )
{
int result = -1;
#if DEBUG
int index = 0;
for ( index = 0; index < argc; index++ )
{
printf ( "[%d] = %s\n", index, argv[index] );
}
#endif
if ( strcmp ( argv[0], kUtilExecutableName ) == 0 )
{
result = UtilityMain ( argc, argv );
}
else
{
result = MountMain ( argc, argv );
}
return result;
}
#if 0
#pragma mark -
#pragma mark - Utility Code
#pragma mark -
#endif
static int
UtilityMain ( int argc, const char * argv[] )
{
char rawDeviceName[MAXPATHLEN];
char blockDeviceName[MAXPATHLEN];
const char * actionPtr = NULL;
const char * mountPointPtr = NULL;
int result = FSUR_IO_SUCCESS;
boolean_t isLocked = 0;
boolean_t isEjectable = 0;
int mountFlags = MNT_RDONLY;
result = ParseUtilityArgs ( argc, argv, &actionPtr, &mountPointPtr, &isEjectable, &isLocked );
require ( ( result == 0 ), Exit );
sprintf ( rawDeviceName, "/dev/r%s", argv[2] );
sprintf ( blockDeviceName, "/dev/%s", argv[2] );
result = seteuid ( 0 );
require_action ( ( result == 0 ), Exit, result = FSUR_INVAL );
result = setegid ( 0 );
if ( result )
{
DebugLog ( ( "cddafs.util: ERROR: setegid: %s\n", strerror ( errno ) ) );
}
DebugLog ( ( "Entering the switch with action = %s\n", actionPtr ) );
switch ( *actionPtr )
{
case FSUC_PROBE:
result = Probe ( rawDeviceName );
break;
case FSUC_MOUNT:
case FSUC_MOUNT_FORCE:
result = Mount ( blockDeviceName, mountPointPtr, mountFlags );
break;
case FSUC_UNMOUNT:
result = Unmount ( mountPointPtr );
break;
default:
DisplayUsage ( kUsageTypeUtility, argv );
result = FSUR_INVAL;
break;
}
Exit:
DebugLog ( ( "cddafs.util: EXIT: %d = ", result ) );
switch ( result )
{
case FSUR_LOADERR:
DebugLog ( ( "FSUR_LOADERR\n" ) );
break;
case FSUR_INVAL:
DebugLog ( ( "FSUR_INVAL\n" ) );
break;
case FSUR_IO_SUCCESS:
DebugLog ( ( "FSUR_IO_SUCCESS\n" ) );
break;
case FSUR_IO_FAIL:
DebugLog ( ( "FSUR_IO_FAIL\n" ) );
break;
case FSUR_RECOGNIZED:
DebugLog ( ( "FSUR_RECOGNIZED\n" ) );
break;
case FSUR_MOUNT_HIDDEN:
DebugLog ( ( "FSUR_MOUNT_HIDDEN\n" ) );
break;
case FSUR_UNRECOGNIZED:
DebugLog ( ( "FSUR_UNRECOGNIZED\n" ) );
break;
default:
DebugLog ( ( "default\n" ) );
break;
}
check ( result == FSUR_IO_SUCCESS );
exit ( result );
return result;
}
int
ParseUtilityArgs ( int argc,
const char * argv[],
const char ** actionPtr,
const char ** mountPointPtr,
boolean_t * isEjectablePtr,
boolean_t * isLockedPtr )
{
int result = FSUR_INVAL;
int deviceLength = 0;
int index = 0;
require_action ( ( argc >= 3 ), Exit, DisplayUsage ( kUsageTypeUtility, argv ) );
require_action ( ( argv[1][0] == '-' ), Exit, DisplayUsage ( kUsageTypeUtility, argv ) );
*actionPtr = &argv[1][1];
switch ( argv[1][1] )
{
case FSUC_PROBE:
require_action ( ( argc >= 5 ), Exit, DisplayUsage ( kUsageTypeUtility, argv ) );
index = 3;
break;
case FSUC_UNMOUNT:
*mountPointPtr = argv[3];
index = 0; break;
case FSUC_MOUNT:
case FSUC_MOUNT_FORCE:
require_action ( ( argc >= 6 ), Exit, DisplayUsage ( kUsageTypeUtility, argv ) );
*mountPointPtr = argv[3];
index = 4;
break;
default:
DisplayUsage ( kUsageTypeUtility, argv );
goto Exit;
break;
}
deviceLength = strlen ( argv[2] );
require ( ( deviceLength >= 5 ), Exit );
result = 0;
require ( ( index != 0 ), Exit );
if ( !strcmp ( argv[index], "removable" ) )
{
*isEjectablePtr = 1;
}
else if ( !strcmp ( argv[index], "fixed" ) )
{
*isEjectablePtr = 0;
}
else
{
DebugLog ( ( "cddafs.util: ERROR: unrecognized flag (removable/fixed) argv[%d]='%s'\n",
index, argv[index] ) );
}
if ( !strcmp ( argv[index + 1], "readonly" ) )
{
*isLockedPtr = 1;
}
else if ( !strcmp ( argv[index + 1], "writable" ) )
{
*isLockedPtr = 0;
}
else
{
DebugLog ( ( "cddafs.util: ERROR: unrecognized flag (readonly/writable) argv[%d]='%s'\n",
index, argv[index + 1] ) );
}
Exit:
return result;
}
int
Probe ( char * deviceNamePtr )
{
int result = FSUR_UNRECOGNIZED;
UInt8 * ptr = NULL;
DebugLog ( ( "ENTER: Probe('%s')\n", deviceNamePtr ) );
ptr = GetTOCDataPtr ( deviceNamePtr );
if ( ptr != NULL )
{
result = ParseTOC ( ptr );
}
else
{
DebugLog ( ( "GetTOCDataPtr returned NULL.\n" ) );
}
if ( result == FSUR_RECOGNIZED )
{
CFStringRef albumName = 0;
CDDATrackName * database = NULL;
database = new CDDATrackName;
if ( database != NULL )
{
DebugLog ( ( "database != NULL\n" ) );
database->Init ( deviceNamePtr, ptr );
DebugLog ( ( "Init called\n" ) );
albumName = database->GetAlbumName ( );
DebugLog ( ( "GetAlbumName called\n" ) );
}
if ( albumName != 0 )
{
Boolean success = false;
char buffer[MAXNAMLEN];
#if DEBUG
CFShow ( albumName );
#endif
success = _CFStringGetFileSystemRepresentation ( albumName,
( UInt8 * ) buffer,
MAXNAMLEN );
if ( success == true )
{
WriteDiskLabel ( buffer );
}
else
{
WriteDiskLabel ( kMountPointName );
}
CFRelease ( albumName );
albumName = 0;
}
else
{
WriteDiskLabel ( kMountPointName );
}
if ( database != NULL )
{
delete database;
database = NULL;
}
}
if ( ptr != NULL )
{
free ( ptr );
ptr = NULL;
}
DebugLog ( ( "Probe: returns " ) );
switch ( result )
{
case FSUR_IO_FAIL:
DebugLog ( ( "FSUR_IO_FAIL\n" ) );
break;
case FSUR_RECOGNIZED:
DebugLog ( ( "FSUR_RECOGNIZED\n" ) );
break;
case FSUR_MOUNT_HIDDEN:
DebugLog ( ( "FSUR_MOUNT_HIDDEN\n" ) );
break;
case FSUR_UNRECOGNIZED:
DebugLog ( ( "FSUR_UNRECOGNIZED\n" ) );
break;
default:
DebugLog ( ( "default\n" ) );
break;
}
return result;
}
int
Unmount ( const char * theMountPointPtr )
{
int result;
int mountflags = 0;
result = unmount ( theMountPointPtr, mountflags );
require_action ( ( result == 0 ), Exit, result = FSUR_IO_FAIL );
result = FSUR_IO_SUCCESS;
Exit:
return result;
}
#if 0
#pragma mark -
#pragma mark - Mount Code
#pragma mark -
#endif
static int
MountMain ( int argc, const char * argv[] )
{
int error = 0;
int mountFlags = 0;
error = ParseMountArgs ( &argc, &argv, &mountFlags );
require_action ( ( error == 0 ), Exit, DisplayUsage ( kUsageTypeMount, argv ) );
error = Mount ( argv[0], argv[1], mountFlags );
check ( error == FSUR_IO_SUCCESS );
if ( error == FSUR_IO_SUCCESS )
error = 0;
Exit:
return error;
}
int
ParseMountArgs ( int * argc, const char ** argv[], int * mountFlags )
{
int error = 0;
int ch = 0;
int altFlags = 0;
mntoptparse_t parse = NULL;
*mountFlags = 0;
*mountFlags |= MNT_RDONLY;
require_action ( ( *argc > 2 ), Exit, error = 1 );
while ( ( ch = getopt ( *argc, ( char * const * ) *argv, "o:" ) ) != -1 )
{
switch ( ch )
{
case 'o':
parse = getmntopts ( optarg, gMountOptions, mountFlags, &altFlags );
if ( parse != NULL )
{
freemntopts ( parse );
}
else
{
error = 1;
}
break;
default:
error = 1;
break;
}
}
*argc -= optind;
*argv += optind;
Exit:
return error;
}
void
WriteDiskLabel ( char * contentsPtr )
{
StripTrailingSpaces ( contentsPtr );
write ( 1, contentsPtr, strlen ( contentsPtr ) );
}
void
StripTrailingSpaces ( char * theContentsPtr )
{
check ( theContentsPtr );
check ( strlen ( theContentsPtr ) > 0 );
if ( strlen ( theContentsPtr ) > 0 )
{
char *myPtr;
myPtr = theContentsPtr + strlen ( theContentsPtr ) - 1;
while ( *myPtr == kASCIISpace && myPtr >= theContentsPtr )
{
*myPtr = 0x00;
myPtr--;
}
}
}
int
Mount ( const char * deviceNamePtr,
const char * mountPointPtr,
int mountFlags )
{
AppleCDDAArguments args = { 0 };
struct vfsconf vfc = { 0 };
int result = FSUR_IO_FAIL;
int error = 0;
CFDataRef data = 0;
CFDataRef xmlDataRef = 0;
UInt32 size = 0;
QTOCDataFormat10Ptr TOCDataPtr = NULL;
UInt8 * xmlDataPtr = NULL;
char realMountPoint[PATH_MAX];
char * realMountPointPtr;
DebugLog ( ( "Mount('%s','%s')\n", deviceNamePtr, mountPointPtr ) );
require ( ( mountPointPtr != NULL ), Exit );
require ( ( *mountPointPtr != '\0' ), Exit );
args.device = ( char * ) deviceNamePtr;
args.fileType = 0x41494643; args.fileCreator = 0x3F3F3F3F;
error = getvfsbyname ( gAppleCDDAName, &vfc );
if ( error != 0 )
{
error = LoadKernelExtension ( );
require ( ( error == 0 ), Exit );
error = getvfsbyname ( gAppleCDDAName, &vfc );
require ( ( error == 0 ), Exit );
}
TOCDataPtr = ( QTOCDataFormat10Ptr ) GetTOCDataPtr ( deviceNamePtr );
require ( ( TOCDataPtr != NULL ), Exit );
data = GetTrackData ( deviceNamePtr, TOCDataPtr );
require ( ( data != NULL ), ReleaseTOCData );
size = CFDataGetLength ( data );
DebugLog ( ( "CFDataGetLength returned size = %ld\n", size ) );
args.nameData = ( char * ) malloc ( size );
args.nameDataSize = size;
CFDataGetBytes ( data, CFRangeMake ( 0, size ), ( UInt8 * ) args.nameData );
CFRelease ( data );
data = 0;
args.numTracks = FindNumberOfAudioTracks ( TOCDataPtr );
xmlDataRef = CreateXMLFileInPListFormat ( TOCDataPtr );
xmlDataPtr = ( UInt8 * ) CFDataGetBytePtr ( xmlDataRef );
args.xmlFileSize = CFDataGetLength ( xmlDataRef );
args.xmlData = ( UInt8 * ) malloc ( args.xmlFileSize );
require ( ( args.xmlData != NULL ), ReleaseNameData );
memcpy ( args.xmlData, xmlDataPtr, args.xmlFileSize );
CFRelease ( xmlDataRef );
#if ( DEBUG_LEVEL > 3 )
{
UInt32 count = 0;
for ( ; count < args.xmlFileSize; count = count + 8 )
{
DebugLog ( ("%x:%x:%x:%x %x:%x:%x:%x\n",
xmlDataPtr[count],
xmlDataPtr[count+1],
xmlDataPtr[count+2],
xmlDataPtr[count+3],
xmlDataPtr[count+4],
xmlDataPtr[count+5],
xmlDataPtr[count+6],
xmlDataPtr[count+7] ) );
}
DebugLog ( ( "\n" ) );
DebugLog ( ( "XML File Size = %ld\n", args.xmlFileSize ) );
}
#endif
DebugLog ( ( "DeviceName = %s\n", deviceNamePtr ) );
DebugLog ( ( "numTracks = %d\n", args.numTracks ) );
require ( ( args.nameData != NULL ), ReleaseXMLData );
require ( ( args.nameDataSize != 0 ), ReleaseXMLData );
realMountPointPtr = realpath ( mountPointPtr, realMountPoint );
require ( ( realMountPointPtr != NULL ), ReleaseXMLData );
result = mount ( vfc.vfc_name, realMountPoint, mountFlags, &args );
require ( ( result == 0 ), ReleaseXMLData );
result = FSUR_IO_SUCCESS;
ReleaseXMLData:
require_quiet ( ( args.xmlData != NULL ), Exit );
free ( ( char * ) args.xmlData );
args.xmlData = NULL;
ReleaseNameData:
require_quiet ( ( args.nameData != NULL ), Exit );
free ( ( char * ) args.nameData );
args.nameData = NULL;
ReleaseTOCData:
require_quiet ( ( TOCDataPtr != NULL ), Exit );
free ( ( char * ) TOCDataPtr );
TOCDataPtr = NULL;
Exit:
return result;
}
int
ParseTOC ( UInt8 * TOCInfoPtr )
{
int result = FSUR_UNRECOGNIZED;
int error = 0;
QTOCDataFormat10Ptr TOCDataPtr = NULL;
UInt8 index = 0;
UInt8 numberOfDescriptors = 0;
require ( ( TOCInfoPtr != NULL ), Exit );
TOCDataPtr = ( QTOCDataFormat10Ptr ) TOCInfoPtr;
error = GetNumberOfTrackDescriptors ( TOCDataPtr, &numberOfDescriptors );
require_quiet ( ( error == 0 ), Exit );
for ( index = 0; index < numberOfDescriptors; index++ )
{
if ( IsAudioTrack ( index, TOCDataPtr ) )
{
return FSUR_RECOGNIZED;
}
}
Exit:
return result;
}
CFDataRef
GetTrackData ( const char * bsdDevNode,
const QTOCDataFormat10Ptr TOCData )
{
CFMutableDataRef data = 0;
CFStringRef trackString = 0;
UInt8 numTracks = 0;
UInt32 trackIndex = 0;
UInt8 currentTrack = 0;
SInt32 error = 0;
CDDATrackName * database = NULL;
data = CFDataCreateMutable ( kCFAllocatorDefault, 0 );
database = new CDDATrackName;
database->Init ( bsdDevNode, TOCData );
error = GetNumberOfTrackDescriptors ( ( QTOCDataFormat10Ptr ) TOCData, &numTracks );
if ( error != 0 )
{
DebugLog ( ( "Error = %ld on GetNumberOfTrackDescriptors\n", error ) );
exit ( 1 );
}
for ( trackIndex = 0; trackIndex < numTracks; trackIndex++ )
{
if ( IsAudioTrack ( trackIndex, TOCData ) == false )
continue;
currentTrack = GetPointValue ( trackIndex, TOCData );
trackString = ( database )->GetTrackName ( currentTrack );
if ( trackString != 0 )
{
UInt8 size = 0;
UInt8 suffixSize = 0;
UInt8 prefixSize = 2;
UInt8 bufferSize = 0;
UInt8 offset = 0;
Boolean success = false;
char * buffer = NULL;
char prefix[kMaxPrefixSize];
if ( currentTrack > 9 )
{
prefixSize++;
prefix[offset++] = currentTrack / 10 + kASCIINumberZero;
}
prefix[offset++] = currentTrack % 10 + kASCIINumberZero;
prefix[offset] = kASCIISpace;
suffixSize = strlen ( gFileSuffix );
bufferSize = MAXNAMLEN - prefixSize - suffixSize - 1;
buffer = ( char * ) calloc ( 1, bufferSize );
success = _CFStringGetFileSystemRepresentation ( trackString,
( UInt8 * ) buffer,
bufferSize );
buffer[bufferSize - 1] = 0;
size = strlen ( buffer ) + prefixSize + suffixSize;
DebugLog ( ( "size = %ld\n", size ) );
DebugLog ( ( "buffer = %s", buffer ) );
CFDataAppendBytes ( data,
¤tTrack,
1 );
CFDataAppendBytes ( data,
&size,
1 );
CFDataAppendBytes ( data,
( UInt8 * ) prefix,
prefixSize );
CFDataAppendBytes ( data,
( UInt8 * ) buffer,
strlen ( buffer ) );
CFDataAppendBytes ( data,
( UInt8 * ) gFileSuffix,
suffixSize );
free ( buffer );
CFRelease ( trackString );
}
}
if ( database != NULL )
{
delete database;
database = NULL;
}
return data;
}
int
LoadKernelExtension ( void )
{
int pid;
int result = -1;
union wait status;
pid = fork ( );
if ( pid == 0 )
{
result = execl ( kLoadCommand, kLoadCommand,
kCDDAFileSystemExtensionPath, NULL );
goto Exit;
}
if ( pid == -1 )
{
result = errno;
goto Exit;
}
if ( ( wait4 ( pid, ( int * ) &status, 0, NULL ) == pid ) &&
( WIFEXITED ( status ) ) )
{
result = status.w_retcode;
}
else
{
result = -1;
}
check ( result == 0 );
Exit:
return result;
}
CFDataRef
CreateXMLFileInPListFormat ( QTOCDataFormat10Ptr TOCDataPtr )
{
SubQTOCInfoPtr trackDescriptorPtr = NULL;
SubQTOCInfoPtr lastTrackDescriptorPtr = NULL;
UInt16 numSessions = 0;
UInt16 length = 0;
UInt16 numberOfDescriptors = 0;
CFMutableDictionaryRef theCDDictionaryRef = 0;
CFMutableArrayRef theSessionArrayRef = 0;
CFDataRef theRawTOCDataRef = 0;
UInt32 index = 0;
CFDataRef xmlData = 0;
DebugLog ( ( "CreateXMLFileInPListFormat called\n" ) );
if ( TOCDataPtr != NULL )
{
theCDDictionaryRef = CFDictionaryCreateMutable ( kCFAllocatorDefault,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks );
length = OSSwapBigToHostInt16 ( TOCDataPtr->TOCDataLength );
theRawTOCDataRef = CFDataCreate ( kCFAllocatorDefault,
( UInt8 * ) TOCDataPtr,
length + sizeof ( TOCDataPtr->TOCDataLength ) );
CFDictionarySetValue ( theCDDictionaryRef,
CFSTR ( kRawTOCDataString ),
theRawTOCDataRef );
CFRelease ( theRawTOCDataRef );
length -= ( sizeof ( TOCDataPtr->firstSessionNumber ) +
sizeof ( TOCDataPtr->lastSessionNumber ) );
numberOfDescriptors = length / ( sizeof ( SubQTOCInfo ) );
numSessions = TOCDataPtr->lastSessionNumber - TOCDataPtr->firstSessionNumber + 1;
if ( numberOfDescriptors <= 0 )
{
DebugLog ( ( "No tracks on this CD...\n" ) );
}
theSessionArrayRef = CFArrayCreateMutable ( kCFAllocatorDefault, numSessions, &kCFTypeArrayCallBacks );
trackDescriptorPtr = TOCDataPtr->trackDescriptors;
lastTrackDescriptorPtr = TOCDataPtr->trackDescriptors + numberOfDescriptors - 1;
for ( index = 0; trackDescriptorPtr <= lastTrackDescriptorPtr; index++ )
{
CFMutableDictionaryRef theSessionDictionaryRef = 0;
CFMutableArrayRef theTrackArrayRef = 0;
UInt32 trackIndex = 0;
theSessionDictionaryRef = CFDictionaryCreateMutable ( kCFAllocatorDefault,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks );
theTrackArrayRef = CFArrayCreateMutable ( kCFAllocatorDefault,
0,
&kCFTypeArrayCallBacks );
while ( ( trackDescriptorPtr <= lastTrackDescriptorPtr ) &&
( trackDescriptorPtr->sessionNumber == ( index + 1 ) ) )
{
CFMutableDictionaryRef theTrackRef = 0;
CFBooleanRef isDigitalData = kCFBooleanFalse;
CFBooleanRef preEmphasis = kCFBooleanFalse;
CFNumberRef startBlock;
CFNumberRef sessionNumber;
CFNumberRef point;
SInt16 pointValue;
UInt32 blockAddress;
pointValue = trackDescriptorPtr->point;
if ( pointValue == 0x00A0 )
{
CFNumberRef sessionType = 0;
CFNumberRef firstTrackNum = 0;
CFNumberRef sessionNumber = 0;
firstTrackNum = CFNumberCreate ( kCFAllocatorDefault,
kCFNumberCharType,
&trackDescriptorPtr->PMSF.A0PMSF.firstTrackNum );
sessionType = CFNumberCreate ( kCFAllocatorDefault,
kCFNumberCharType,
&trackDescriptorPtr->PMSF.A0PMSF.discType );
sessionNumber = CFNumberCreate ( kCFAllocatorDefault,
kCFNumberCharType,
&trackDescriptorPtr->sessionNumber );
CFDictionarySetValue ( theSessionDictionaryRef,
CFSTR ( kFirstTrackInSessionString ),
firstTrackNum );
CFDictionarySetValue ( theSessionDictionaryRef,
CFSTR ( kSessionTypeString ),
sessionType );
CFDictionarySetValue ( theSessionDictionaryRef,
CFSTR ( kSessionNumberString ),
sessionNumber );
CFRelease ( firstTrackNum );
CFRelease ( sessionType );
CFRelease ( sessionNumber );
goto nextIteration;
}
if ( pointValue == 0x00A1 )
{
CFNumberRef lastTrackNum = 0;
lastTrackNum = CFNumberCreate ( kCFAllocatorDefault,
kCFNumberCharType,
&trackDescriptorPtr->PMSF.A1PMSF.lastTrackNum );
CFDictionarySetValue ( theSessionDictionaryRef,
CFSTR ( kLastTrackInSessionString ),
lastTrackNum );
CFRelease ( lastTrackNum );
goto nextIteration;
}
if ( pointValue == 0x00A2 )
{
CFNumberRef leadoutBlock = 0;
UInt32 blockAddress = 0;
blockAddress = ( ( trackDescriptorPtr->PMSF.leadOutStartPosition.minutes * 60 ) +
trackDescriptorPtr->PMSF.leadOutStartPosition.seconds ) * 75 +
trackDescriptorPtr->PMSF.leadOutStartPosition.frames;
leadoutBlock = CFNumberCreate ( kCFAllocatorDefault,
kCFNumberIntType,
&blockAddress );
CFDictionarySetValue ( theSessionDictionaryRef,
CFSTR ( kLeadoutBlockString ),
leadoutBlock );
CFRelease ( leadoutBlock );
goto nextIteration;
}
if ( pointValue > 0x63 )
{
goto nextIteration;
}
theTrackRef = CFDictionaryCreateMutable ( kCFAllocatorDefault,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks );
point = CFNumberCreate ( kCFAllocatorDefault,
kCFNumberSInt16Type,
&pointValue );
CFDictionarySetValue ( theTrackRef,
CFSTR ( kPointString ),
point );
CFRelease ( point );
blockAddress = ( ( trackDescriptorPtr->PMSF.startPosition.minutes * 60 ) +
trackDescriptorPtr->PMSF.startPosition.seconds ) * 75 +
trackDescriptorPtr->PMSF.startPosition.frames;
DebugLog ( ( "track = %d, blockAddress = %ld\n", pointValue, blockAddress ) );
startBlock = CFNumberCreate ( kCFAllocatorDefault,
kCFNumberLongType,
&blockAddress );
CFDictionarySetValue ( theTrackRef,
CFSTR ( kStartBlockString ),
startBlock );
CFRelease ( startBlock );
sessionNumber = CFNumberCreate ( kCFAllocatorDefault,
kCFNumberCharType,
&trackDescriptorPtr->sessionNumber );
CFDictionarySetValue ( theTrackRef,
CFSTR ( kSessionNumberString ),
sessionNumber );
CFRelease ( sessionNumber );
if ( ( trackDescriptorPtr->control & kDigitalDataMask ) == kDigitalDataMask )
{
isDigitalData = kCFBooleanTrue;
}
CFDictionarySetValue ( theTrackRef,
CFSTR ( kDataString ),
isDigitalData );
if ( ( trackDescriptorPtr->control & kPreEmphasisMask ) == kPreEmphasisMask )
{
preEmphasis = kCFBooleanTrue;
}
CFDictionarySetValue ( theTrackRef,
CFSTR ( kPreEmphasisString ),
preEmphasis );
CFArraySetValueAtIndex ( theTrackArrayRef, trackIndex, theTrackRef );
CFRelease ( theTrackRef );
trackIndex++;
nextIteration:
trackDescriptorPtr++;
}
CFDictionarySetValue ( theSessionDictionaryRef, CFSTR ( kTrackArrayString ), theTrackArrayRef );
CFArraySetValueAtIndex ( theSessionArrayRef, index, theSessionDictionaryRef );
CFRelease ( theSessionDictionaryRef );
CFRelease ( theTrackArrayRef );
}
CFDictionarySetValue ( theCDDictionaryRef, CFSTR ( kSessionsString ), theSessionArrayRef );
CFRelease ( theSessionArrayRef );
xmlData = CFPropertyListCreateXMLData ( kCFAllocatorDefault, theCDDictionaryRef );
CFRelease ( theCDDictionaryRef );
}
return xmlData;
}
#if 0
#pragma mark -
#pragma mark - Shared Code
#pragma mark -
#endif
void
DisplayUsage ( int usageType, const char * argv[] )
{
if ( usageType == kUsageTypeMount )
{
printf ( "usage: mount_cddafs [-o options] device-name mount-point\n" );
}
else if ( usageType == kUsageTypeUtility )
{
printf ( "usage: %s action_arg device_arg [mount_point_arg] [Flags] \n", argv[0] );
printf ( "action_arg:\n" );
printf ( " -%c (Probe for mounting)\n", FSUC_PROBE );
printf ( " -%c (Mount)\n", FSUC_MOUNT );
printf ( " -%c (Unmount)\n", FSUC_UNMOUNT );
printf ( " -%c (Force Mount)\n", FSUC_MOUNT_FORCE );
printf ( "device_arg:\n" );
printf ( " device we are acting upon (for example, 'sd2')\n" );
printf ( "mount_point_arg:\n" );
printf ( " required for Mount and Force Mount \n" );
printf ( "Flags:\n" );
printf ( " required for Mount, Force Mount and Probe\n" );
printf ( " indicates removable or fixed (for example 'fixed')\n" );
printf ( " indicates readonly or writable (for example 'readonly')\n" );
printf ( "Examples:\n");
printf ( " %s -p sd2 fixed writable\n", argv[0] );
printf ( " %s -m sd2 /my/hfs removable readonly\n", argv[0] );
}
return;
}
UInt8 *
GetTOCDataPtr ( const char * deviceNamePtr )
{
UInt8 * ptr = NULL;
IOReturn error = 0;
io_iterator_t iterator = MACH_PORT_NULL;
io_registry_entry_t registryEntry = MACH_PORT_NULL;
CFMutableDictionaryRef properties = 0;
CFDataRef data = 0;
char * bsdName = NULL;
if ( !strncmp ( deviceNamePtr, "/dev/r", 6 ) )
{
bsdName = ( char * ) &deviceNamePtr[6];
}
else if ( !strncmp ( deviceNamePtr, "/dev/", 5 ) )
{
bsdName = ( char * ) &deviceNamePtr[5];
}
else
{
DebugLog ( ( "GetTOCDataPtr: ERROR: not /dev/something...\n" ) );
goto Exit;
}
error = IOServiceGetMatchingServices ( kIOMasterPortDefault,
IOBSDNameMatching ( kIOMasterPortDefault, 0, bsdName ),
&iterator );
require ( ( error == kIOReturnSuccess ), Exit );
registryEntry = IOIteratorNext ( iterator );
require ( ( registryEntry != MACH_PORT_NULL ), ReleaseIterator );
require ( IOObjectConformsTo ( registryEntry, kIOCDMediaString ), ReleaseEntry );
error = IORegistryEntryCreateCFProperties ( registryEntry,
&properties,
kCFAllocatorDefault,
kNilOptions );
require ( ( error == kIOReturnSuccess ), ReleaseEntry );
data = ( CFDataRef ) CFDictionaryGetValue ( properties,
CFSTR ( kIOCDMediaTOCKey ) );
if ( data != NULL )
{
ptr = CreateBufferFromCFData ( data );
}
CFRelease ( properties );
ReleaseEntry:
error = IOObjectRelease ( registryEntry );
ReleaseIterator:
error = IOObjectRelease ( iterator );
Exit:
return ptr;
}
Boolean
IsAudioTrack ( UInt32 trackNumber, QTOCDataFormat10Ptr TOCData )
{
SubQTOCInfoPtr trackDescriptorPtr;
trackDescriptorPtr = TOCData->trackDescriptors;
trackDescriptorPtr = trackDescriptorPtr + trackNumber;
if ( trackDescriptorPtr->point < 100 && trackDescriptorPtr->point > 0 )
{
if ( ( trackDescriptorPtr->control & kDigitalDataMask ) == 0 )
{
return true;
}
}
return false;
}
SInt32
GetNumberOfTrackDescriptors ( QTOCDataFormat10Ptr TOCDataPtr,
UInt8 * numberOfDescriptors )
{
UInt16 length = 0;
SInt32 result = 0;
require_action ( ( TOCDataPtr != NULL ), Exit, result = -1 );
require_action ( ( numberOfDescriptors != NULL ), Exit, result = -1 );
length = OSSwapBigToHostInt16 ( TOCDataPtr->TOCDataLength );
DebugLog ( ( "Length = %d\n", length ) );
require_action ( ( length > sizeof ( CDTOC ) ), Exit, result = -1 );
length -= ( sizeof ( TOCDataPtr->firstSessionNumber ) +
sizeof ( TOCDataPtr->lastSessionNumber ) );
*numberOfDescriptors = length / ( sizeof ( SubQTOCInfo ) );
DebugLog ( ( "Number of descriptors = %d\n", *numberOfDescriptors ) );
Exit:
return result;
}
UInt8
GetPointValue ( UInt32 trackIndex, QTOCDataFormat10Ptr TOCData )
{
SubQTOCInfoPtr trackDescriptorPtr;
trackDescriptorPtr = TOCData->trackDescriptors;
trackDescriptorPtr = trackDescriptorPtr + trackIndex;
return trackDescriptorPtr->point;
}
UInt8 *
CreateBufferFromCFData ( CFDataRef theData )
{
CFRange range;
CFIndex bufferLength = 0;
UInt8 * buffer = NULL;
bufferLength = CFDataGetLength ( theData );
buffer = ( UInt8 * ) malloc ( bufferLength );
range = CFRangeMake ( 0, bufferLength );
if ( buffer != NULL )
CFDataGetBytes ( theData, range, buffer );
return buffer;
}
UInt32
FindNumberOfAudioTracks ( QTOCDataFormat10Ptr TOCDataPtr )
{
UInt32 result = 0;
SubQTOCInfoPtr trackDescriptorPtr = NULL;
UInt16 length = 0;
UInt16 numberOfDescriptors = 0;
DebugLog ( ( "FindNumberOfAudioTracks called\n" ) );
require ( ( TOCDataPtr != NULL ), Exit );
length = OSSwapBigToHostInt16 ( TOCDataPtr->TOCDataLength );
require ( ( length > sizeof ( CDTOC ) ), Exit );
length -= ( sizeof ( TOCDataPtr->firstSessionNumber ) +
sizeof ( TOCDataPtr->lastSessionNumber ) );
numberOfDescriptors = length / ( sizeof ( SubQTOCInfo ) );
require ( ( numberOfDescriptors != 0 ), Exit );
DebugLog ( ( "numberOfDescriptors = %d\n", numberOfDescriptors ) );
trackDescriptorPtr = TOCDataPtr->trackDescriptors;
while ( numberOfDescriptors > 0 )
{
if ( trackDescriptorPtr->point < 100 && trackDescriptorPtr->point > 0 )
{
if ( ( trackDescriptorPtr->control & kDigitalDataMask ) == 0 )
{
result++;
}
}
trackDescriptorPtr++;
numberOfDescriptors--;
}
Exit:
DebugLog ( ( "numberOfTracks = %ld\n", result ) );
return result;
}