/*===============================
 *	Finderesque.c
 *
 *	Blugs 1.1 content handler for Finder list views
 *	www.blugs.com
 *
 *	Copyright © 1998-2000 Brian Hall, Kyle Hammond
 *	Portions (the icon code) adapted from the Find_icon library © James W. Walker.
 *
 *===============================*/

#include "Finderesque.h"
#include "BlugsAppearanceExtras.h"

#ifndef __DEVICES__
#include <Devices.h>
#endif

#ifndef __FINDER__
#include <Finder.h>
#endif

#ifndef __FOLDERS__
#include <Folders.h>
#endif

#ifndef __GESTALT__
#include <Gestalt.h>
#endif

#ifndef __ICONS__
#include <Icons.h>
#endif

#ifndef __TOOLUTILS__
#include <ToolUtils.h>
#endif

#ifndef __SOUND__
#include <Sound.h>
#endif

#ifndef __TEXTUTILS__
#include <TextUtils.h>
#endif

#ifndef __LOWMEM__
#include <LowMem.h>
#endif



// The pixels added to the TERec's destRect.right so text won't wrap. The Finder uses
//	approximately this amount. Thankyou MacsBug!
#define kDestRectExtraRight					1000
#define kMaximumLength						31
#define finderesque_OffsetToText(indent)	(indent + 20)


static const RGBColor blackCol = {0,0,0}, whiteCol = {0xFFFF,0xFFFF,0xFFFF};
static Boolean gHasIconServices = false;

typedef struct
{
	TEHandle	inlineTE;
	Handle		icon; // Can be an icon suite or ref
	FSSpec		spec;
	Boolean		doingInline;
	Boolean		isAlias;
} FinderesqueData, **FinderesqueHdl;

static void				local_GetRegion( FinderesqueHdl dataH, const Rect* inCellRect, UInt16 indent, RgnHandle rgn );
static void				local_Draw( BLHandlerParamPtr param );
static void				local_InlineEditBegin( BLHandlerParamPtr param, FinderesqueHdl dataH );
static Boolean			local_InlineEditKey( BLHandlerParamPtr param, FinderesqueHdl dataH );
static Boolean			local_InlineEditClick( BLHandlerParamPtr param, FinderesqueHdl dataH );
static Boolean			local_InlineEditEnd( FinderesqueHdl dataH );
static void				local_DrawTextBox( Rect textRect );
static Boolean			local_Idle( BLHandlerParamPtr param, FinderesqueHdl dataH );
static FinderesqueHdl	local_AllocateStorage( void );
static void				local_Set( BLHandlerParamPtr param, FinderesqueHdl dataH );
static void				local_Get( BLHandlerParamPtr param, FinderesqueHdl dataH );
static SInt32			local_Sort( FinderesqueHdl fh1, BLHandlerParamPtr pp );
static SInt32			local_Search( BLHandlerParamPtr pp );
static void				local_IconRect( const Rect* inCellRect, UInt16 inIndent, Rect* outIconRect );
static Rect				local_AdjustTERect( FinderesqueHdl dataH, Rect cellRect, UInt16 indent );
static Rect				local_InlineTextRect( FinderesqueHdl dataH, Rect cellRect, UInt16 indent );
static Rect				local_NormalTextRect( FinderesqueHdl dataH, const Rect* inCellRect, UInt16 indent );
static Boolean			local_IsDisplayChar( UInt8 inChar );
static Boolean			local_IsWithinMaximum( UInt8 inChar, TEHandle inTE );


#if !__BL_USE_CARBON_API__
typedef struct
{
	OSType		fileCreator;
	OSType		fileType;
	short		DTRefNum;
} GetIconData;

typedef struct
{
	OSType	fileType;
	SInt32	iconID;
} FilePair;

typedef struct
{
	OSType	folderType;
	SInt32	iconID;
} FolderPair;

typedef struct
{
	short	whoCares[9];
	Str255	name;
} DriverHeader;



static OSErr	GetFileIcon( FSSpec *thing, IconSelectorValue iconSelector, Handle *theSuite);
static Boolean	IsSuiteEmpty( Handle theSuite );
static Boolean	IsVolEjected( short vRefNum );
static OSErr	GetCustomFileIcon(FSSpec *filespec, IconSelectorValue iconSelector, Handle *theSuite);
static OSErr	GetNormalFileIcon(CInfoPBRec *cpb, IconSelectorValue iconSelector, Handle *theSuite);
static void		GetFinderFilename(StringPtr _finderFilename);
static OSErr	GetCustomFolderIcon( SInt16 vRefNum, SInt32 dirID, IconSelectorValue selector,
									Handle *suite );
static OSErr	GetNormalFolderIcon( const CInfoPBRec* cpb, IconSelectorValue selector,
									Handle* suite );
static OSErr	GetVolumeIcon( SInt16 vRefNum, Handle* suite );
static pascal OSErr GetIconProc(ResType theType, Handle *theIcon, void *yourDataPtr);
static short	FindDesktopDatabase(short firstVRefNum, OSType fileCreator); // returns a DT refnum or 0
static Boolean	InOneDesktop(short vRefNum, OSType fileCreator, short *dtRefNum);
static pascal OSErr GetResourceIcons(Handle *theSuite, short theID, long theSelector);
static OSErr	CopyEachIcon(Handle theSuite);
static pascal OSErr CopyOneIcon(ResType theType, Handle *theIcon, void *yourDataPtr);
static short	FindGenericIconID(OSType theType, Boolean *inFinder);
static pascal OSErr Get1IconSuite(Handle *theSuite, short theID, IconSelectorValue theSelector);
static pascal OSErr Get1Icon(ResType theType, Handle *theIcon, short *resID);
static pascal OSErr TestHandle(ResType theType, Handle *theIcon, void *yourDataPtr);
static void			GetIconFileName( Str31 iconFileName );
static void		FIGetDriverName( SInt16 inDriverRefnum, StringPtr outName );



	#define GetQDGlobalsWhite(x)				(&qd.white)
	#define SetPortBackPixPat(port,pat)			(port->bkPixPat = pat)
	#define GetPortBackPixPat(port,pat)			(port->bkPixPat)

#endif // !__BL_USE_CARBON_API__


