//////////
//
//	File:		QTMovieFromProcs.c
//
//	Contains:	Sample code for creating a QuickTime movie using application-defined procedures.
//
//	Written by:	Tim Monroe
//				Based on sample code in the QuickTime 3.0 Reference document.
//
//	Copyright:	© 1998-1999 by Apple Computer, Inc., all rights reserved.
//
//	Change History (most recent first):
//
//	   <8>	 	03/32/00	rtm		removed calls to Standard File Package (FSSpec now passed in);
//									made changes to run under CarbonLib
//	   <7>	 	02/09/99	rtm		minor tweaks; verified on Windows and Mac; added more comments
//	   <6>	 	02/05/99	rtm		added code to enumerate all components that can export-by-procs
//									add their names to the Test menu, and use the selected exporter
//	   <5>	 	02/02/99	rtm		reworked prompt and filename handling to remove "\p" sequences
//	   <4>	 	11/11/98	rtm		minor tweaks; added more comments
//	   <3>	 	11/06/98	rtm		incorporated settings file code from QTHintMovies.c
//	   <2>	 	10/19/98	rtm		further work; works fine on Mac and Windows
//	   <1>	 	10/16/98	rtm		first file
//	 
//	QuickTime 3.0 provides functions that allow you to create a movie using data supplied by one or more
//	application-defined procedures. In particular, you use the function MovieExportAddDataSource to add a
//	track-generating procedure and you use the function MovieExportFromProceduresToDataRef to do the actual
//	movie exporting.
//
//	In this example, we will create a QuickTime movie with a video track and an audio track; we generate the
//	video track by drawing a series of individual frames, and we generate the audio track by generating
//	10 seconds of silence.
//
//	This sample code finds all movie export components that can export using application-defined procedures,
//	adds their names to a menu, and then calls the appropriate exporter when the user selects a menu item. The
//	only real interesting code in the QTMenu_ functions is the code that enumerates the available exporters
//	that can export-by-procedures.
//
//	This sample code snippet also illustrates how to configure the movie export component, using either
//	MovieExportDoUserDialog to display the component's settings dialog or MovieExportSetSettingsFromAtomContainer
//	to restore some previously-saved settings from an atom container. Note that any settings configured by the
//	user or by a call to MovieExportSetSettingsFromAtomContainer may be overridden by the settings returned by 
//	your track property callback function (in this sample, the functions QTMoovProcs_AudioTrackPropertyProc and
//	QTMoovProcs_VideoTrackPropertyProc).
//
//////////


#include "QTMovieFromProcs.h"


// global variables
QTMoovProcsAudioDataRec				gAudioDataRec;
QTMoovProcsVideoDataRec				gVideoDataRec;

MovieExportGetPropertyUPP			gAudioPropProcUPP = NULL;
MovieExportGetDataUPP				gAudioDataProcUPP = NULL;

MovieExportGetPropertyUPP			gVideoPropProcUPP = NULL;
MovieExportGetDataUPP				gVideoDataProcUPP = NULL;

QTProcExportersInfo					gExporterInfo;

extern ConstStr255Param				gSettingsFileName;

#if TARGET_OS_WIN32
extern HWND							ghWnd;					// the MDI frame window; this window has the menu bar
#include "ComResource.h"
#endif


//////////
//
// QTMoovProcs_CreateMovieFromProcs
// Create a QuickTime movie using audio- and video-data generating procedures.
//
//////////

