/* * Copyright (c) 2000-2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ // AppleCDDAFileSystemUtils.c created by CJS on Sun 14-May-2000 #ifndef __APPLE_CDDA_FS_UTILS_H__ #include "AppleCDDAFileSystemUtils.h" #endif #ifndef __APPLE_CDDA_FS_DEBUG_H__ #include "AppleCDDAFileSystemDebug.h" #endif #ifndef __APPLE_CDDA_FS_DEFINES_H__ #include "AppleCDDAFileSystemDefines.h" #endif #ifndef __AIFF_SUPPORT_H__ #include "AIFFSupport.h" #endif #ifndef __APPLE_CDDA_FS_VFS_OPS_H__ #include "AppleCDDAFileSystemVFSOps.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include //----------------------------------------------------------------------------- // Static Function Prototypes //----------------------------------------------------------------------------- static int BuildTrackName ( mount_t mountPtr, AppleCDDANodeInfoPtr nodeInfoPtr ); static UInt32 CalculateNumberOfDescriptors ( const QTOCDataFormat10Ptr TOCDataPtr ); static UInt32 CalculateLBA ( SubQTOCInfoPtr trackDescriptorPtr ); static int FindName ( mount_t mountPtr, UInt8 trackNumber, char ** name, UInt8 * nameSize ); //----------------------------------------------------------------------------- // CreateNewCDDANode - This routine is responsible for creating new nodes //----------------------------------------------------------------------------- errno_t CreateNewCDDANode ( mount_t mountPtr, UInt32 nodeID, enum vtype vNodeType, vnode_t parentVNodePtr, struct componentname * compNamePtr, vnode_t * vNodeHandle ) { errno_t result = 0; AppleCDDANodePtr cddaNodePtr = NULL; vnode_t vNodePtr = NULLVP; struct vnode_fsparam vfsp; DebugAssert ( ( mountPtr != NULL ) ); DebugAssert ( ( vNodeHandle != NULL ) ); // Allocate the cddaNode MALLOC ( cddaNodePtr, AppleCDDANodePtr, sizeof ( AppleCDDANode ), M_TEMP, M_WAITOK ); // Zero the structure bzero ( cddaNodePtr, sizeof ( AppleCDDANode ) ); // Set the nodeID cddaNodePtr->nodeID = nodeID; // Zero the FS param structure bzero ( &vfsp, sizeof ( vfsp ) ); vfsp.vnfs_mp = mountPtr; vfsp.vnfs_vtype = vNodeType; vfsp.vnfs_str = "cddafs"; vfsp.vnfs_dvp = parentVNodePtr; vfsp.vnfs_fsnode = cddaNodePtr; vfsp.vnfs_cnp = compNamePtr; vfsp.vnfs_vops = gCDDA_VNodeOp_p; vfsp.vnfs_rdev = 0; #if DEBUG if ( compNamePtr != NULL ) { DebugLog ( ( "compNamePtr->cn_flags = 0x%08x\n", ( int ) compNamePtr->cn_flags ) ); DebugLog ( ( "compNamePtr->cn_nameiop = 0x%08x\n", ( int ) compNamePtr->cn_nameiop ) ); DebugLog ( ( "compNamePtr->cn_pnbuf = %s\n", compNamePtr->cn_pnbuf ) ); DebugLog ( ( "compNamePtr->cn_nameptr = %s\n", compNamePtr->cn_nameptr ) ); DebugLog ( ( "compNamePtr->cn_namelen = %ld\n", compNamePtr->cn_namelen ) ); DebugLog ( ( "compNamePtr->cn_hash = 0x%08x\n", ( int ) compNamePtr->cn_hash ) ); DebugLog ( ( "compNamePtr->cn_consume = %ld\n\n", compNamePtr->cn_consume ) ); } #endif /* DEBUG */ if ( ( parentVNodePtr != NULL ) && ( compNamePtr != NULL ) && ( compNamePtr->cn_flags & MAKEENTRY ) ) vfsp.vnfs_flags = 0; else vfsp.vnfs_flags = VNFS_NOCACHE; vfsp.vnfs_markroot = ( nodeID == kAppleCDDARootFileID ); vfsp.vnfs_marksystem = 0; // Note that vnode_create ( ) returns the vnode with an iocount of +1; // this routine returns the newly created vnode with this positive iocount. result = vnode_create ( VNCREATE_FLAVOR, ( uint32_t ) VCREATESIZE, &vfsp, &vNodePtr ); if ( result != 0 ) { DebugLog ( ( "getnewvnode failed with error code %d\n", result ) ); goto FREE_CDDA_NODE_ERROR; } // Link the cddaNode to the vnode cddaNodePtr->vNodePtr = vNodePtr; vnode_addfsref ( vNodePtr ); // Return the vnode to the caller *vNodeHandle = vNodePtr; return result; FREE_CDDA_NODE_ERROR: // Free the allocated memory FREE ( ( caddr_t ) cddaNodePtr, M_TEMP ); cddaNodePtr = NULL; return result; } //----------------------------------------------------------------------------- // DisposeCDDANode - This routine is responsible for cleaning up cdda nodes //----------------------------------------------------------------------------- int DisposeCDDANode ( vnode_t vNodePtr ) { AppleCDDANodePtr cddaNodePtr = NULL; DebugAssert ( ( vNodePtr != NULL ) ); cddaNodePtr = VTOCDDA ( vNodePtr ); DebugAssert ( ( cddaNodePtr != NULL ) ); if ( cddaNodePtr != NULL ) { // Free memory associated with our filesystem's internal data FREE ( vnode_fsnode ( vNodePtr ), M_TEMP ); vnode_clearfsnode ( vNodePtr ); } return ( 0 ); } //----------------------------------------------------------------------------- // CreateNewCDDAFile - This routine is responsible for creating new // files //----------------------------------------------------------------------------- errno_t CreateNewCDDAFile ( mount_t mountPtr, UInt32 nodeID, AppleCDDANodeInfoPtr nodeInfoPtr, vnode_t parentVNodePtr, struct componentname * compNamePtr, vnode_t * vNodeHandle ) { errno_t result = 0; vnode_t vNodePtr = NULLVP; AppleCDDANodePtr cddaNodePtr = NULL; AppleCDDANodePtr parentCDDANodePtr = NULL; AppleCDDAMountPtr cddaMountPtr = NULL; struct componentname cn; bzero ( &cn, sizeof ( cn ) ); DebugAssert ( ( mountPtr != NULL ) ); DebugAssert ( ( nodeInfoPtr != NULL ) ); DebugAssert ( ( vNodeHandle != NULL ) ); cddaMountPtr = VFSTOCDDA ( mountPtr ); parentCDDANodePtr = VTOCDDA ( cddaMountPtr->root ); DebugAssert ( ( cddaMountPtr != NULL ) ); DebugAssert ( ( parentCDDANodePtr != NULL ) ); if ( parentVNodePtr == NULL ) { DebugLog ( ( "CreateNewCDDAFile called with NULL parentVNodePtr\n" ) ); parentVNodePtr = cddaMountPtr->root; } if ( compNamePtr == NULL ) { DebugLog ( ( "CreateNewCDDAFile called with NULL compNamePtr\n" ) ); MALLOC ( cn.cn_pnbuf, caddr_t, MAXPATHLEN, M_TEMP, M_WAITOK ); cn.cn_nameiop = LOOKUP; cn.cn_flags = ISLASTCN | MAKEENTRY; cn.cn_pnlen = MAXPATHLEN; cn.cn_nameptr = cn.cn_pnbuf; cn.cn_namelen = nodeInfoPtr->nameSize; cn.cn_hash = 0; cn.cn_consume = 0; bcopy ( nodeInfoPtr->name, cn.cn_nameptr, nodeInfoPtr->nameSize + 1 ); compNamePtr = &cn; } result = CreateNewCDDANode ( mountPtr, nodeID, VREG, parentVNodePtr, compNamePtr, &vNodePtr ); if ( result != 0 ) { DebugLog ( ( "Error = %d returned from CreatNewCDDANode\n", result ) ); return result; } if ( cn.cn_pnbuf != NULL ) { DebugLog ( ( "CreateNewCDDAFile: freeing cn_pnbuf\n" ) ); FREE ( cn.cn_pnbuf, M_TEMP ); } cddaNodePtr = VTOCDDA ( vNodePtr ); DebugAssert ( ( cddaNodePtr != NULL ) ); // Build the header. BuildCDAIFFHeader ( &cddaNodePtr->u.file.aiffHeader, nodeInfoPtr->numBytes ); // Fill in the miscellaneous fields for the cddaNode cddaNodePtr->nodeType = kAppleCDDATrackType; cddaNodePtr->blockDeviceVNodePtr = parentCDDANodePtr->blockDeviceVNodePtr; // Set the back pointer cddaNodePtr->u.file.nodeInfoPtr = nodeInfoPtr; DebugLog ( ( "LBA of %d = %ld.\n", cddaNodePtr->nodeID, nodeInfoPtr->LBA ) ); // stuff the vNode in *vNodeHandle = vNodePtr; return 0; } //----------------------------------------------------------------------------- // CreateNewXMLFile - This routine is responsible for creating the ".TOC.plist" // file which has XML data describing the CD layout. //----------------------------------------------------------------------------- errno_t CreateNewXMLFile ( mount_t mountPtr, UInt32 xmlFileSize, UInt8 * xmlData, vnode_t parentVNodePtr, struct componentname * compNamePtr, vnode_t * vNodeHandle ) { errno_t result = 0; vnode_t vNodePtr = NULLVP; AppleCDDANodePtr cddaNodePtr = NULL; AppleCDDANodePtr parentCDDANodePtr = NULL; AppleCDDAMountPtr cddaMountPtr = NULL; struct componentname cn; bzero ( &cn, sizeof ( cn ) ); DebugAssert ( ( mountPtr != NULL ) ); DebugAssert ( ( vNodeHandle != NULL ) ); cddaMountPtr = VFSTOCDDA ( mountPtr ); parentCDDANodePtr = VTOCDDA ( cddaMountPtr->root ); DebugAssert ( ( cddaMountPtr != NULL ) ); DebugAssert ( ( parentCDDANodePtr != NULL ) ); if ( parentVNodePtr == NULL ) { DebugLog ( ( "CreateNewXMLFile called with NULL parentVNodePtr\n" ) ); parentVNodePtr = cddaMountPtr->root; } if ( compNamePtr == NULL ) { DebugLog ( ( "CreateNewXMLFile called with NULL compNamePtr\n" ) ); MALLOC ( cn.cn_pnbuf, caddr_t, MAXPATHLEN, M_TEMP, M_WAITOK ); cn.cn_nameiop = LOOKUP; cn.cn_flags = ISLASTCN | MAKEENTRY; cn.cn_pnlen = MAXPATHLEN; cn.cn_nameptr = cn.cn_pnbuf; cn.cn_namelen = ( uint32_t ) strlen ( ".TOC.plist" ); cn.cn_hash = 0; cn.cn_consume = 0; snprintf ( cn.cn_nameptr, MAXPATHLEN, "%s", ".TOC.plist" ); compNamePtr = &cn; } result = CreateNewCDDANode ( mountPtr, kAppleCDDAXMLFileID, VREG, parentVNodePtr, compNamePtr, &vNodePtr ); if ( result != 0 ) { DebugLog ( ( "Error = %d returned from CreatNewCDDANode\n", result ) ); return result; } if ( cn.cn_pnbuf != NULL ) { DebugLog ( ( "CreateNewXMLFile: freeing cn_pnbuf\n" ) ); FREE ( cn.cn_pnbuf, M_TEMP ); } cddaNodePtr = VTOCDDA ( vNodePtr ); DebugAssert ( ( cddaNodePtr != NULL ) ); // Fill in the miscellaneous fields for the cddaNode cddaNodePtr->nodeType = kAppleCDDAXMLFileType; cddaNodePtr->blockDeviceVNodePtr = parentCDDANodePtr->blockDeviceVNodePtr; // Point the xmlData to the correct place cddaNodePtr->u.xmlFile.fileDataPtr = xmlData; cddaNodePtr->u.xmlFile.fileSize = xmlFileSize; #if 0 { UInt32 count; // Let's see if we got the right data mapped in for ( count = 0; count < xmlFileSize; count = count + 8 ) { DebugLog ( ( "%x:%x:%x:%x %x:%x:%x:%x\n", xmlData[count], xmlData[count+1], xmlData[count+2], xmlData[count+3], xmlData[count+4], xmlData[count+5], xmlData[count+6], xmlData[count+7] ) ); } DebugLog ( ( "\n" ) ); } #endif // stuff the vNode in *vNodeHandle = vNodePtr; return 0; } //----------------------------------------------------------------------------- // CreateNewCDDADirectory - This routine is responsible for creating new // directories (i.e. the root directory) //----------------------------------------------------------------------------- errno_t CreateNewCDDADirectory ( mount_t mountPtr, UInt32 nodeID, vnode_t * vNodeHandle ) { errno_t result = 0; vnode_t vNodePtr = NULLVP; AppleCDDANodePtr cddaNodePtr = NULL; DebugAssert ( ( mountPtr != NULL ) ); DebugAssert ( ( vNodeHandle != NULL ) ); result = CreateNewCDDANode ( mountPtr, nodeID, VDIR, NULL, NULL, &vNodePtr ); if ( result != 0 ) { DebugLog ( ( "Error = %d returned from CreatNewCDDANode\n", result ) ); return result; } cddaNodePtr = VTOCDDA ( vNodePtr ); DebugAssert ( ( cddaNodePtr != NULL ) ); // Set up the directory-specific fields cddaNodePtr->nodeType = kAppleCDDADirectoryType; cddaNodePtr->u.directory.directorySize = 0; cddaNodePtr->u.directory.entryCount = kNumberOfFakeDirEntries; // ".", "..", and ".TOC.plist" // stuff the vNode in *vNodeHandle = vNodePtr; return 0; } //----------------------------------------------------------------------------- // IsAudioTrack - Checks the arguments passed in to find out if specified // track is audio or not //----------------------------------------------------------------------------- boolean_t IsAudioTrack ( const SubQTOCInfoPtr trackDescriptorPtr ) { DebugAssert ( ( trackDescriptorPtr != NULL ) ); // Check to make sure the point is between 1 and 99 (inclusive) if ( trackDescriptorPtr->point < 100 && trackDescriptorPtr->point > 0 ) { // Do we have digital data? if ( ( trackDescriptorPtr->control & kDigitalDataMask ) == 0 ) { // Found an audio track return TRUE; } } return FALSE; } //----------------------------------------------------------------------------- // CalculateSize - Calculate the file size based on number of frames // (i.e. blocks) in the track //----------------------------------------------------------------------------- UInt32 CalculateSize ( const QTOCDataFormat10Ptr TOCDataPtr, UInt32 trackDescriptorOffset, UInt32 currentA2Offset ) { UInt32 size = 0; UInt32 offset = 0; UInt32 numberOfDescriptors = 0; UInt32 nextOffset = 0; SubQTOCInfoPtr trackDescriptorPtr = NULL; SubQTOCInfoPtr nextTrackDescriptorPtr = NULL; DebugLog ( ( "CalculateSize: Entering...\n" ) ); DebugAssert ( ( TOCDataPtr != NULL ) ); // Find the number of descriptors numberOfDescriptors = CalculateNumberOfDescriptors ( TOCDataPtr ); // Get the correct track descriptor trackDescriptorPtr = &TOCDataPtr->trackDescriptors[trackDescriptorOffset]; // Are we past the total number of descriptors in TOC? if ( trackDescriptorOffset + 1 >= numberOfDescriptors ) { // yes, so set the descriptor to the last leadout descriptor we hit nextTrackDescriptorPtr = &TOCDataPtr->trackDescriptors[currentA2Offset]; } else { // no, so set the descriptor to the next entry in the TOC nextTrackDescriptorPtr = &TOCDataPtr->trackDescriptors[trackDescriptorOffset + 1]; // Are we past the end of the session? if ( trackDescriptorPtr->sessionNumber != nextTrackDescriptorPtr->sessionNumber || !IsAudioTrack ( nextTrackDescriptorPtr ) ) { // yes, so set the descriptor to the last leadout descriptor we hit nextTrackDescriptorPtr = &TOCDataPtr->trackDescriptors[currentA2Offset]; } } // Calculate the LBAs for both tracks offset = CalculateLBA ( trackDescriptorPtr ); nextOffset = CalculateLBA ( nextTrackDescriptorPtr ); // Multiply number of blocks by block size and add the header + pad (1 block) size = ( ( nextOffset - offset ) * kPhysicalMediaBlockSize ) + kPhysicalMediaBlockSize; DebugLog ( ( "CalculateSize: size = %ld.\n", size ) ); DebugLog ( ( "CalculateSize: exiting...\n" ) ); return size; } //----------------------------------------------------------------------------- // FindName - Parses the names data that gets passed in to the // filesystem, looking for the specified track's name. // All names look like the following packed structure: // // | 1 byte | 1 byte | number of bytes in 2nd byte | // Track # size of String String for Name // // Track # of zero corresponds to the album name (the mount point name). //----------------------------------------------------------------------------- int FindName ( mount_t mountPtr, UInt8 trackNumber, char ** name, UInt8 * nameSize ) { AppleCDDAMountPtr cddaMountPtr = NULL; UInt8 * ptr = NULL; UInt8 length = 0; DebugLog ( ( "FindName: entering\n" ) ); DebugLog ( ( "trackNumber = %d\n" ) ); DebugAssert ( ( mountPtr != NULL ) ); DebugAssert ( ( name != NULL ) ); DebugAssert ( ( nameSize != NULL ) ); cddaMountPtr = VFSTOCDDA ( mountPtr ); DebugLog ( ( "cddaMountPtr->nameDataSize = %ld\n", cddaMountPtr->nameDataSize ) ); ptr = cddaMountPtr->nameData; if ( ptr == NULL ) { DebugLog ( ( "cddaMountPtr->nameData is NULL" ) ); return ENOENT; } do { DebugLog ( ( "*ptr = %d\n", *ptr ) ); if ( *ptr == trackNumber ) { char mylocalname[512]; DebugLog ( ( "Found track = %d\n", trackNumber ) ); *nameSize = ptr[1]; *name = ( char * ) &ptr[2]; bcopy ( &ptr[2], mylocalname, *nameSize ); mylocalname[*nameSize] = 0; DebugLog ( ( "NameSize = %d\n", *nameSize ) ); DebugLog ( ( "Name = %s\n", mylocalname ) ); break; } else { length = ptr[1]; DebugLog ( ( "Didn't find it, keep looking\n" ) ); ptr = &ptr[length + 2]; } } while ( ptr < ( cddaMountPtr->nameData + cddaMountPtr->nameDataSize ) ); DebugLog ( ( "FindName: exiting\n" ) ); return 0; } //----------------------------------------------------------------------------- // ParseTOC - Parses the TOC to find audio tracks. It figures out which // tracks are audio and what their offsets are and fills in the // cddaNode structures associated with each vnode //----------------------------------------------------------------------------- SInt32 ParseTOC ( mount_t mountPtr, UInt32 numTracks ) { QTOCDataFormat10Ptr TOCDataPtr = NULL; SubQTOCInfoPtr trackDescriptorPtr = NULL; AppleCDDAMountPtr cddaMountPtr = NULL; AppleCDDANodeInfoPtr nodeInfoPtr = NULL; AppleCDDADirectoryNodePtr rootDirNodePtr = NULL; OSStatus error = 0; UInt16 numberOfDescriptors = 0; UInt32 currentA2Offset = 0; UInt32 currentOffset = 0; DebugLog ( ( "ParseTOC: Entering...\n" ) ); DebugAssert ( ( mountPtr != NULL ) ); cddaMountPtr = VFSTOCDDA ( mountPtr ); rootDirNodePtr = &( ( VTOCDDA ( cddaMountPtr->root ) )->u.directory ); DebugAssert ( ( cddaMountPtr != NULL ) ); DebugAssert ( ( rootDirNodePtr != NULL ) ); // Get the data from the registry entry TOCDataPtr = CreateBufferFromIORegistry ( mountPtr ); if ( TOCDataPtr != NULL ) { // calculate number of track descriptors numberOfDescriptors = CalculateNumberOfDescriptors ( TOCDataPtr ); DebugLog ( ( "Number of descriptors = %d\n", numberOfDescriptors ) ); if ( numberOfDescriptors <= 0 ) { // This is bad...no track descriptors, time to bail error = EINVAL; goto Exit; } trackDescriptorPtr = TOCDataPtr->trackDescriptors; while ( numberOfDescriptors > 0 && rootDirNodePtr->entryCount < ( numTracks + kNumberOfFakeDirEntries ) ) { if ( trackDescriptorPtr->point == 0xA2 ) { // Set the a2 offset when we find an a2 point currentA2Offset = currentOffset; } // Is this an audio track? if ( IsAudioTrack ( trackDescriptorPtr ) ) { // Make this easier to read by getting a pointer to the nodeInfo nodeInfoPtr = &cddaMountPtr->nodeInfoArrayPtr[rootDirNodePtr->entryCount - kNumberOfFakeDirEntries]; // Copy this trackDescriptor into the AppleCDDANodeInfo array nodeInfoPtr->trackDescriptor = *trackDescriptorPtr; // Get the LogicalBlockAddress and number of bytes in the track nodeInfoPtr->LBA = CalculateLBA ( trackDescriptorPtr ); nodeInfoPtr->numBytes = CalculateSize ( TOCDataPtr, currentOffset, currentA2Offset ); // Add this node's size to the root directory's directorySize field rootDirNodePtr->directorySize += nodeInfoPtr->numBytes; // Increment the number of audio tracks rootDirNodePtr->entryCount++; ( void ) BuildTrackName ( mountPtr, nodeInfoPtr ); DebugLog ( ( "LBA of %d = %ld.\n", trackDescriptorPtr->point, nodeInfoPtr->LBA ) ); } // Advance the pointers and decrement the count trackDescriptorPtr++; numberOfDescriptors--; currentOffset++; } if ( ( numberOfDescriptors != 0 ) && ( rootDirNodePtr->entryCount == ( numTracks + kNumberOfFakeDirEntries ) ) ) { // Oops...the parsing routine in userland must've screwed up DebugLog ( ( "ParseTOC: userland utility sent wrong number of audio tracks in at mount time.\n" ) ); } } else { // Couldn't parse the TOC, so return an error return ENOMEM; } Exit: if ( TOCDataPtr != NULL ) { // Free the buffer allocated earlier DisposeBufferFromIORegistry ( TOCDataPtr ); } DebugLog ( ( "ParseTOC: exiting...\n" ) ); return error; } //----------------------------------------------------------------------------- // BuildTrackName - This routine is responsible for building a track // name based on its number //----------------------------------------------------------------------------- int BuildTrackName ( mount_t mountPtr, AppleCDDANodeInfoPtr nodeInfoPtr ) { UInt8 trackNumber = 0; char * name = NULL; UInt8 nameSize = 0; int error = 0; DebugLog ( ( "BuildTrackName: entering.\n" ) ); DebugAssert ( ( nodeInfoPtr != NULL ) ); // Get the track number for which to find the name trackNumber = nodeInfoPtr->trackDescriptor.point; // Find the name error = FindName ( mountPtr, trackNumber, &name, &nameSize ); if ( error != 0 ) { DebugLog ( ( "cddafs : FindName returned error = %d\n", error ) ); // Buffer copied in was formatted incorrectly. We'll just use // track numbers on this CD. } // Set the size of the name nodeInfoPtr->nameSize = nameSize; // If we got here, then we have a valid track and the nodeInfoArrayPtr points to our // offset into the array. So, MALLOC the name here MALLOC ( nodeInfoPtr->name, char *, nodeInfoPtr->nameSize + 1, M_TEMP, M_WAITOK ); // Copy the name bcopy ( name, &nodeInfoPtr->name[0], nameSize ); // Don't forget NULL byte nodeInfoPtr->name[nameSize] = 0; DebugLog ( ( "BuildTrackName: fileName = %s\n", nodeInfoPtr->name ) ); return 0; } //----------------------------------------------------------------------------- // CalculateNumberOfDescriptors - Calculate the number of SubQTOCInfo entries // in the given TOC //----------------------------------------------------------------------------- UInt32 CalculateNumberOfDescriptors ( const QTOCDataFormat10Ptr TOCDataPtr ) { UInt32 numberOfDescriptors = 0; UInt32 length = 0; DebugLog ( ( "CalculateNumberOfDescriptors: Entering...\n" ) ); DebugAssert ( ( TOCDataPtr != NULL ) ); // Get the length of the TOC length = OSSwapBigToHostInt16 ( TOCDataPtr->TOCDataLength ); // Remove the first and last session numbers so all we are left with are track descriptors length -= ( UInt32 ) ( ( sizeof ( TOCDataPtr->firstSessionNumber ) + sizeof ( TOCDataPtr->lastSessionNumber ) ) ); // Divide the length by the size of a single track descriptor to get total number numberOfDescriptors = ( length / ( ( UInt32 ) sizeof ( SubQTOCInfo ) ) ); DebugLog ( ( "CalculateNumberOfDescriptors: exiting...\n" ) ); return numberOfDescriptors; } //----------------------------------------------------------------------------- // CalculateLBA - Convert the frames offset of the file (from the TOC) to // the LBA of the device // // NB: this is a workaround because the first 2 seconds of a CD are unreadable // and defined as off-limits. So we convert our absolute MSF to an actual // logical block which can be addressed through the BSD layer. //----------------------------------------------------------------------------- UInt32 CalculateLBA ( SubQTOCInfoPtr trackDescriptorPtr ) { UInt32 frames = 0; DebugAssert ( ( trackDescriptorPtr != NULL ) ); frames = ( ( ( trackDescriptorPtr->PMSF.startPosition.minutes * kSecondsPerMinute ) + trackDescriptorPtr->PMSF.startPosition.seconds ) * kFramesPerSecond ) + trackDescriptorPtr->PMSF.startPosition.frames; if ( frames < kMSFToLBA ) frames = kMSFToLBA; // Simply convert MSF to LBA return frames - kMSFToLBA; } //----------------------------------------------------------------------------- // End Of File //-----------------------------------------------------------------------------