pascal UInt32 Finderesque(	BLMessage			message,
							BLHandlerParamPtr	param		)
{
	FinderesqueHdl		dataH = nil;
	UInt32				answer = 0;
	Rect				textRect;
	Boolean				doingInline = false;
	OSErr				err;
	ThemeDrawingState	saveState;
	
	if (param)
	{
		dataH = (FinderesqueHdl)param->ioStorage;
		if (dataH) doingInline = (*dataH)->doingInline;
	}
	if ((doingInline && message != blInlineEditCommandStatusMsg &&
		message != blInlineEditCommandProcessMsg) || message == blInlineEditBeginMsg)
	{
		err = BLGetThemeDrawingState( &saveState );
		err = BLNormalizeThemeDrawingState();
	}
	else saveState = nil;
	switch (message)
	{
		// Put it here for efficiency
		case blCellDrawMsg:
		if (dataH) local_Draw( param );
		break;
		
		case blHandlerInitMsg:
		{
			SInt32	response;
			
			answer = blWantsInlineEdit + blWantsSort + blWantsRegion + blWantsMin + blWantsHilite;
			response = 0;
			err = Gestalt( gestaltIconUtilitiesAttr, &response );
			if (!err && (response & gestaltIconUtilitiesHasIconServices))
	#if GENERATING_CFM
			if ( (UInt32)GetIconRef != kUnresolvedCFragSymbolAddress )
	#endif
			gHasIconServices = true;
			break;
		}
		
		case blCellInitMsg:
		if (param) param->ioStorage = (Handle)local_AllocateStorage();
		break;
		
		case blCellDeinitMsg:
		if (dataH)
		{
			Handle	icon;
			
			if ((*dataH)->doingInline) local_InlineEditEnd( dataH );
			icon = (*dataH)->icon;
			if (icon)
			{
				if (gHasIconServices) ReleaseIconRef( (IconRef)icon );
				else DisposeIconSuite( icon, true );
			}
			DisposeHandle( (Handle)dataH );
			// No need to zero storage in param block (Blugs does it for us)
		}
		break;
		
		case blCellSetDataMsg:
		local_Set( param, dataH );
		break;
		
		case blCellGetDataMsg:
		local_Get( param, dataH );
		break;
		
		case blCellRegionMsg:
		if (dataH) local_GetRegion( dataH, &param->inRect, param->inIndent, param->inRegion );
		break;
		
		case blInlineEditRegionMsg:
		if (dataH)
		{
			if (doingInline) textRect = local_InlineTextRect( dataH, param->inRect, param->inIndent );
			else
			{
				textRect = local_NormalTextRect( dataH, &param->inRect, param->inIndent );
				textRect.left--;
			}
			RectRgn( param->inRegion, &textRect );
		}
		break;
		
		case blInlineEditBeginMsg:
		if (dataH) local_InlineEditBegin( param, dataH );
		break;
		
		case blInlineEditKeyMsg:
		if (dataH) answer = local_InlineEditKey( param, dataH );
		break;
		
		case blInlineEditClickMsg:
		if (dataH) answer = local_InlineEditClick( param, dataH );
		break;
		
		case blInlineEditEndMsg:
		if (dataH) answer = local_InlineEditEnd( dataH );
		break;
		
		case blInlineEditCommandStatusMsg:
		answer = blInlineEditCommandStatusDisable;
		break;
		
		case blInlineEditCommandProcessMsg:
		if (param->ioCommand == kHICommandSelectAll) TESetSelect( 0, 32767, (*dataH)->inlineTE );
		break;
		
		case blCellIdleMsg:
		if (dataH && doingInline) answer = local_Idle( param, dataH );
		break;
		
		case blCellSortMsg:
		answer = local_Sort( dataH, param );
		break;
		
		case blCellSearchMsg:
		answer = local_Search( param );
		break;
		
		case blCellMinSizeMsg:
		param->outMinWidth = 100;
		param->outMinHeight = 0;
		break;
	}
	if (saveState) BLSetThemeDrawingState( saveState, true );
	return answer;
}

//===============================
static void local_GetRegion( FinderesqueHdl dataH, const Rect* inCellRect, UInt16 indent, RgnHandle rgn )
{
	Rect		iconRect, textRect;
	RgnHandle	tempRgn;
	
	tempRgn = NewRgn();
	local_IconRect( inCellRect, indent, &iconRect );
	RectRgn( tempRgn, &iconRect );
	textRect = local_NormalTextRect( dataH, inCellRect, indent );
	RectRgn( rgn, &textRect );
	UnionRgn( rgn, tempRgn, rgn );
	DisposeRgn( tempRgn );
}

//===============================
static void local_Draw( BLHandlerParamPtr param )
{
	FinderesqueHdl	dataH = (FinderesqueHdl)param->ioStorage;
	Rect			cellRect = param->inRect, textRect;
	Handle			icon;
	OSErr			err;
	UInt16			indent = param->inIndent;
	Boolean			selected = param->inIsSelected, doingInline = (*dataH)->doingInline;
	
	if (doingInline)
	{
		TEHandle	te = (*dataH)->inlineTE;
		
		textRect = local_InlineTextRect( dataH, cellRect, indent );
		if (te)
		{
			Rect	teViewRect;
			
			teViewRect = (*te)->viewRect;
			// In rare circumstances, the text rectangle can move after the TE record is created.
			// Most of the time Blugs tries to prevent this from happening, but a public call
			//	like BLMakeVisible can scroll without ending the inline edit session!
			if (!EqualRect( &textRect, &teViewRect ))
			{
				Rect	destRect;
				
				destRect = textRect;
				destRect.right += kDestRectExtraRight;
				(*te)->viewRect = textRect;
				(*te)->destRect = destRect;
			}
			TEUpdate( &textRect, te );
		}
		local_DrawTextBox( textRect );
	}
	else
	{
		Str255		truncatedString;
		Boolean		hasAqua, truncated;
		
		hasAqua = ((BLEnvironment() & blHasAqua) == blHasAqua);
		BlockMoveData( (*dataH)->spec.name, truncatedString, ((*dataH)->spec.name[0]) + 1 );
		if ((*dataH)->isAlias) TextFace( italic );
		err = BLTruncateString( truncatedString, kThemeCurrentPortFont,
								cellRect.right - (cellRect.left + finderesque_OffsetToText(indent)),
								(hasAqua) ? truncMiddle : truncEnd, &truncated );
		textRect = local_NormalTextRect( dataH, &cellRect, indent );
		// Do our hiliting first.
		if (selected) BLDrawHiliteRect( BLIsActive( param->inList ), &textRect );
		/*{
			RGBColor	saveColor, hiliteColor;
			Rect		hiliteRect;
			
			hiliteRect = textRect;
			if (!hasAqua) InsetRect( &hiliteRect, -1, -1 );
			LMGetHiliteRGB( &hiliteColor );
			GetForeColor( &saveColor );
			RGBForeColor( &hiliteColor );
			if (hiliteRect.right >= cellRect.right) hiliteRect.right = cellRect.right - 1;
			if (BLIsActive( param->inList )) PaintRect( &hiliteRect );
			else FrameRect( &hiliteRect );
			RGBForeColor( &saveColor );
		}*/
		err = BLDrawTextBox( &truncatedString[1], truncatedString[0], kThemeCurrentPortFont,
								kThemeStateActive, false, &textRect, teFlushDefault );
		TextFace( normal );
	}
	icon = (*dataH)->icon;
	if (icon)
	{
		IconTransformType	transform = 0;
		Boolean				active;
		Rect				iconRect;
		
		active = BLIsActive( param->inList );
		if (selected) transform += kTransformSelected;
		if (!active) transform += kTransformDisabled;
		local_IconRect( &cellRect, indent, &iconRect );
		if (gHasIconServices) err = PlotIconRef( &iconRect, kAlignNone, transform,
												kIconServicesNormalUsageFlag, (IconRef)icon );
		else err = PlotIconSuite( &iconRect, kAlignNone, transform, icon );
	}
}