OSErr QTMoovProcs_CreateMovieFromProcs (FSSpecPtr theOutputFile, MovieExportComponent theExporter, Boolean thePromptUser)
{	
	Handle						myDataRef = NULL;
	FSSpec						myPrefsFile;
	OSErr						myErr = userCanceledErr;

	if (theOutputFile == NULL)
		goto bail;
	
	// add sources of audio and video data to the movie exporter;
	// we ignore errors here, since some exporters might be audio-only or video-only
	myErr = QTMoovProcs_AddAudioSourceToExporter(theExporter);
	myErr = QTMoovProcs_AddVideoSourceToExporter(theExporter);
		
	// create a data reference for the output movie file
	myDataRef = NewHandle(sizeof(Handle));
    if (myDataRef == NULL)
    	goto bail;

	QTNewAlias(theOutputFile, (AliasHandle *)&myDataRef, true);
	
	// get the preferences file for this application
	QTMoovProcs_GetPrefsFileSpec(&myPrefsFile, (void *)(theOutputFile));
	
	// read existing movie exporter settings from a file; if we aren't going to prompt
	// the user for exporter settings, these stored settings will be used; otherwise,
	// these stored settings will be used as initial values in the settings dialog box
	QTUtils_GetExporterSettingsFromFile(theExporter, &myPrefsFile);
	
	if (thePromptUser) {
		Boolean		myCancelled = false;
		
		// display a dialog box to prompt the user for desired movie exporter settings		
		myErr = MovieExportDoUserDialog(theExporter, NULL, NULL, 0, 0, &myCancelled);
		if (myCancelled)
			goto bail;
		
		// save the existing settings into our preferences file
		QTUtils_SaveExporterSettingsInFile(theExporter, &myPrefsFile);
	}
		
	// export the audio and video data to the data reference
	myErr = MovieExportFromProceduresToDataRef(theExporter, myDataRef, rAliasType);
	
bail:
	// dispose of the routine descriptors
	DisposeMovieExportGetPropertyUPP(gAudioPropProcUPP);
	DisposeMovieExportGetDataUPP(gAudioDataProcUPP);
	DisposeMovieExportGetPropertyUPP(gVideoPropProcUPP);
	DisposeMovieExportGetDataUPP(gVideoDataProcUPP);
	
	// dispose of any memory that we allocated before or during the export operation
    if (myDataRef != NULL)
    	DisposeHandle(myDataRef);
	
	if (gAudioDataRec.fSoundData != NULL)
		DisposePtr(gAudioDataRec.fSoundData);
		
	if (gAudioDataRec.fSoundDescription != NULL)
		DisposeHandle((Handle)gAudioDataRec.fSoundDescription);
		
	if (gVideoDataRec.fGWorld != NULL)
		DisposeGWorld(gVideoDataRec.fGWorld);
		
	if (gVideoDataRec.fImageDescription != NULL)
		DisposeHandle((Handle)gVideoDataRec.fImageDescription);
		
	return(myErr);
}


//////////
//
// QTMoovProcs_AddAudioSourceToExporter
// Attach a source for audio data to the specified movie exporter.
//
//////////

OSErr QTMoovProcs_AddAudioSourceToExporter (MovieExportComponent theExporter)
{	
	SoundDescriptionPtr			mySoundDescPtr = NULL;
	short						myIndex;
	OSErr						myErr = memFullErr;
		
	// create a buffer to hold the audio data
	gAudioDataRec.fSoundData = NewPtrClear(kSoundBufferSize);
	if (gAudioDataRec.fSoundData == NULL)
		goto bail;
	
	// our sound data format is 8-bit, offset binary, where a sample point is an 8-bit value
	// in the range 0 to 255 (0x00 to 0xFF); for silence, set all sample points to 128 (0x80)
	for (myIndex = 0; myIndex < kSoundBufferSize; myIndex++)
		gAudioDataRec.fSoundData[myIndex] = (UInt8)128;
	
	// create and configure a sound description record
	gAudioDataRec.fSoundDescription = (SoundDescriptionHandle)NewHandleClear(sizeof(SoundDescription));
	if (gAudioDataRec.fSoundDescription == NULL)
		goto bail;

	mySoundDescPtr = *(gAudioDataRec.fSoundDescription);
	mySoundDescPtr->descSize = sizeof(SoundDescription);
	mySoundDescPtr->dataFormat = k8BitOffsetBinaryFormat;
	mySoundDescPtr->numChannels = 1;
	mySoundDescPtr->sampleSize = 8;
	mySoundDescPtr->sampleRate = kAudioSampleRate << 16;
	
	// create UPPs for the two app-defined export functions
	gAudioPropProcUPP = NewMovieExportGetPropertyUPP(QTMoovProcs_AudioTrackPropertyProc);
	gAudioDataProcUPP = NewMovieExportGetDataUPP(QTMoovProcs_AudioTrackDataProc);
	
	myErr = MovieExportAddDataSource(theExporter,
										SoundMediaType,
										kAudioSampleRate,
										&gAudioDataRec.fTrackID,
										gAudioPropProcUPP,
										gAudioDataProcUPP,
										&gAudioDataRec);

bail:
	return(myErr);
}


//////////
//
// QTMoovProcs_AddVideoSourceToExporter
// Attach a source for video data to the specified movie exporter.
//
//////////

