/* Adjustments for pluginized VM
 *
 * Note: The Mac support files have not yet been fully converted to
 * pluginization. For the time being, it is assumed that they are linked
 * with the VM. When conversion is complete, they will no longer import
 * "sq.h" and they will access all VM functions and variables through
 * the interpreterProxy mechanism.
 
 Feb 2nd 2001, JMM rewrote, using more current file manager logic.
 3.0.7 return correct response on findimage
 3.0.10 Mimimal VM logic
 */

#include "sq.h"
#include "FilePlugin.h"

/* End of adjustments for pluginized VM */

#include <Files.h>
#include <Strings.h>
#ifndef __MPW__
#include <path2fss.h>
#else
#include <Aliases.h>
#include <StandardFile.h>
#include <Gestalt.h>
#endif

#include <Navigation.h>


/***
	The interface to the directory primitive is path based.
	That is, the client supplies a Squeak string describing
	the path to the directory on every call. To avoid traversing
	this path on every call, a cache is maintained of the last
	path seen, along with the Mac volume and folder reference
	numbers corresponding to that path.
***/

/*** Constants ***/
#define ENTRY_FOUND     0
#define NO_MORE_ENTRIES 1
#define BAD_PATH        2

#define DELIMITOR ':'
#define MAX_PATH 2000

/*** Variables ***/
char lastPath[MAX_PATH + 1];
int  lastPathValid = false;
FSSpec lastSpec;

/*** Functions ***/
int convertToSqueakTime(int macTime);
int equalsLastPath(char *pathString, int pathStringLength);
int lookupPath(char *pathString, int pathStringLength, FSSpec *spec,Boolean noDrillDown);
int recordPath(char *pathString, int pathStringLength, FSSpec *spec);
void makePascalStringFromSqName(char *pathString, int pathStringLength,unsigned char *name);
OSErr makeFSSpec(char *pathString, int pathStringLength,FSSpec *spec);
OSErr getSpecAndFInfo(char *filename, int filenameSize,FSSpec *spec,FInfo *finderInfo);
int fetchFileInfo(CInfoPBRec *pb,int dirIndex,FSSpec *spec,unsigned char *name, Boolean doAlias, Boolean *isFolder);
int doItTheHardWay(unsigned char *pathString,FSSpec *spec,CInfoPBRec *pb,Boolean noDrillDown);
pascal	OSErr	FSMakeFSSpecCompat(short vRefNum,
								   long dirID,
								   ConstStr255Param fileName,
								   FSSpec *spec);
OSErr FSpLocationFromFullPath(short fullPathLength,
									 const void *fullPath,
									 FSSpec *spec);
									 
pascal	OSErr	GetFullPath(short vRefNum,
							long dirID,
							ConstStr255Param name,
							short *fullPathLength,
							Handle *fullPath);

pascal	OSErr	FSpGetFullPath(const FSSpec *spec,
							   short *fullPathLength,
							   Handle *fullPath);
							   
OSErr squeakFindImage(const FSSpecPtr defaultLocationfssPtr,FSSpecPtr documentfsSpec);
pascal void findImageEventProc(NavEventCallbackMessage callBackSelector, 
                        NavCBRecPtr callBackParms, 
                        NavCallBackUserData callBackUD);
pascal Boolean findImageFilterProc(AEDesc* theItem, void* info, 
                            NavCallBackUserData callBackUD,
                            NavFilterModes filterMode);                        						
pascal short DialogHook(short item, DialogPtr theDialog, 
	void *userData);
	
OSErr __path2fss(const char * pathName, FSSpecPtr spec)
{
    return lookupPath((char *) pathName, strlen(pathName),spec,true);
}
									 								 
int convertToSqueakTime(int macTime) {
	/* Squeak epoch is Jan 1, 1901, 3 non-leap years earlier than Mac one */
	return macTime + (3 * 365 * 24 * 60 * 60);
}

void makePascalStringFromSqName(char *pathString, int pathStringLength,unsigned char *name)
{
	/* copy file name into a Pascal string */
	
	name[0] = pathStringLength;
	strncpy((char *)name+1,pathString,pathStringLength);

} 