//===============================
static void local_InlineEditBegin( BLHandlerParamPtr param, FinderesqueHdl dataH )
{
	Rect		viewRect, destRect, newRect;
	TEHandle	inlineTE;
	
	viewRect = local_NormalTextRect( dataH, &param->inRect, param->inIndent );
	viewRect.left--;
	destRect = viewRect;
	// Make sure TE doesn't try to wrap the text to a new line.
	destRect.right += kDestRectExtraRight;
	inlineTE = TENew( &destRect, &viewRect );
	if (inlineTE)
	{
		(*dataH)->doingInline = true;
		(*dataH)->inlineTE = inlineTE;
		TESetText( &((*dataH)->spec.name[1]), (*dataH)->spec.name[0], inlineTE );
		newRect = local_AdjustTERect( dataH, param->inRect, param->inIndent );
		TEActivate( inlineTE );
		TESetSelect( 0, 32767, inlineTE );
	}
}

//===============================
static Boolean local_InlineEditKey( BLHandlerParamPtr param, FinderesqueHdl dataH )
{
	TEHandle	inlineTE;
	
	inlineTE = (*dataH)->inlineTE;
	if (inlineTE)
	{
		UInt8	key;
		
		key = param->inEventMessage & charCodeMask;
		// We will not allow more than 31 characters
		if (local_IsWithinMaximum( key,inlineTE ))
		{
			Rect	oldRect, newRect;
			
			oldRect = local_InlineTextRect( dataH, param->inRect, param->inIndent );
			TEKey( key, inlineTE );
			// Resize the viewRect to hold the new character
			newRect = local_AdjustTERect( dataH, param->inRect, param->inIndent );
			if (!EqualRect(&oldRect,&newRect)) return blInlineEditKeyUpdate;
		}
		else SysBeep( 30 );
	}
	return blInlineEditKeyNoUpdate;
}

//===============================
static Boolean local_InlineEditClick( BLHandlerParamPtr param, FinderesqueHdl dataH )
{
	Point		where;
	Rect		textRect;
	TEHandle	inlineTE;
	
	inlineTE = (*dataH)->inlineTE;
	if (inlineTE)
	{
		textRect = local_InlineTextRect( dataH, param->inRect, param->inIndent );
		where = param->inEventWhereLocal;
		if (PtInRect(where,&textRect))
		{
			TEClick( where, false, inlineTE );
			return blInlineEditClickHandled;
		}
	}
	return blInlineEditClickNotHandled;
}

//===============================
static Boolean local_InlineEditEnd( FinderesqueHdl dataH )
{
	TEHandle	inlineTE;
	Boolean		answer = false;
	
	inlineTE = (*dataH)->inlineTE;
	(*dataH)->doingInline = false;
	if (inlineTE)
	{
		UInt8	stringLength;
		
		stringLength = ((*inlineTE)->teLength <= 31) ? (*inlineTE)->teLength : 31;
		// Check to see if the text changed
		if (IdenticalText(*(*inlineTE)->hText, &((*dataH)->spec.name[1]),
							stringLength, (*dataH)->spec.name[0], nil))
								answer = true;
		BlockMoveData( *((*inlineTE)->hText), &((*dataH)->spec.name[1]), stringLength );
		(*dataH)->spec.name[0] = stringLength;
		TEDispose( inlineTE );
		(*dataH)->inlineTE = nil;
	}
	return answer;
}

//===============================
static void local_DrawTextBox( Rect textRect )
{
	InsetRect( &textRect, -2, -2 );
	FrameRect( &textRect );
}

//===============================
static Boolean local_Idle( BLHandlerParamPtr param, FinderesqueHdl dataH )
{
	TEHandle	inlineTE;
	Boolean		answer = false;
	
	inlineTE = (*dataH)->inlineTE;
	if (inlineTE)
	{
		Rect	textRect;
		
		textRect = local_InlineTextRect( dataH, param->inRect, param->inIndent );
		if (PtInRect(param->inEventWhereLocal,&textRect))
		{
			SetCursor( *GetCursor( iBeamCursor ) );
			answer = true;
		}
		TEIdle( inlineTE );
	}
	return answer;
}

//===============================
static FinderesqueHdl local_AllocateStorage( void )
{
	return (FinderesqueHdl)NewHandleClear( sizeof(FinderesqueData) );
}

//===============================
static void local_Set( BLHandlerParamPtr param, FinderesqueHdl dataH )
{
	switch (param->ioDataFlavor)
	{
		case kFinderesqueFSSpecFlavor:
		if (dataH)
		{
			FInfo	finderInfo;
			OSErr	err;
			Handle	icon;
			
			BlockMoveData( param->ioDataBuffer, (Ptr)(&((*dataH)->spec)), param->ioDataSize );
			// We can assume Icon Services under Carbon.
			// We can remove massive amounts of the find_icon library under Carbon:
			//	all of it as a matter of fact.
			#if !__BL_USE_CARBON_API__
			if (gHasIconServices)
			#endif
			{
				SInt16	label;
				
				err = GetIconRefFromFile( &((*dataH)->spec), (IconRef*)&icon, &label );
			}
			#if !__BL_USE_CARBON_API__
			else err = GetFileIcon( &((*dataH)->spec), kSelectorAllSmallData, &icon );
			#endif
			if (!err) (*dataH)->icon = icon;
			err = FSpGetFInfo( &((*dataH)->spec), &finderInfo );
			if (!err) if (finderInfo.fdFlags & 0x8000) (*dataH)->isAlias = true;
		}
		break;
	}
}

//===============================
static void local_Get( BLHandlerParamPtr param, FinderesqueHdl dataH )
{
	Size	bytes = 0;
	
	switch (param->ioDataFlavor)
	{
		case kFinderesqueFSSpecFlavor:
		if (dataH)
		{
			bytes = sizeof(FSSpec);
			if (param->ioDataBuffer) 
			{
				// Copy no data if caller passes a too-small ptr
				if (param->ioDataSize < bytes) bytes = 0;
				else BlockMoveData( (Ptr)(&((*dataH)->spec)), param->ioDataBuffer, bytes );
			}
		}
		break;
	}
	param->ioDataSize = bytes;
}