OSErr QTMoovProcs_AddVideoSourceToExporter (MovieExportComponent theExporter)
{	
	OSErr	myErr = noErr;

	gVideoDataRec.fGWorld = NULL;	
	gVideoDataRec.fImageDescription = NULL;
	
	// create UPPs for the two app-defined export functions
	gVideoPropProcUPP = NewMovieExportGetPropertyUPP(QTMoovProcs_VideoTrackPropertyProc);
	gVideoDataProcUPP = NewMovieExportGetDataUPP(QTMoovProcs_VideoTrackDataProc);
	
	myErr = MovieExportAddDataSource(theExporter,
										VideoMediaType,
										kVideoSampleRate,
										&gVideoDataRec.fTrackID,
										gVideoPropProcUPP,
										gVideoDataProcUPP,
										&gVideoDataRec);

	return(myErr);
}


//////////
//
// QTMoovProcs_AudioTrackPropertyProc
// Handle requests for information about the output audio data.
//
//////////

PASCAL_RTN OSErr QTMoovProcs_AudioTrackPropertyProc (void *theRefcon, long theTrackID, OSType thePropertyType, void *thePropertyValue)
{
#pragma unused(theRefcon, theTrackID)

	OSErr	myErr = noErr;
	
	switch (thePropertyType) {
	
		case scSoundSampleRateType:
			*(Fixed *)thePropertyValue = 32000L << 16;
			break;
			
		default:
			myErr = paramErr;	// non-zero value means: use default value provided by export component
			break;
	}
	
	return(myErr);
}


//////////
//
// QTMoovProcs_AudioTrackDataProc
// Provide the output audio data.
//
//////////

PASCAL_RTN OSErr QTMoovProcs_AudioTrackDataProc (void *theRefcon, MovieExportGetDataParams *theParams)
{
	QTMoovProcsAudioDataRecPtr	myAudioDataRecPtr;
	OSErr						myErr = noErr;
	
	myAudioDataRecPtr = (QTMoovProcsAudioDataRecPtr)theRefcon;

	// end the data after desired length of movie
	if (theParams->requestedTime > kAudioSampleRate * kMovieLengthInSeconds)
		return(eofErr);
	
	theParams->actualTime = theParams->requestedTime;
	theParams->dataPtr = myAudioDataRecPtr->fSoundData;
	theParams->dataSize = kSoundBufferSize;
	theParams->desc = (SampleDescriptionHandle)(myAudioDataRecPtr->fSoundDescription);
	theParams->descType = SoundMediaType;
	theParams->descSeed = 1;
	theParams->actualSampleCount = kSoundBufferSize;
	theParams->durationPerSample = 1;
	theParams->sampleFlags = 0L;
	
	return(myErr);
}


//////////
//
// QTMoovProcs_VideoTrackPropertyProc
// Handle requests for information about the output video data.
//
//////////

PASCAL_RTN OSErr QTMoovProcs_VideoTrackPropertyProc (void *theRefcon, long theTrackID, OSType thePropertyType, void *thePropertyValue)
{
#pragma unused(theRefcon, theTrackID)

	OSErr	myErr = noErr;
	
	switch (thePropertyType) {
		case movieExportWidth:
			*(Fixed *)thePropertyValue = kVideoFrameWidth << 16;
			break;
			
		case movieExportHeight:
			*(Fixed *)thePropertyValue = kVideoFrameHeight << 16;
			break;

		case scSpatialSettingsType: {
			SCSpatialSettings		*mySpatialSettings = thePropertyValue;
			
			mySpatialSettings->codecType = kJPEGCodecType;
			mySpatialSettings->codec = 0;
			mySpatialSettings->depth = 0;
			mySpatialSettings->spatialQuality = codecNormalQuality;
		}
			break;

		default:
			myErr = paramErr;	// non-zero value means: use default value provided by export component
			break;
	}
	
	return(myErr);
}


//////////
//
// QTMoovProcs_VideoTrackDataProc
// Provide the output audio data.
//
//////////