OSErr makeFSSpec(char *pathString, int pathStringLength,FSSpec *spec)
{	
	char name[256];
	
	if (pathStringLength > 255 ) 
	    return -1;
   
    strncpy((char *) name,pathString,pathStringLength);
    name[pathStringLength] = 0x00;
    return __path2fss((char *) name, spec);
}

int dir_Create(char *pathString, int pathStringLength) {
	/* Create a new directory with the given path. By default, this
	   directory is created in the current directory. Use
	   a full path name such as "MyDisk:Working:New Folder" to
	   create folders elsewhere. */

    //JMM tests create file in Vm directory, other place, other volume
    
    FSSpec spec;
    OSErr  err;
    long  createdDirID;
    
    if ((err = makeFSSpec(pathString, pathStringLength,&spec)) == -1)
        return false;
        
   	return FSpDirCreate(&spec,smSystemScript,&createdDirID) == noErr;
}

int dir_Delete(char *pathString, int pathStringLength) {
	/* Delete the existing directory with the given path. */
    FSSpec spec;
    OSErr  err;

    if ((err = makeFSSpec(pathString, pathStringLength,&spec)) == -1)
        return false;
        
   	return FSpDelete(&spec) == noErr;
}

int dir_Delimitor(void) {
	return DELIMITOR;
}