//===============================
static SInt32 local_Sort( FinderesqueHdl fh1, BLHandlerParamPtr pp )
{
	SInt32			result = 0;
	FinderesqueHdl	fh2;
	
	fh2 = (FinderesqueHdl)pp->inStorage2;
	if (fh1 && fh2) result = CompareString( (*fh1)->spec.name, (*fh2)->spec.name, nil );
	return result;
}

//===============================
static SInt32 local_Search( BLHandlerParamPtr pp )
{
	FinderesqueHdl	data;
	SInt32			result = 0;
	//TEHandle		te = nil;
	
	data = (FinderesqueHdl)pp->ioStorage;
	if (data && pp->ioDataBuffer)
	{
		Str255		searchString;
		UInt8		stringSize;
		
		stringSize = (pp->ioDataSize <= 255) ? pp->ioDataSize : 255;
		BlockMoveData( pp->ioDataBuffer, &searchString[1], stringSize );
		searchString[0] = stringSize;
		result = RelString( (*data)->spec.name, searchString, false, false );
		//result = CompareText( &((*data)->spec.name[1]), pp->ioDataBuffer, (*data)->spec.name[0],
		//					pp->ioDataSize, nil );
	}
	return result;
}

//===================================
static void local_IconRect( const Rect* inCellRect, UInt16 inIndent, Rect* outIconRect )
{
	SetRect( outIconRect, inCellRect->left + inIndent, inCellRect->top,
			inCellRect->left + inIndent + 16, inCellRect->top + 16 );
	BLAlignRectInRect( blAlignVCenter, false, outIconRect, inCellRect );
}

//===============================
static Rect local_AdjustTERect( FinderesqueHdl dataH, Rect cellRect, UInt16 indent )
{
	Rect		newRect;
	TEHandle	inlineTE;
	
	inlineTE = (*dataH)->inlineTE;
	newRect = local_InlineTextRect( dataH, cellRect, indent );
	(*inlineTE)->viewRect = newRect;
	(*inlineTE)->destRect.right = newRect.right + kDestRectExtraRight;
	return newRect;
}

//===============================
static Rect local_InlineTextRect( FinderesqueHdl dataH, Rect cellRect, UInt16 indent )
{
	Rect		r;
	OSErr		err;
	Point		bounds = {0,0};
	SInt16		baseline;
	TEHandle	te;
	
	r = cellRect;
	r.left += finderesque_OffsetToText(indent);
	r.left--;
	te = (*dataH)->inlineTE;
	if (te)
	{
		Handle		textHdl;
		
		textHdl = (*te)->hText;
		HLock( textHdl );
		err = BLGetTextDimensions( *textHdl, (*te)->teLength, kThemeCurrentPortFont,
									kThemeStateActive, false, &bounds, &baseline );
		HUnlock( textHdl );
	}
	r.bottom = r.top + bounds.v;
	r.right = r.left + bounds.h + 1;
	BLAlignRectInRect( blAlignVCenter, false, &r, &cellRect );
	// Make sure the rectangle has some width, so we can hit-test with a zero-length string
	if (r.right <= r.left + 4) r.right = r.left + 4;
	if (r.right > cellRect.right - 3) r.right = cellRect.right - 3;
	return r;
}

//===============================
static Rect local_NormalTextRect( FinderesqueHdl dataH, const Rect* inCellRect, UInt16 indent )
{
	Rect		r;
	OSErr		err;
	Point		bounds;
	SInt16		baseline;
	Str63		name;
	
	r = *inCellRect;
	r.left += finderesque_OffsetToText(indent);
	// So we don't have to HLock the data handle.
	BlockMoveData( (*dataH)->spec.name, name, (*dataH)->spec.name[0] + 1 );
	err = BLGetTextDimensions( &name[1], name[0], kThemeCurrentPortFont,
								kThemeStateActive, false, &bounds, &baseline );
	r.bottom = r.top + bounds.v;
	r.right = r.left + bounds.h;
	if (r.right > inCellRect->right) r.right = inCellRect->right;
	BLAlignRectInRect( blAlignVCenter, false, &r, inCellRect );
	// Make sure the rectangle has some width, so we can hit-test with a zero-length string
	if (r.right <= r.left + 4) r.right = r.left + 4;
	return r;
}


//===============================
// Should this character be counted against the 31 character maximum?
static Boolean local_IsDisplayChar( UInt8 inChar )
{
	if ((inChar >= kLeftArrowCharCode && inChar <= kDownArrowCharCode) ||
		inChar == kDeleteCharCode || inChar == kBackspaceCharCode) return false;
	return true;
}

//===============================
static Boolean local_IsWithinMaximum( UInt8 inChar, TEHandle inTE )
{
	if (local_IsDisplayChar( inChar ))
	{
		if ((*inTE)->teLength - ((*inTE)->selEnd - (*inTE)->selStart) + 1 > kMaximumLength)
			return false;
	}
	return true;
}

// Include find_icon stuff if not Carbon.
// This #if terminates at the end of the file!
#if !__BL_USE_CARBON_API__
#pragma mark -


#define kRootFolderIconPairCount	6
static const FolderPair gRootFolderIconPair[] =
{
	{ kDesktopFolderType, kDesktopIconResource },
	{ kTrashFolderType, kTrashIconResource },
	// new in Mac OS 8
	{ 'astÄ', -3946 },	// Assistants
	{ 'utiÄ', -3945 },	// Utilities
	// These icons are defined in the Appearance Extension,
	// but for some reason FindFolder doesn't know about them.
	{ 'rdoc', -3966 },	// Documents folder
	{ 'rapp', -3965 }	// Applications folder
};


#define kFolderIconPairCount		22
static const FolderPair gFolderIconPair[] =
{
	{ kDropFolderAliasType, kDropFolderIconResource },
	{ kPrintMonitorDocsFolderType, kPrintMonitorFolderIconResource },
	
	{ kExtensionFolderType, kExtensionsFolderIconResource },
	{ kControlPanelFolderType, kControlPanelFolderIconResource },
	{ kFontsFolderType, kFontsFolderIconResource },
	{ kPreferencesFolderType, kPreferencesFolderIconResource },
	{ kAppleMenuFolderType, kAppleMenuFolderIconResource },
	{ kPrintMonitorDocsFolderType, kPrintMonitorFolderIconResource },
	{ kStartupFolderType, kStartupFolderIconResource },
	{ kShutdownFolderType, kStartupFolderIconResource },
	// ------ new for Mac OS 8's Appearance Extension
	{ 'sdev', -3962 },	// Control Strip Modules
	{ 'Äscr', -3959 },	// Scripting Additions
	{ 'Änet', -3958 },	// Internet Plugins
	{ 'Äprd', -3954 },	// Printer Drivers
	{ 'ppdf', -3953 },	// Printer Descriptions
	{ 'ctrD', -3951 },	// Control Panels (Disabled)
	{ 'extD', -3950 },	// Extensions (Disabled)
	{ 'strD', -3949 },	// Startup Items (Disabled)
	{ 'cmnu', -3942 },	// Contextual Menu Items
	{ 'shdD', -3948 },	// Shutdown Items (Disabled)
	{ 'asup', -3944 },	// Application Support
	{ 'macD', -3947 }	// System Extensions (Disabled)
};