PASCAL_RTN OSErr QTMoovProcs_VideoTrackDataProc (void *theRefcon, MovieExportGetDataParams *theParams)
{	
	QTMoovProcsVideoDataRecPtr	myVideoDataRecPtr;
	PixMapHandle				myPixMap = NULL;
	Rect						myRect;		
	CGrafPtr					myOldPort = NULL;
	GDHandle					myOldDevice = NULL;
	Str255						myString;
	static long					myFrameNum = 0;
	OSErr						myErr = noErr;
	
	myVideoDataRecPtr = (QTMoovProcsVideoDataRecPtr)theRefcon;
	
	// end the data after desired length of movie
	if (theParams->requestedTime > kVideoSampleRate * kMovieLengthInSeconds)
		return(eofErr);
	
	// set the size of the video frame
	MacSetRect(&myRect, 0, 0, kVideoFrameWidth, kVideoFrameHeight);

	// if we haven't allocated a GWorld yet, do so now
	if (myVideoDataRecPtr->fGWorld == NULL) {
		NewGWorld(&(myVideoDataRecPtr->fGWorld), 32, &myRect, NULL, NULL, (GWorldFlags)0);
		if (myVideoDataRecPtr->fGWorld == NULL)
			return(memFullErr);
			
		myPixMap = GetGWorldPixMap(myVideoDataRecPtr->fGWorld);
		if (myPixMap == NULL)
			return(memFullErr);
		
		LockPixels(myPixMap);
		
		myErr = MakeImageDescriptionForPixMap(myPixMap, &(myVideoDataRecPtr->fImageDescription));
		if (myErr != noErr)
			goto bail;
	}
	
	GetGWorld(&myOldPort, &myOldDevice);
	SetGWorld(myVideoDataRecPtr->fGWorld, NULL);
	
	// draw a frame: white rectangle with black frame number centered horizontally in frame
	EraseRect(&myRect);
	ForeColor(whiteColor);
	PaintRect(&myRect);

	ForeColor(blackColor);
	
	NumToString(++myFrameNum, myString);
	MoveTo((short)(myRect.right / 2) - (StringWidth(myString) / 2), (short)(myRect.bottom / 2));
	TextSize((short)(myRect.bottom / 4));
	DrawString(myString);

	theParams->actualTime = theParams->requestedTime;
	theParams->dataPtr = GetPixBaseAddr(GetGWorldPixMap(myVideoDataRecPtr->fGWorld));
	theParams->dataSize = (**(myVideoDataRecPtr->fImageDescription)).dataSize;
	theParams->desc = (SampleDescriptionHandle)(myVideoDataRecPtr->fImageDescription);
	theParams->descType = VideoMediaType;
	theParams->descSeed = 1;
	theParams->actualSampleCount = 1;
	theParams->durationPerSample = kVideoFrameDuration;
	theParams->sampleFlags = 0L;

bail:
	// restore the original graphics port and device
	SetGWorld(myOldPort, myOldDevice);
	
	return(myErr);
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Menu utilities.
//
// Use these functions to add component names to a menu and to handle user selections in that menu. These
// exist mainly to illustrate how to find all movie export components that can export using application-
// defined procedures. 
//
// It's useful to remember that Macintosh menu items are numbered from 1, whereas Windows menu items are
// numbered from 0.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////

//////////
//
// QTMenu_InitializeTestMenu
// Initialize the Test menu; add component names to it.
//
//////////

OSErr QTMenu_InitializeTestMenu (void)
{
	short			myIndex;
	short			myNumItems;

#if TARGET_OS_MAC
	gExporterInfo.fTestMenuHandle = GetMenuHandle(kTestMenuID);
	
	// remove any existing menu items
	myNumItems = CountMenuItems(gExporterInfo.fTestMenuHandle);
	for (myIndex = 0; myIndex < myNumItems; myIndex++)
		DeleteMenuItem(gExporterInfo.fTestMenuHandle, 1);
#elif TARGET_OS_WIN32
	gExporterInfo.fTestMenuHandle = GetSubMenu(GetMenu(ghWnd), WINDOWMENU - 1);

	// remove any existing menu items
	myNumItems = GetMenuItemCount(gExporterInfo.fTestMenuHandle);
	for (myIndex = 0; myIndex < myNumItems; myIndex++)
		RemoveMenu(gExporterInfo.fTestMenuHandle, 0, MF_BYPOSITION);
#endif

	gExporterInfo.fNextAvailIndex = 0;
	
	// add names of all components that can export-by-procedures to Test menu
	QTMenu_AddComponentNamesToMenu();
	
	return(noErr);
}


//////////
//
// QTMenu_AddComponentNamesToMenu
// Add the name of all movie export components that can export-by-procedures to the Test menu.
//
//////////

OSErr QTMenu_AddComponentNamesToMenu (void)
{
	Component				myComponent = NULL;
	Handle					myCompName = NewHandleClear(0);
	ComponentDescription	myCompDesc;
	
	// find all movie export components that can export-by-procedures
	do {
		myCompDesc.componentType = MovieExportType;
		myCompDesc.componentSubType = 0;
		myCompDesc.componentManufacturer = 0;
		myCompDesc.componentFlags = canMovieExportFromProcedures;
		myCompDesc.componentFlagsMask = canMovieExportFromProcedures;
	
		myComponent = FindNextComponent(myComponent, &myCompDesc);
		if (myComponent != NULL) {
			// get the component information
			GetComponentInfo(myComponent, &myCompDesc, myCompName, NULL, NULL);

			// add the component's name to the menu
#if TARGET_OS_MAC		
			MacAppendMenu(gExporterInfo.fTestMenuHandle, (StringPtr)*myCompName);
#elif TARGET_OS_WIN32
			AppendMenu(gExporterInfo.fTestMenuHandle, MF_STRING | MF_ENABLED, MENU_IDENTIFIER(kTestMenu, gExporterInfo.fNextAvailIndex + 1), p2cstr((StringPtr)*myCompName));
#endif			
			// keep track of this component
			gExporterInfo.fComponentType[gExporterInfo.fNextAvailIndex] = myCompDesc.componentType;
			gExporterInfo.fComponentSubType[gExporterInfo.fNextAvailIndex] = myCompDesc.componentSubType;
			gExporterInfo.fComponentManufacturer[gExporterInfo.fNextAvailIndex] = myCompDesc.componentManufacturer;
			
			gExporterInfo.fNextAvailIndex++;
		}
	} while (myComponent != NULL);
	
	if (myCompName != NULL)
		DisposeHandle(myCompName);
	
	return(noErr);
}


//////////
//
// QTMenu_HandleTestMenu
// Handle user selection of items in the Test menu.
//
//////////

OSErr QTMenu_HandleTestMenu (UInt16 theMenuItem)
{
	MovieExportComponent		myExporter = NULL;
	ComponentDescription		myCompDesc;
	short						myIndex; 
	OSErr						myErr = noErr;
	
	myIndex = MENU_ITEM(theMenuItem) - 1;
	if ((myIndex < 0) || (myIndex >= gExporterInfo.fNextAvailIndex))
		return(paramErr);
	
	myCompDesc.componentType = gExporterInfo.fComponentType[myIndex];
	myCompDesc.componentSubType = gExporterInfo.fComponentSubType[myIndex];
	myCompDesc.componentManufacturer = gExporterInfo.fComponentManufacturer[myIndex];
	myCompDesc.componentFlags = canMovieExportFromProcedures;
	myCompDesc.componentFlagsMask = canMovieExportFromProcedures;

	// open the selected movie export component
	myExporter = OpenComponent(FindNextComponent(NULL, &myCompDesc));
	if (myExporter == NULL)
		return(badComponentType);
		
	// create the movie using application-defined procedures
	myErr = QTMoovProcs_CreateMovieFromProcs(myExporter, true);
	
	// close the movie export component
	if (myExporter != NULL)
		CloseComponent(myExporter);
		
	return(myErr);
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Settings utilities.
//
// Use these functions to save/retrieve movie exporter settings into/from a preferences file.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////

//////////
//
// QTMoovProcs_GetPrefsFileSpec
// Fill in the specified FSSpec with info about this application's preferences file.
//
// The theRefCon parameter is a pointer to some application-specific data, which you
// might use to find the preferences file; here, we assume it's a pointer to an FSSpec
// for the output hinted file. We'll specify a preferences file in the same folder as
// the hinted file that has the name specified by the global variable gSettingsFileName.
//
//////////

OSErr QTMoovProcs_GetPrefsFileSpec (FSSpecPtr thePrefsSpecPtr, void *theRefCon)
{
	FSSpecPtr	myFSSpecPtr = (FSSpecPtr)theRefCon;
	OSErr		myErr = noErr;

	if (myFSSpecPtr == NULL)
		return(paramErr);
		
	myErr = FSMakeFSSpec(myFSSpecPtr->vRefNum, myFSSpecPtr->parID, gSettingsFileName, thePrefsSpecPtr);
	
	return(myErr);
}


//////////
//
// QTUtils_SaveExporterSettingsInFile
// Get the current settings of the specified movie exporter and save them into a file.
//
//////////

OSErr QTUtils_SaveExporterSettingsInFile (MovieExportComponent theExporter, FSSpecPtr theFSSpecPtr)
{	
	QTAtomContainer		myContainer = NULL;
	ComponentResult		myErr = noErr;
		
	myErr = MovieExportGetSettingsAsAtomContainer(theExporter, &myContainer);
	if (myErr != noErr)
		goto bail;
		
	myErr = QTUtils_WriteHandleToFile((Handle)myContainer, theFSSpecPtr);

bail:
	if (myContainer != NULL)
		QTDisposeAtomContainer(myContainer);
		
	return((OSErr)myErr);
}


//////////
//
// QTUtils_GetExporterSettingsFromFile
// Read the movie exporter settings saved in the specified file.
//
//////////

OSErr QTUtils_GetExporterSettingsFromFile (MovieExportComponent theExporter, FSSpecPtr theFSSpecPtr)
{	
	Handle				myHandle = NULL;
	ComponentResult		myErr = fnfErr;		// assume we cannot find the file
		
	myHandle = QTUtils_ReadHandleFromFile(theFSSpecPtr);
	if (myHandle == NULL)
		goto bail;
		
	myErr = MovieExportSetSettingsFromAtomContainer(theExporter, (QTAtomContainer)myHandle);
		
bail:
	if (myHandle != NULL)
		DisposeHandle(myHandle);
		
	return((OSErr)myErr);
}


//////////
//
// QTUtils_WriteHandleToFile
// Write the data in the specified handle into the specified file;
// if the file already exists, it is overwritten.
//
//////////

OSErr QTUtils_WriteHandleToFile (Handle theHandle, FSSpecPtr theFSSpecPtr)
{
	short			myRefNum = 0;
#if TARGET_OS_MAC	
	short			myVolNum;
#endif
	long			mySize = 0;
	OSErr			myErr = paramErr;

	if (theHandle == NULL)
		goto bail;

	mySize = GetHandleSize(theHandle);
	if (mySize == 0)
		goto bail;

	HLock(theHandle);
	
	// delete the file;
	// if it doesn't exist yet, we'll get an error (fnfErr), which we just ignore
	myErr = FSpDelete(theFSSpecPtr);
	
	// create and open the file
	myErr = FSpCreate(theFSSpecPtr, kSettingsFileCreator, kSettingsFileType, smSystemScript);

	if (myErr == noErr)
		myErr = FSpOpenDF(theFSSpecPtr, fsRdWrPerm, &myRefNum);
	
	// position the file mark to the beginning of the file and write the data
	if (myErr == noErr)
		myErr = SetFPos(myRefNum, fsFromStart, 0);

	if (myErr == noErr)
		myErr = FSWrite(myRefNum, &mySize, *theHandle);

	if (myErr == noErr)
		myErr = SetFPos(myRefNum, fsFromStart, mySize);

	// resize the file to the number of bytes written
	if (myErr == noErr)
		myErr = SetEOF(myRefNum, mySize);
				
	// close the file			 
	if (myErr == noErr)		
		myErr = FSClose(myRefNum);

#if TARGET_OS_MAC	
	// flush the volume
	if (myErr == noErr)		
		myErr = GetVRefNum(myRefNum, &myVolNum);

	if (myErr == noErr)		
		myErr = FlushVol(NULL, myVolNum);
#endif	

bail:
	HUnlock(theHandle);

	return(myErr);
}


//////////
//
// QTUtils_ReadHandleFromFile
// Read the data in the specified file into a new handle.
//
//////////

Handle QTUtils_ReadHandleFromFile (FSSpecPtr theFSSpecPtr)
{
	Handle			myHandle = NULL;
	short			myRefNum = 0;
	long			mySize = 0;
	OSErr			myErr = noErr;

	// open the file
	myErr = FSpOpenDF(theFSSpecPtr, fsRdWrPerm, &myRefNum);
	
	if (myErr == noErr)
		myErr = SetFPos(myRefNum, fsFromStart, 0);

	// get the size of the file data
	if (myErr == noErr)
		myErr = GetEOF(myRefNum, &mySize);
		
	// allocate a new handle
	if (myErr == noErr)
		myHandle = NewHandleClear(mySize);
	
	if (myHandle == NULL)
		goto bail;

	HLock(myHandle);

	// read the data from the file into the handle
	if (myErr == noErr)
		myErr = FSRead(myRefNum, &mySize, *myHandle);

bail:
	HUnlock(myHandle);
	
	if (myRefNum != 0)		
		FSClose(myRefNum);

	return(myHandle);
}