int dir_Lookup(char *pathString, int pathStringLength, int index,
  /* outputs: */
  char *name, int *nameLength, int *creationDate, int *modificationDate,
  int *isDirectory, int *sizeIfFile) {
	/* Lookup the index-th entry of the directory with the given path, starting
	   at the root of the file system. Set the name, name length, creation date,
	   creation time, directory flag, and file size (if the entry is a file).
	   Return:	0 	if a entry is found at the given index
	   			1	if the directory has fewer than index entries
	   			2	if the given path has bad syntax or does not reach a directory
	*/

	int okay;
	HVolumeParam volumeParams;
	CInfoPBRec dirParams;
    FSSpec      spec;
    Boolean     isFolder;
    OSErr       err;
    
	/* default return values */
	*name             = 0;
	*nameLength       = 0;
	*creationDate     = 0;
	*modificationDate = 0;
	*isDirectory      = false;
	*sizeIfFile       = 0;

	if ((pathStringLength == 0)) {
		/* get volume info */
		volumeParams.ioNamePtr = (unsigned char *) name;
		volumeParams.ioVRefNum = 0;
		volumeParams.ioVolIndex = index;
		okay = PBHGetVInfoSync((HParmBlkPtr) &volumeParams) == noErr;
		if (okay) {
			CopyPascalStringToC((ConstStr255Param) name,name);
			*nameLength       = strlen(name);
			*creationDate     = convertToSqueakTime(volumeParams.ioVCrDate);
			*modificationDate = convertToSqueakTime(volumeParams.ioVLsMod);
			*isDirectory      = true;
			*sizeIfFile       = 0;
			return ENTRY_FOUND;
		} else {
			return NO_MORE_ENTRIES;
		}
	} else {
		/* get file or directory info */
		if (!equalsLastPath(pathString, pathStringLength)) {
			/* lookup and cache the refNum for this path */
			err = lookupPath(pathString, pathStringLength, &spec,false);
			if (err == noErr) 
				recordPath(pathString, pathStringLength, &spec);
			else 
				return BAD_PATH;
		}
	    spec = lastSpec;
		okay = fetchFileInfo(&dirParams,index,&spec,(unsigned char *) name,true,&isFolder);
		if (okay) {
			CopyPascalStringToC((ConstStr255Param) name,name);
			*nameLength       = strlen(name);
			*creationDate     = convertToSqueakTime(dirParams.hFileInfo.ioFlCrDat);
			*modificationDate = convertToSqueakTime(dirParams.hFileInfo.ioFlMdDat);
			if (((dirParams.hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0) || isFolder) {
				*isDirectory  = true;
				*sizeIfFile   = 0;
			} else {
				*isDirectory  = false;
				*sizeIfFile   = dirParams.hFileInfo.ioFlLgLen;
			}
			return ENTRY_FOUND;
		} else
			return NO_MORE_ENTRIES;
	}
}

OSErr getSpecAndFInfo(char *filename, int filenameSize,FSSpec *spec,FInfo *finderInfo) {
    OSErr err;
    
    if ((err = makeFSSpec(filename, filenameSize,spec)) != noErr)
        return err;
        
    if ((err= FSpGetFInfo(spec,finderInfo)) != noErr) 
        return err;
        
    return noErr;
}

dir_SetMacFileTypeAndCreator(char *filename, int filenameSize, char *fType, char *fCreator) {
	/* Set the Macintosh type and creator of the given file. */
	/* Note: On other platforms, this is just a noop. */

    FSSpec spec;
    FInfo   finderInfo;
    
    if (getSpecAndFInfo(filename,filenameSize,&spec,&finderInfo) != noErr)
        return false;
       
	finderInfo.fdType = *((int *) fType);
	finderInfo.fdCreator = *((int *) fCreator);
	
    return FSpSetFInfo(&spec,&finderInfo) == noErr;
}

dir_GetMacFileTypeAndCreator(char *filename, int filenameSize, char *fType, char *fCreator) {
	/* Get the Macintosh type and creator of the given file. */
	/* Note: On other platforms, this is just a noop. */

    FSSpec spec;
    FInfo   finderInfo;
    
    if (getSpecAndFInfo(filename,filenameSize,&spec,&finderInfo) != noErr)
        return false;
       
	*((int *) fType) = finderInfo.fdType;
	*((int *) fCreator) = finderInfo.fdCreator;

	return true;
}


int equalsLastPath(char *pathString, int pathStringLength) {
	/* Return true if the lastPath cache is valid and the
	   given Squeak string equals it. */

	int i, ch;

	if (!lastPathValid ||
		(pathStringLength > MAX_PATH)) {
			return false;
	}

	for (i = 0; i < pathStringLength; i++) {
		ch = lastPath[i];
		if ((ch == 0) || (ch != pathString[i])) return false;
	}
	return lastPath[i] == 0;
}


/*
JMM 2001/02/02 rewrote 
*/

int lookupPath(char *pathString, int pathStringLength, FSSpec *spec,Boolean noDrillDown) {
	/* Resolve the given path and return the resulting folder or volume
	   reference number in *refNumPtr. Return error if the path is bad. */

	CInfoPBRec      pb;
	Str255          tempName;
 	OSErr		    err;
    Boolean         ignore;
 
    /* First locate by farily normal methods, with perhaps an alias lookup */
    strncpy((char*)tempName,pathString,pathStringLength);
    tempName[0] = pathStringLength;

    err = FSMakeFSSpecCompat(0,0,tempName,spec);

    if (err == noErr) {
        if (noDrillDown == false) {
            fetchFileInfo(&pb,0,spec,spec->name,true,&ignore);
        }
        return noErr;
    }         
         
    /* Than failed, we might have an alias chain, or other issue so 
    first setup for directory or file then do it the hard way */
    
    strncpy((char *)tempName,pathString,pathStringLength);
    if (noDrillDown) {
        tempName[pathStringLength] = 0x00;
    }
    else {
        tempName[pathStringLength] = ':';
        tempName[pathStringLength+1] = 0x00;
    }

    err = doItTheHardWay(tempName,spec,&pb,noDrillDown);
    return err;
}

/* This method is used to lookup paths, chunk by chunk. It builds specs for each chuck and fetchs the file 
information, Note the special case when noDrilldown */

int doItTheHardWay(unsigned char *pathString,FSSpec *spec,CInfoPBRec *pb,Boolean noDrillDown) {
    char *token;
    Str255 lookup;
    Boolean ignore,firstTime=true;
    OSErr   err;
    
    token = strtok((char*) pathString,":");
    if (token == 0) return -1;
    while (token) 
    {
        if (firstTime) {
            strncpy((char*) lookup+1,(char*) token,63);
            lookup[0] = strlen(token)+1;
            lookup[lookup[0]] = ':';
            firstTime = false;
        } else {
            strncpy((char*) lookup+2,(char*) token,63);
            lookup[0] = strlen(token)+1;
            lookup[1] = ':';
        }
        if ((err = FSMakeFSSpecCompat(spec->vRefNum,spec->parID, lookup, spec)) != noErr) 
            return err;
        
        fetchFileInfo(pb,0,spec,spec->name,true,&ignore);
        token = strtok(NULL,":"); 
    }
   if (noDrillDown) 
       spec->parID = pb->dirInfo.ioDrParID;
     return noErr;
}

/*Get the file ID that unique IDs this file or directory, also resolve any alias if required */

int fetchFileInfo(CInfoPBRec *pb,int dirIndex,FSSpec *spec,unsigned char *name,Boolean doAlias,Boolean *isFolder) {
    int i;
    long    aliasGestaltInfo;
     
    *isFolder = false;
    pb->hFileInfo.ioNamePtr = name;
	pb->hFileInfo.ioFVersNum = 0;
	pb->hFileInfo.ioFDirIndex = dirIndex;
	pb->hFileInfo.ioVRefNum = spec->vRefNum;
	pb->hFileInfo.ioDirID = spec->parID;

	if (PBGetCatInfoSync(pb) == noErr) {
		if ((pb->hFileInfo.ioFlFndrInfo.fdFlags & kIsAlias) && doAlias) {
		    FSSpec spec2;
		    Boolean isAlias;
		    OSErr   err;
		    
		   
		   err = FSMakeFSSpecCompat(spec->vRefNum, spec->parID, name,&spec2);
#if TARGET_CPU_PPC
           if ((Gestalt(gestaltAliasMgrAttr, &aliasGestaltInfo) == noErr) &&
                aliasGestaltInfo & (1<<gestaltAliasMgrResolveAliasFileWithMountOptions)  &&
                ((Ptr) ResolveAliasFileWithMountFlags != (Ptr)kUnresolvedCFragSymbolAddress)) {
                err = ResolveAliasFileWithMountFlags(&spec2,false,isFolder,&isAlias,kResolveAliasFileNoUI);
            } 
            else 
#endif
    			err = ResolveAliasFile(&spec2,false,isFolder,&isAlias);
    		
    			
            if (err == noErr) {
            	if (dirIndex == 0) {
            	    fetchFileInfo(pb,dirIndex,&spec2,spec2.name,false,isFolder);
            	    *spec = spec2;
            	}
        		return true;
			}
		}
        spec->parID = pb->hFileInfo.ioDirID;
		return true;
	}
	return false;

}

int recordPath(char *pathString, int pathStringLength, FSSpec *spec) {
	/* Copy the given Squeak string into the lastPath cache. */

	if (pathStringLength > MAX_PATH) {
		lastPath[0] = 0; /* set to empty string */
		lastPathValid = false;
		lastSpec = *spec;
		return;
	}
	strncpy(lastPath,pathString,pathStringLength);
	lastPath[pathStringLength] = 0; /* string terminator */
	lastPathValid = true;
	lastSpec = *spec;
}


pascal	OSErr	GetFullPath(short vRefNum,
							long dirID,
							ConstStr255Param name,
							short *fullPathLength,
							Handle *fullPath)
{
	OSErr		result;
	FSSpec		spec;
	
	*fullPathLength = 0;
	*fullPath = NULL;
	
	result = FSMakeFSSpecCompat(vRefNum, dirID, name, &spec);
	if ( (result == noErr) || (result == fnfErr) )
	{
		result = FSpGetFullPath(&spec, fullPathLength, fullPath);
	}
	
	return ( result );
}

pascal	OSErr	FSpGetFullPath(const FSSpec *spec,
							   short *fullPathLength,
							   Handle *fullPath)
{
	OSErr		result;
	OSErr		realResult;
	FSSpec		tempSpec;
	CInfoPBRec	pb;
	
	*fullPathLength = 0;
	*fullPath = NULL;
	
	
	/* Default to noErr */
	realResult = result = noErr;
	
#if 0
//The following code doesn't seem to work in OS X, the BlockMoveData crashes the
// machine, the the FSMakeFSSpecCompat works, so go figure...  KG 4/1/01

	/* work around Nav Services "bug" (it returns invalid FSSpecs with empty names) */
	if ( spec->name[0] == 0 )
	{
		result = FSMakeFSSpecCompat(spec->vRefNum, spec->parID, spec->name, &tempSpec);
	}
	else
	{
		/* Make a copy of the input FSSpec that can be modified */
		BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
	}
#endif 0

	result = FSMakeFSSpecCompat(spec->vRefNum, spec->parID, spec->name, &tempSpec);


	if ( result == noErr )
	{
		if ( tempSpec.parID == fsRtParID )
		{
			/* The object is a volume */
			
			/* Add a colon to make it a full pathname */
			++tempSpec.name[0];
			tempSpec.name[tempSpec.name[0]] = ':';
			
			/* We're done */
			result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
			*fullPathLength = tempSpec.name[0];
		}
		else
		{
			/* The object isn't a volume */
			
			/* Is the object a file or a directory? */
			pb.dirInfo.ioNamePtr = tempSpec.name;
			pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
			pb.dirInfo.ioDrDirID = tempSpec.parID;
			pb.dirInfo.ioFDirIndex = 0;
			result = PBGetCatInfoSync(&pb);
			// Allow file/directory name at end of path to not exist.
			realResult = result;
			if ( (result == noErr) || (result == fnfErr) )
			{
				/* if the object is a directory, append a colon so full pathname ends with colon */
				if ( (result == noErr) && (pb.hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0 )
				{
					++tempSpec.name[0];
					tempSpec.name[tempSpec.name[0]] = ':';
				}
				
				/* Put the object name in first */
				result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
				*fullPathLength = tempSpec.name[0];
				if ( result == noErr )
				{
					/* Get the ancestor directory names */
					pb.dirInfo.ioNamePtr = tempSpec.name;
					pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
					pb.dirInfo.ioDrParID = tempSpec.parID;
					do	/* loop until we have an error or find the root directory */
					{
						pb.dirInfo.ioFDirIndex = -1;
						pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
						result = PBGetCatInfoSync(&pb);
						if ( result == noErr )
						{
							/* Append colon to directory name */
							++tempSpec.name[0];
							tempSpec.name[tempSpec.name[0]] = ':';
							
							/* Add directory name to beginning of fullPath */
							(void) Munger(*fullPath, 0, NULL, 0, &tempSpec.name[1], tempSpec.name[0]);
							*fullPathLength += tempSpec.name[0];
							result = MemError();
						}
					} while ( (result == noErr) && (pb.dirInfo.ioDrDirID != fsRtDirID) );
				}
			}
		}
	}
	
	if ( result == noErr )
	{
		/* Return the length */
///		*fullPathLength = GetHandleSize(*fullPath);
		result = realResult;	// return realResult in case it was fnfErr
	}
	else
	{
		/* Dispose of the handle and return NULL and zero length */
		if ( *fullPath != NULL )
		{
			DisposeHandle(*fullPath);
		}
		*fullPath = NULL;
		*fullPathLength = 0;
	}
	
	return ( result );
}


pascal	OSErr	FSMakeFSSpecCompat(short vRefNum,
								   long dirID,
								   ConstStr255Param fileName,
								   FSSpec *spec)
{
	OSErr	result;
	
	/* Let the file system create the FSSpec if it can since it does the job */
	/* much more efficiently than I can. */
	result = FSMakeFSSpec(vRefNum, dirID, fileName, spec);

	/* Fix a bug in Macintosh PC Exchange's MakeFSSpec code where 0 is */
	/* returned in the parID field when making an FSSpec to the volume's */
	/* root directory by passing a full pathname in MakeFSSpec's */
	/* fileName parameter. Fixed in Mac OS 8.1 */
	if ( (result == noErr) && (spec->parID == 0) )
		spec->parID = fsRtParID;
	return ( result );
}

OSErr FSpLocationFromFullPath(short fullPathLength,
									 const void *fullPath,
									 FSSpec *spec)
{
	AliasHandle	alias;
	OSErr		result;
	Boolean		wasChanged;
	Str32		nullString;
	
	/* Create a minimal alias from the full pathname */
	nullString[0] = 0;	/* null string to indicate no zone or server name */
	result = NewAliasMinimalFromFullPath(fullPathLength, fullPath, nullString, nullString, &alias);
	if ( result == noErr )
	{
		/* Let the Alias Manager resolve the alias. */
		result = ResolveAlias(NULL, alias, spec, &wasChanged);
		
		/* work around Alias Mgr sloppy volume matching bug */
		if ( spec->vRefNum == 0 )
		{
			/* invalidate wrong FSSpec */
			spec->parID = 0;
			spec->name[0] =  0;
			result = nsvErr;
		}
		DisposeHandle((Handle)alias);	/* Free up memory used */
	}
	return ( result );
}

typedef struct {
	StandardFileReply *theSFR;
	FSSpec *itemSpec;
} HookRecord, *HookRecordPtr;

OSErr squeakFindImage(const FSSpecPtr defaultLocationfssPtr,FSSpecPtr documentFSSpec)
{
    NavDialogOptions    dialogOptions;
    AEDesc              defaultLocation;
    NavEventUPP         eventProc = NewNavEventUPP(findImageEventProc);
    NavObjectFilterUPP  filterProc =  NewNavObjectFilterUPP(findImageFilterProc);
    OSErr               anErr = noErr;
    
#if !TARGET_API_MAC_CARBON 
#if   MINIMALVM
  if (true) {
#else
  if ((Ptr) NavGetDefaultDialogOptions==(Ptr)kUnresolvedCFragSymbolAddress ) {
#endif
      	//System pre 8.5 or system 7.x
    	// point my hook data record at the reply record and at
		// the file spec for the system file
		
     	StandardFileReply mySFR;
    	HookRecord hookRec;
	    DlgHookYDUPP	myDlgHookUPP;
    	SFTypeList mySFTypeList;
	    Point dialogPt;
	    
		hookRec.itemSpec = defaultLocationfssPtr;
		hookRec.theSFR = &mySFR;
		SetPt(&dialogPt, -1, -1);

		// Set up the universal proc pointer to your hook routine with this 
		// macro defined in StandardFile.h.  **NOTE** This is different
		// from the macro used for System 6 dialog hooks, and you should get
		// a compiler error if you try to use the wrong UPP with the wrong call.
		myDlgHookUPP = NewDlgHookYDProc(DialogHook);
		
		// call Std File
		CustomGetFile(nil, -1, mySFTypeList, &mySFR, 0, dialogPt, myDlgHookUPP,
			nil, nil, nil, &hookRec);
			
		// Dispose of the routine descriptor, since they do allocate memory..
		DisposeRoutineDescriptor(myDlgHookUPP);
		*documentFSSpec = mySFR.sfFile; 
		return !mySFR.sfGood;
	}
#endif
#if !MINIMALVM
    //  Specify default options for dialog box
    anErr = NavGetDefaultDialogOptions(&dialogOptions);
    if (anErr == noErr)
    {
        //  Adjust the options to fit our needs
        //  Set default location option
        dialogOptions.dialogOptionFlags |= kNavSelectDefaultLocation;
        dialogOptions.dialogOptionFlags |= kNavNoTypePopup;
        //  Clear preview option
        dialogOptions.dialogOptionFlags ^= kNavAllowPreviews;
        
        // make descriptor for default location
        anErr = AECreateDesc(typeFSS, defaultLocationfssPtr,
                             sizeof(*defaultLocationfssPtr),
                             &defaultLocation );
        if (anErr == noErr)
        {
            // Get 'open' resource. A nil handle being returned is OK,
            // this simply means no automatic file filtering.
            NavTypeListHandle typeList = (NavTypeListHandle)GetResource(
                                        'open', 128);
            NavReplyRecord reply;
            
            // Call NavGetFile() with specified options and
            // declare our app-defined functions and type list
            anErr = NavGetFile (&defaultLocation, &reply, &dialogOptions,
                                eventProc, nil, filterProc,
                                typeList, nil);
            if (anErr == noErr && reply.validRecord)
            {
                //  Deal with multiple file selection
                long    count;
                
                anErr = AECountItems(&(reply.selection), &count);
                // Set up index for file list
                if (anErr == noErr)
                {
                    long index;
                    
                    for (index = 1; index <= 1; index++)
                    {
                        AEKeyword   theKeyword;
                        DescType    actualType;
                        Size        actualSize;
                        
                        // Get a pointer to selected file
                        anErr = AEGetNthPtr(&(reply.selection), index,
                                            typeFSS, &theKeyword,
                                            &actualType,documentFSSpec,
                                            sizeof(FSSpec),
                                            &actualSize);
                     }
                }
                //  Dispose of NavReplyRecord, resources, descriptors
                anErr = NavDisposeReply(&reply);
            }
            if (typeList != NULL)
            {
                ReleaseResource( (Handle)typeList);
            }
            (void) AEDisposeDesc(&defaultLocation);
        }
    }
    DisposeNavEventUPP(eventProc);
    DisposeNavObjectFilterUPP(filterProc);
    return anErr;
#endif
}

pascal void findImageEventProc(NavEventCallbackMessage callBackSelector, 
                        NavCBRecPtr callBackParms, 
                        NavCallBackUserData callBackUD)
{
   // WindowPtr window = 
   //                 (WindowPtr)callBackParms->eventData.event->message;
    switch (callBackSelector)
    {
        case kNavCBEvent:
            switch (((callBackParms->eventData)
                    .eventDataParms).event->what)
            {
                case updateEvt:
                   // MyHandleUpdateEvent(window, 
                    //    (EventRecord*)callBackParms->eventData.event);
                    break;
            }
            break;
    }
}

pascal Boolean findImageFilterProc(AEDesc* theItem, void* info, 
                            NavCallBackUserData callBackUD,
                            NavFilterModes filterMode)
{
    OSErr theErr = noErr;
    Boolean display = true;
    NavFileOrFolderInfo* theInfo = (NavFileOrFolderInfo*)info;
    
    if (theItem->descriptorType == typeFSS)
        if (!theInfo->isFolder)
            if (theInfo->fileAndFolder.fileInfo.finderInfo.fdType 
                != 'STim')
                display = false;
    return display;
}

#if !TARGET_API_MAC_CARBON

// this dialog hook for System 7 std file selects
// the file specified by the hookRecord supplied as userData

pascal short DialogHook(short item, DialogPtr theDialog, 
	void *userData)
{
	HookRecordPtr hookRecPtr;
	
	hookRecPtr = (HookRecordPtr) userData;
	
	// hookRecPtr->itemSpec points to the FSSpec of the item to be selected
	// hookRecPtr->theSFR points to the standard file reply record

	// make sure we're dealing with the proper dialog
	if (GetWRefCon(theDialog) == sfMainDialogRefCon) {
	
		// just when opening the dialog...
		if (item == sfHookFirstCall) {
	
			// make the reply record hold the spec of the specified item
			hookRecPtr->theSFR->sfFile = *hookRecPtr->itemSpec;
			
			// ThereÕs a gotcha in Standard File when using sfHookChangeSelection. 
			// Even though New Inside Macintosh: Files has a sample that doesn't set
			// the sfScript field, it should be set, or the last object in the
			// selected directory  will always be selected.
			hookRecPtr->theSFR->sfScript = smSystemScript;

			// tell std file to change the selection to that item
			item = sfHookChangeSelection;
		}
	}			
		
	return item;
}
#endif

#ifndef __MPW__

#include <ansi_files.h>
#include <buffer_io.h>

int fflush(FILE * file)
{
	fpos_t	position;                    /* mm 970708 */
	ParamBlockRec pb;
    OSErr error;
	
	if (!file)
		return(__flush_all());
	
	if (file->state.error || file->mode.file_kind == __closed_file)
		return(EOF);
	
	if (file->mode.io_mode == __read)		/* mm 980430 */
		return 0;							/* mm 980430 */
	
	if (file->state.io_state >= __rereading)
		file->state.io_state = __reading;
	
	if (file->state.io_state == __reading)
		file->buffer_len = 0;
	
	if (file->state.io_state != __writing)
	{
		file->state.io_state = __neutral;  /* mm 970905 */
		return(0);
	}
	
#ifndef _No_Disk_File_OS_Support
	if (file->mode.file_kind != __disk_file || (position = ftell(file)) < 0)
		position = 0;
#else
	position = 0;
#endif
	
	if (__flush_buffer(file, NULL))
	{
		set_error(file);
		return(EOF);
	}
	
	file->state.io_state = __neutral;
	file->position       = position;
	file->buffer_len     = 0;
	
	pb.ioParam.ioRefNum = file->handle;
    error = PBFlushFileSync(&pb);
 
	return(0);
}
#endif