#define kGenericFinderIconsCount		7
static const FilePair gGenericFinderIcons[] =
{
	{ 'ifil', 12500 },	// international scripts
	{ 'ffil', 14500 },	// bitmapped font file
	{ 'sfil', 14000 },	// sound file (beep)
	{ 'tfil', 14501 },	// TrueType font file
	{ 'FFIL', 15500 },	// font suitcase
	{ 'DFIL', 15750 },	// desk accessory suitcase
	{ 'kfil', 14750 }	// keyboard layout file
};


/*	Custom icons numbered -16496 appear in aliases to volumes and
	servers.  I don't know where this is documented.	*/
#define	kVolumeAliasIconResource	-16496

static Str31	gIconFileName = "\p";

/*	------------------------------------------------------------------
	GetFileIcon		Given a file specification for a file, folder, or
					volume, create an appropriate icon suite
					and find its label color.
	------------------------------------------------------------------ */
static OSErr GetFileIcon( FSSpec* thing, IconSelectorValue iconSelector, Handle* theSuite )
{
	CInfoPBRec		cpb;
	OSErr			err;

	*theSuite = nil;
	if (IsVolEjected( thing->vRefNum )) err = volOffLinErr;
	else
	{
		cpb.hFileInfo.ioVRefNum		= thing->vRefNum;
		cpb.hFileInfo.ioDirID		= thing->parID;
		cpb.hFileInfo.ioNamePtr		= thing->name;
		cpb.hFileInfo.ioFDirIndex	= 0;
		err = PBGetCatInfoSync( &cpb );
		if (!err)
		{
			Boolean	customIcon;
			
			customIcon = (cpb.hFileInfo.ioFlFndrInfo.fdFlags & kHasCustomIcon) ? true : false;
			if ((cpb.hFileInfo.ioFlAttrib & ioDirMask) == 0)	// file
			{
				if (customIcon) err = GetCustomFileIcon( thing, iconSelector, theSuite );
				if (!customIcon || err) err = GetNormalFileIcon( &cpb, iconSelector, theSuite );
			}
			else // folder
			{
				// Try to get custom icon
				if (customIcon)
					err = GetCustomFolderIcon( thing->vRefNum, cpb.hFileInfo.ioDirID, iconSelector, theSuite );
				else err = noErr;
				if (!customIcon || err)
				{
					// a volume
					if (cpb.hFileInfo.ioDirID == fsRtDirID) err = GetVolumeIcon( thing->vRefNum, theSuite );
					else err = GetNormalFolderIcon( &cpb, iconSelector, theSuite );
				}
			}
		}	
	}
	return err;
}

//===============================
static Boolean IsSuiteEmpty( Handle theSuite )
{
	Boolean			retVal;
	IconActionUPP	testHandleProc;

	testHandleProc = NewIconActionUPP( TestHandle );
	retVal = true;
	ForEachIconDo(theSuite, svAllAvailableData, testHandleProc, &retVal);
	DisposeIconActionUPP( testHandleProc );
	return retVal;
}

//===============================
static Boolean	IsVolEjected( short vRefNum )
{
	OSErr			err;
	HVolumeParam	vol_pb;
	
	vol_pb.ioNamePtr	= NULL;
	vol_pb.ioVRefNum	= vRefNum;
	vol_pb.ioVolIndex	= 0;
	err = PBHGetVInfoSync( (HParmBlkPtr )&vol_pb );
	return ((err == noErr) && (vol_pb.ioVDRefNum > 0));
}

//===============================
static OSErr GetCustomFileIcon(
/* --> */	FSSpec				*filespec,
/* --> */	IconSelectorValue	iconSelector,
/* <-- */	Handle				*theSuite)
{
	short	saveResFile, customResFile;
	OSErr	err;
	
	saveResFile = CurResFile();
	SetResLoad( false );
	customResFile = FSpOpenResFile(filespec, fsRdPerm);
	SetResLoad( true );
	if (customResFile == -1) err = ResError();
	else
	{
		err = GetResourceIcons( theSuite, kCustomIconResource, iconSelector );
		if (!err)
		{
			if (IsSuiteEmpty( *theSuite ))
			{
				FInfo	finderInfo;
				Boolean	isAlias = false;
			
				err = FSpGetFInfo( filespec, &finderInfo );
				if (!err) if (finderInfo.fdFlags & 0x8000) isAlias = true;
				if (isAlias) err = GetResourceIcons( theSuite, kVolumeAliasIconResource, iconSelector );
				else err = paramErr;
			}
		}
		CloseResFile( customResFile );
		UseResFile( saveResFile );
	}
	return err;
}

//===============================
static OSErr GetNormalFileIcon( CInfoPBRec* cpb, IconSelectorValue iconSelector,
									Handle* theSuite )
{
	OSErr			err;
	SInt32			sysDirID;
	GetIconData		getData;
	Boolean			inFinder;
	SInt16			iconID, saveResFile, FinderResFile, sysVRefNum;
	Str255			finderName;
	IconActionUPP	getIconProcPtr;

	iconID = FindGenericIconID( cpb->hFileInfo.ioFlFndrInfo.fdType, &inFinder );
	saveResFile = CurResFile();
	if (inFinder)
	{
		FindFolder(kOnSystemDisk, kSystemFolderType, kDontCreateFolder, &sysVRefNum, &sysDirID);

		SetResLoad( false );
		GetFinderFilename( finderName );
		FinderResFile = HOpenResFile(sysVRefNum, sysDirID, finderName, fsRdPerm);
		SetResLoad( true );
		if (FinderResFile == -1) err = ResError();
		else
		{
			err = GetResourceIcons(theSuite, iconID, iconSelector);
			CloseResFile( FinderResFile );
		}
	}
	else	// icons in desktop DB or in System
	{
		getData.DTRefNum = FindDesktopDatabase( cpb->dirInfo.ioVRefNum,
												cpb->hFileInfo.ioFlFndrInfo.fdCreator );

		if (getData.DTRefNum != 0)	// the right icons are in some desktop
		{
			err = NewIconSuite( theSuite );
			if (!err)
			{
				getData.fileCreator	= cpb->hFileInfo.ioFlFndrInfo.fdCreator;
				getData.fileType	= cpb->hFileInfo.ioFlFndrInfo.fdType;
				if (getData.fileType == kApplicationAliasType) getData.fileType = 'APPL';
				getIconProcPtr = NewIconActionUPP( GetIconProc );
				err = ForEachIconDo(*theSuite, iconSelector, getIconProcPtr, &getData);
				DisposeIconActionUPP( getIconProcPtr );
			}
		}
		if ((getData.DTRefNum == 0) || IsSuiteEmpty( *theSuite ))
		{
			UseResFile( 0 );
			err = GetResourceIcons(theSuite, iconID, iconSelector);
		}
	}
	UseResFile( saveResFile );
	return err;
}

//===============================
static void GetFinderFilename( StringPtr _finderFilename )
{
	Str255          _defaultFinderFilename="\pFinder";
	StringPtr       _lowMemFinderName;

	_lowMemFinderName = LMGetFinderName();
	if( (_lowMemFinderName != (StringPtr)nil) && (_lowMemFinderName[0] > 0))
		BlockMove(_lowMemFinderName, _finderFilename, _lowMemFinderName[0]+1);
	else BlockMove(_defaultFinderFilename, _finderFilename, _defaultFinderFilename[0]+1);
}

//===============================
/*	Create an icon suite for a folder that is known to have a custom icon.
	The icons in the suite are not resources, and it is your
	responsibility to dispose of the suite when you are done with it.
	
	vRefNum			input:	volume specification
	dirID			input:	directory ID number
	selector		input:	an icon type mask, as defined in <Icons.h>.
	suite			output:	The new icon suite.
*/
static OSErr GetCustomFolderIcon( SInt16 vRefNum, SInt32 dirID, IconSelectorValue selector,
									Handle *suite )
{
	FSSpec	iconFile;
	OSErr	err;
	
	if (gIconFileName[0] == 0) GetIconFileName( gIconFileName );
	err = FSMakeFSSpec( vRefNum, dirID, gIconFileName, &iconFile );
	if (err == noErr) err = GetCustomFileIcon( &iconFile, selector, suite );
	return err;
}



/*	Create an icon suite for a folder, assuming that it does not have
	a custom icon.  This includes finding special icons for the special
	folders found by FindFolder, and shared folders.
	The icons in the suite are not resources, and it is your
	responsibility to dispose of the suite when you are done with it.

	cpb				input:	A parameter block describing the folder, filled in
							by PBGetCatInfo.
	selector		input:	an icon type mask, as defined in <Icons.h>.
	suite			output:	The new icon suite.
*/
static OSErr GetNormalFolderIcon( const CInfoPBRec* cpb, IconSelectorValue selector,
									Handle* suite )
{
	OSErr	err;
	SInt16	iconID, saveResFile, index, vRefNum, foundVRefNum;
	SInt32	sysDirID, dirID, foundDirID;
	
	// Normal folder icons are resources in the System file (or possibly
	// the Appearance Extension, which looks like the System file to us.)
	// Our main problem is determining the resource ID for the right icon.
	dirID = cpb->dirInfo.ioDrDirID;
	vRefNum = cpb->dirInfo.ioVRefNum;
	iconID = kGenericFolderIconResource;	// default
	err = FindFolder( vRefNum, kSystemFolderType, kDontCreateFolder, &foundVRefNum, &sysDirID );
	if (!err && sysDirID == dirID) iconID = kSystemFolderIconResource;
	else if (cpb->dirInfo.ioDrParID == fsRtDirID)
	{
		for (index = 0; index < kRootFolderIconPairCount; ++index)
		{
			err = FindFolder( vRefNum, gRootFolderIconPair[index].folderType,
								kDontCreateFolder, &foundVRefNum, &foundDirID );
			if (!err && foundDirID == dirID)
			{
				iconID = gRootFolderIconPair[index].iconID;
				break;
			}
		}
	}
	else if ( sysDirID == cpb->dirInfo.ioDrParID )
	{
		/* The folder is a subfolder of the System Folder, so it
			might be one with a special icon. */
		for (index = 0; index < kFolderIconPairCount; ++index)
		{
			err = FindFolder( vRefNum, gFolderIconPair[index].folderType,
								kDontCreateFolder, &foundVRefNum, &foundDirID );
			if (!err && foundDirID == dirID)
			{
				iconID = gFolderIconPair[index].iconID;
				break;
			}
		}
	}
	else
	{
		/* These attribute bits are described in TN 301. */
		if ((cpb->dirInfo.ioFlAttrib & 0x08) != 0) iconID = kMountedFolderIconResource;
		else if ((cpb->dirInfo.ioFlAttrib & 0x20) != 0) iconID = kSharedFolderIconResource;
		else if ((cpb->dirInfo.ioFlAttrib & 0x04) != 0) iconID = kOwnedFolderIconResource;
	}
	saveResFile = CurResFile();
	UseResFile(0);	// look in the System file
	// The reason I use kFI_resChain here is because the icons may be in Aaron.
	//err = FIGetIconSuite( suite, iconID, selector, kFI_resChain );
	err = Get1IconSuite( suite, iconID, selector );
	if ((err != noErr) && (iconID != kGenericFolderIconResource))
	{
		iconID = kGenericFolderIconResource;
		//err = FIGetIconSuite( suite, iconID, selector, kFI_resChain );
		err = Get1IconSuite( suite, iconID, selector );
	}
	UseResFile( saveResFile );
	return err;
}

//===============================
/*	Find an icon suite to represent a volume, assuming that the volume
	does not have a custom icon.  Normally, this will be the 'ICN#' icon
	obtained from the disk driver.  If there was some error getting that,
	we use the kFloppyIconResource system resource icon suite.  In either
	case, the icons in the suite are not resources, and it is your
	responsibility to dispose of the suite when you are done with it.
	
	vRefNum		input:	volume specification
	suite		output:	a newly created icon suite
*/
static OSErr GetVolumeIcon( SInt16 vRefNum, Handle* suite )
{
	OSErr			err;
	HParamBlockRec	pb;
	ParamBlockRec	cpb;
	Handle			iconHandle;
	short			save_resfile;
	Ptr				*driveIcon;
	Str255			theDriverName;
	
	*suite = nil;
	// Find the volume's drive number and driver reference number
	pb.volumeParam.ioNamePtr = nil;
	pb.volumeParam.ioVRefNum = vRefNum;
	pb.volumeParam.ioVolIndex = 0;
	err = PBHGetVInfoSync(&pb);
	if (!err)
	{
		// See if the driver is ".Sony", the floppy driver
		FIGetDriverName( pb.volumeParam.ioVDRefNum, theDriverName );
		if (EqualString( theDriverName, "\p.Sony", true, false ))
		{
			save_resfile = CurResFile();
			UseResFile(0);	// we want a System resource
			//err = FIGetIconSuite( suite, kFloppyIconResource, kSelectorAllAvailableData, kFI_use1File );
			err = Get1IconSuite( suite, kFloppyIconResource, kSelectorAllAvailableData );
			UseResFile( save_resfile );
		}
		else
		{
			// set up for Control call
			cpb.cntrlParam.ioCRefNum = pb.volumeParam.ioVDRefNum;
			cpb.cntrlParam.ioVRefNum = pb.volumeParam.ioVDrvInfo;
			driveIcon = (Ptr *) &cpb.cntrlParam.csParam;
			*driveIcon = nil;
			
			// Warning: Under A/UX 3.0, the csCode = 22 call can fail
			// without returning an error code.
			// try media icon
			cpb.cntrlParam.csCode = 22;
			err = PBControlSync( &cpb );

			if ((err != noErr) || ((long)*driveIcon <= 0))
			{
				// try physical drive icon;
				cpb.cntrlParam.csCode = 21;
				err = PBControlSync( &cpb );
			}
			
			if ((err == noErr) && (0 < (long)*driveIcon))	// we got an icon
			{
				err = NewIconSuite( suite );	// create the new suite	
				if (!err) err = PtrToHand( *driveIcon, &iconHandle, kLargeIconSize );
				if (!err) err = AddIconToSuite(iconHandle, *suite, large1BitMask);
			}
		}
	}
	return err;
}


/*	------------------------------------------------------------------
	GetIcon		This is an IconAction procedure to fill in one
					slot of an icon suite, given a file type, creator,
					and desktop database.
	------------------------------------------------------------------ */
static pascal OSErr GetIconProc(ResType theType, Handle *theIcon, void *yourDataPtr)
{
	OSErr			err;
	GetIconData		*data;
	DTPBRec			deskRec;

	err = noErr;
	data = (GetIconData *)yourDataPtr;
	*theIcon = NewHandle( kLarge8BitIconSize );
	if (!*theIcon) err = memFullErr;
	else
	{
		HLock( *theIcon );
	
		deskRec.ioDTRefNum		= data->DTRefNum;
		deskRec.ioDTBuffer		= **theIcon;
		deskRec.ioDTReqCount	= kLarge8BitIconSize;
		deskRec.ioFileCreator	= data->fileCreator;
		deskRec.ioFileType		= data->fileType;
	
		switch( theType )
		{
			case large1BitMask:
				deskRec.ioIconType = kLargeIcon;
				break;
	
			case large4BitData:
				deskRec.ioIconType = kLarge4BitIcon;
				break;
	
			case large8BitData:
				deskRec.ioIconType = kLarge8BitIcon;
				break;
	
			case small1BitMask:
				deskRec.ioIconType = kSmallIcon;
				break;
	
			case small4BitData:
				deskRec.ioIconType = kSmall4BitIcon;
				break;
	
			case small8BitData:
				deskRec.ioIconType = kSmall8BitIcon;
				break;
			
			default:
				// The desktop database does not have "mini" icons
				deskRec.ioIconType = 1000;
				break;
		}

		err = PBDTGetIconSync( &deskRec );
		if (err == noErr)
		{
			HUnlock( *theIcon );
			SetHandleSize(*theIcon, deskRec.ioDTActCount);
		}
		else
		{
			DisposeHandle( *theIcon );
			*theIcon = NULL;
			err = noErr;
		}
	}
	return err;
}


/*	------------------------------------------------------------------
	Find_desktop_database			Find the reference number of a
									desktop database containing icons
									for a specified creator code.
	The search begins on a specified volume, but covers all volumes.
	------------------------------------------------------------------ */
static	short	FindDesktopDatabase(
/* --> */	short	firstVRefNum,
/* --> */	OSType	fileCreator)	// returns a DT refnum or 0
{
	//OSErr			err;
	VolumeParam		vpb;
	short			DTRefNum = 0;

	if( !InOneDesktop(firstVRefNum, fileCreator, &DTRefNum) )
	{
		vpb.ioNamePtr = NULL;
		for(vpb.ioVolIndex = 1; PBGetVInfoSync((ParmBlkPtr )&vpb) == noErr; ++vpb.ioVolIndex)
		{
			if (vpb.ioVRefNum == firstVRefNum) continue;
			if (InOneDesktop(vpb.ioVRefNum, fileCreator, &DTRefNum)) break;
		}
	}
	return DTRefNum;
}



/*	------------------------------------------------------------------
	InOneDesktop			Determine whether the desktop database for
							one particular volume contains icons for
							a given creator code, and if so, return its
							reference number.
	------------------------------------------------------------------*/
static	Boolean	InOneDesktop(
/* --> */	short	vRefNum,
/* --> */	OSType	fileCreator,
/* <-- */	short	*dtRefNum)
{
	OSErr		err;
	DTPBRec		deskRec;
	Boolean		retVal;
	
	HParamBlockRec         _myHPB;
	GetVolParmsInfoBuffer  _infoBuffer;
	
	retVal = false;	// default to failure
	deskRec.ioNamePtr = NULL;
	deskRec.ioVRefNum = vRefNum;
	
	// check to make sure we've got a database first:
	_myHPB.ioParam.ioNamePtr  = (StringPtr)nil;
	_myHPB.ioParam.ioVRefNum  = vRefNum;
	_myHPB.ioParam.ioBuffer   = (Ptr)&_infoBuffer;
	_myHPB.ioParam.ioReqCount = sizeof(_infoBuffer);
	if ( ((err=PBHGetVolParms(&_myHPB,false/*async*/))!=noErr) ||
	((_infoBuffer.vMAttrib&(1L<<bHasDesktopMgr))==0) )
		return retVal;

	err = PBDTGetPath( &deskRec );
	if( !err )
	{
		/*	We want to ignore any non-icon data, such as the 'paul'
			item that is used for drag-and-drop. */
		deskRec.ioFileCreator = fileCreator;
		deskRec.ioIndex = 1;
		do
		{
			deskRec.ioTagInfo = 0;
			err = PBDTGetIconInfoSync( &deskRec );
			deskRec.ioIndex += 1;
		} while( (err == noErr) && (deskRec.ioIconType <= 0) );
	
		if(err == noErr)
		{
			retVal = true;
			*dtRefNum = deskRec.ioDTRefNum;
		}
	}
	return retVal;
}


static pascal OSErr GetResourceIcons(
/* <-- */	Handle	*theSuite,
/* --> */	short	theID,
/* --> */	long	theSelector)
{
	OSErr	err;
	
	err = Get1IconSuite(theSuite, theID, theSelector);
	if (err == noErr) err = CopyEachIcon( *theSuite );
	return err;
}

//===============================
static pascal OSErr CopyOneIcon(
/* --> */	ResType		theType,
/* <-> */	Handle		*theIcon,
/* --- */	void		*yourDataPtr)
{
	#pragma unused (theType,yourDataPtr)
	OSErr	err;
	
	if (*theIcon != nil)
	{
		LoadResource( *theIcon );
		err = HandToHand( theIcon );
		if (err != noErr) *theIcon = nil;
	}
	return noErr;
}

//===============================
static OSErr CopyEachIcon( Handle theSuite )
{
	IconActionUPP	copyOneIconProc;
	OSErr			err;
	
	copyOneIconProc = NewIconActionProc( CopyOneIcon );
	err = ForEachIconDo( theSuite, svAllAvailableData, copyOneIconProc, nil );
	DisposeRoutineDescriptor( copyOneIconProc );
	return err;
}


//typedef struct genericIconInfo { OSType type; short id; } GenericIconInfo;
#define kGenericSysIconsCount	17
static FilePair gGenericSysIcons[] =
{
	{kContainerFolderAliasType,genericFolderIconResource},
	{kContainerTrashAliasType,trashIconResource},
	{kSystemFolderAliasType,systemFolderIconResource},
	{'INIT',genericExtensionIconResource},
	{'APPL',genericApplicationIconResource},
	{'dfil',genericDeskAccessoryIconResource},
	{'pref',genericPreferencesIconResource},
	{kAppleMenuFolderAliasType,appleMenuFolderIconResource},
	{kControlPanelFolderAliasType,controlPanelFolderIconResource},
	{kExtensionFolderAliasType,extensionsFolderIconResource},
	{kPreferencesFolderAliasType,preferencesFolderIconResource},
	{kStartupFolderAliasType,startupFolderIconResource},
	{kApplicationAliasType,genericApplicationIconResource},
	{kExportedFolderAliasType,ownedFolderIconResource},
	{kDropFolderAliasType,dropFolderIconResource},
	{kSharedFolderAliasType,sharedFolderIconResource},
	{kMountedFolderAliasType,mountedFolderIconResource}
};


static short FindGenericIconID( OSType theType, Boolean	*inFinder )
{
	short			id = genericDocumentIconResource; // default
	const FilePair	*icon, *endIcon;
   
	icon = gGenericFinderIcons;
	endIcon = icon + kGenericFinderIconsCount;
	for (;icon < endIcon && icon->fileType != theType; icon++) ;
	*inFinder = (icon < endIcon);
	if (!(*inFinder))
	{
		icon = gGenericSysIcons;
		endIcon = icon + kGenericSysIconsCount;
		for (; icon < endIcon && icon->fileType != theType; icon++) ;
	}
	if (icon < endIcon) id = icon->iconID;
	return id;
}


/*	--------------------------------------------------------------------
	Get1IconSuite			Like GetIconSuite, but only looks in
							the current resource file.
	
	In case you're wondering why it would be necessary to ensure that
	icons come from only one file, suppose you're looking at a
	file that has its custom icon bit set, but for some reason does
	not contain a custom icon, or at least not a full family.
	Way down the resource chain, there may be another file, say a
	font file, that does have a full family of custom icons. 
	So you get an unexpected icon.
	-------------------------------------------------------------------- */
static pascal OSErr Get1IconSuite( Handle* theSuite, short theID, IconSelectorValue theSelector )
{
	OSErr			err;
	IconActionUPP	get1IconProc;

	err = NewIconSuite( theSuite );
	if( !err )
	{
		get1IconProc = NewIconActionUPP( Get1Icon );
		err = ForEachIconDo(*theSuite, theSelector, get1IconProc, &theID);
		DisposeIconActionUPP( get1IconProc );
	}
	return( err );
}

//===============================
static pascal OSErr Get1Icon(
/* --> */	ResType	theType,
/* <-> */	Handle	*theIcon,
/* --> */	short	*resID)
{
	*theIcon = Get1Resource(theType, *resID);
	return noErr;
}

//===============================
static pascal OSErr TestHandle(ResType theType, Handle *theIcon, void *yourDataPtr)
{
	#pragma unused (theType)
	if (*theIcon != NULL) *(Boolean *)yourDataPtr = false;	// not empty!
	return noErr;
}

//===============================
/*	Get the name of the invisible file used to store custom icons
	for folders.  This is usually "\pIcon\r", but unfortunately on
	some localized systems it is something else.
	
	iconFileName	output:	The name of the custom icon files on
							this computer. You must have allocated
							a Str31 variable to hold it.
*/
static void GetIconFileName( Str31 iconFileName )
{
	SInt16	saveResFile, sysVRefNum, finderResFile;
	SInt32	sysDirID;
	Str255	tempName;
	OSErr	err;
	
	tempName[0] = 0;
	saveResFile = CurResFile();
	err = FindFolder( kOnSystemDisk, kSystemFolderType, kDontCreateFolder, &sysVRefNum,
						&sysDirID );
	SetResLoad( false );
	finderResFile = HOpenResFile( sysVRefNum, sysDirID, LMGetFinderName(), fsRdPerm );
	SetResLoad( true );
	if (finderResFile != -1)	// successful open
	{
		GetIndString( tempName, 11250, 5 );
		if (tempName[0] == 0) GetIndString( tempName, 4500, 5 ); // for Mac OS 8
		CloseResFile( finderResFile );
		UseResFile( saveResFile );
	}
	if ((tempName[0] < 32) && (tempName[0] > 0))
		BlockMoveData( tempName, iconFileName, tempName[0] + 1 );
	else BlockMoveData( "\pIcon\r", iconFileName, 6 );
}


//===============================
/*	Find the name of a driver from its driver reference number.
	I use this to identify floppy disks, on the assumption that
	their drivers will always be named "\p.Sony".
	
	inDriverRefnum		input:		driver reference number
	outName				output:		The name of the driver.  I'm not sure how long
									a driver name can be, so allocate a Str255
									to be safe.
*/
static void FIGetDriverName( SInt16 inDriverRefnum, StringPtr outName )
{
	DCtlHandle		DCtlH;
	DriverHeader*	driver;
	
	DCtlH = GetDCtlEntry( inDriverRefnum );
	if ((DCtlH != nil) && ((*DCtlH)->dCtlDriver != nil) )
	{
		if (((*DCtlH)->dCtlFlags >> dRAMBased) & 1) driver = *(DriverHeader**)(*DCtlH)->dCtlDriver;
		else driver = (DriverHeader*)(*DCtlH)->dCtlDriver;
		BlockMoveData( driver->name, outName, driver->name[0]+1 );
	}
	else outName[0] = 0;
}

#endif // !__BL_USE_CARBON_API__