Mac-Carbon

 view release on metacpan or  search on metacpan

MoreFiles/MoreFilesSrc/MoreDesktopMgr.c  view on Meta::CPAN

/* local data structures */

#if PRAGMA_STRUCT_ALIGN
#pragma options align=mac68k
#endif

struct IDRec
{
	short		localID;
	short		rsrcID;
};
typedef struct IDRec IDRec;
typedef	IDRec *IDRecPtr;

struct BundleType
{
	OSType		type;			/* 'ICN#' or 'FREF' */
	short		count;			/* number of IDRecs - 1 */
	IDRec		idArray[1];
};
typedef struct BundleType BundleType;
typedef BundleType *BundleTypePtr;

struct BNDLRec
{
	OSType		signature;		/* creator type signature */
	short		versionID;		/* version - should always be 0 */
	short		numTypes;		/* number of elements in typeArray - 1 */
	BundleType	typeArray[1];
};
typedef struct BNDLRec BNDLRec;
typedef BNDLRec **BNDLRecHandle;

struct FREFRec
{
	OSType		fileType;		/* file type */
	short		iconID;			/* icon local ID */
	Str255		fileName;		/* file name */
};
typedef struct FREFRec FREFRec;
typedef FREFRec **FREFRecHandle;

struct APPLRec
{
	OSType		creator;		/* creator type signature */
	long		parID;			/* parent directory ID */
	Str255		applName;		/* application name */
};
typedef struct APPLRec APPLRec;
typedef APPLRec *APPLRecPtr;

#if PRAGMA_STRUCT_ALIGN
#pragma options align=reset
#endif

/*****************************************************************************/

/* static prototypes */

static	OSErr	GetDesktopFileName(short vRefNum,
								   Str255 desktopName);

static	OSErr	GetAPPLFromDesktopFile(ConstStr255Param volName,
									   short vRefNum,
									   OSType creator,
									   short *applVRefNum,
									   long *applParID,
									   Str255 applName);

static	OSErr	FindBundleGivenCreator(OSType creator,
									   BNDLRecHandle *returnBndl);
									   
static	OSErr	FindTypeInBundle(OSType typeToFind,
								 BNDLRecHandle theBndl,
								 BundleTypePtr *returnBundleType);
										 
static	OSErr	GetLocalIDFromFREF(BundleTypePtr theBundleType,
								   OSType fileType,
								   short *iconLocalID);

static	OSErr	GetIconRsrcIDFromLocalID(BundleTypePtr theBundleType,
										 short iconLocalID,
										 short *iconRsrcID);

static	OSType	DTIconToResIcon(short iconType);

static	OSErr	GetIconFromDesktopFile(ConstStr255Param volName,
									   short vRefNum,
									   short iconType,
									   OSType fileCreator,
									   OSType fileType,
									   Handle *iconHandle);

static	OSErr	GetCommentID(short vRefNum,
							 long dirID,
							 ConstStr255Param name,
							 short *commentID);

static	OSErr	GetCommentFromDesktopFile(short vRefNum,
										  long dirID,
										  ConstStr255Param name,
										  Str255 comment);

/*****************************************************************************/

/*
**	GetDesktopFileName
**
**	Get the name of the Desktop file.
*/
static	OSErr	GetDesktopFileName(short vRefNum,
								   Str255 desktopName)
{
	OSErr			error;
	HParamBlockRec	pb;
	short			index;
	Boolean			found;
	
	pb.fileParam.ioNamePtr = desktopName;
	pb.fileParam.ioVRefNum = vRefNum;
	pb.fileParam.ioFVersNum = 0;
	index = 1;
	found = false;
	do
	{
		pb.fileParam.ioDirID = fsRtDirID;
		pb.fileParam.ioFDirIndex = index;
		error = PBHGetFInfoSync(&pb);
		if ( error == noErr )
		{
			if ( (pb.fileParam.ioFlFndrInfo.fdType == 'FNDR') &&
				 (pb.fileParam.ioFlFndrInfo.fdCreator == 'ERIK') )
			{
				found = true;
			}
		}
		++index;
	} while ( (error == noErr) && !found );
	
	return ( error );
}

/*****************************************************************************/

pascal	OSErr	DTOpen(ConstStr255Param volName,
					   short vRefNum,
					   short *dtRefNum,
					   Boolean *newDTDatabase)
{
	OSErr error;
	GetVolParmsInfoBuffer volParmsInfo;
	long infoSize;
	DTPBRec pb;
	
	/* Check for volume Desktop Manager support before calling */
	infoSize = sizeof(GetVolParmsInfoBuffer);
	error = HGetVolParms(volName, vRefNum, &volParmsInfo, &infoSize);
	if ( error == noErr )
	{
		if ( hasDesktopMgr(volParmsInfo) )
		{
			pb.ioNamePtr = (StringPtr)volName;
			pb.ioVRefNum = vRefNum;
			error = PBDTOpenInform(&pb);
			/* PBDTOpenInform informs us if the desktop was just created */
			/* by leaving the low bit of ioTagInfo clear (0) */
			*newDTDatabase = ((pb.ioTagInfo & 1L) == 0);
			if ( error == paramErr )
			{
				error = PBDTGetPath(&pb);
				/* PBDTGetPath doesn't tell us if the database is new */
				/* so assume it is not new */
				*newDTDatabase = false;
			}
			*dtRefNum = pb.ioDTRefNum;
		}
		else
		{
			error = paramErr;
		}
	}
	return ( error );
}

/*****************************************************************************/

/*
**	GetAPPLFromDesktopFile
**
**	Get a application's location from the
**	Desktop file's 'APPL' resources.
*/
static	OSErr	GetAPPLFromDesktopFile(ConstStr255Param volName,
									   short vRefNum,
									   OSType creator,
									   short *applVRefNum,
									   long *applParID,
									   Str255 applName)
{
	OSErr error;
	short realVRefNum;
	Str255 desktopName;
	short savedResFile;
	short dfRefNum;
	Handle applResHandle;
	Boolean foundCreator;
	Ptr applPtr;
	long applSize;
	
	error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
	if ( error == noErr )
	{
		error = GetDesktopFileName(realVRefNum, desktopName);
		if ( error == noErr )
		{
			savedResFile = CurResFile();
			/*
			**	Open the 'Desktop' file in the root directory. (because
			**	opening the resource file could preload unwanted resources,
			**	bracket the call with SetResLoad(s))
			*/
			SetResLoad(false);
			dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
			SetResLoad(true);
			
			if ( dfRefNum != -1)
			{
				/* Get 'APPL' resource ID 0 */
				applResHandle = Get1Resource(kAPPLResType, 0);
				if ( applResHandle != NULL )
				{
					applSize = GetHandleSize((Handle)applResHandle);
					if ( applSize != 0 )	/* make sure the APPL resource isn't empty */
					{
						foundCreator = false;
						applPtr = *applResHandle;
						
						/* APPL's don't have a count so I have to use the size as the bounds */
						while ( (foundCreator == false) &&
								(applPtr < (*applResHandle + applSize)) )
						{
							if ( ((APPLRecPtr)applPtr)->creator == creator )
							{
								foundCreator = true;
							}
							else
							{
								/* fun with pointer math... */
								applPtr += sizeof(OSType) +
										   sizeof(long) +
										   ((APPLRecPtr)applPtr)->applName[0] + 1;
								/* application mappings are word aligned within the resource */
								if ( ((unsigned long)applPtr % 2) != 0 )
								{
									applPtr += 1;
								}
							}
						}
						if ( foundCreator == true )
						{
							*applVRefNum = realVRefNum;
							*applParID = ((APPLRecPtr)applPtr)->parID;
							BlockMoveData(((APPLRecPtr)applPtr)->applName,
										  applName,
										  ((APPLRecPtr)applPtr)->applName[0] + 1);
							/* error is already noErr */
						}
						else
						{
							error = afpItemNotFound;	/* didn't find a creator match */
						}
					}
					else
					{
						error = afpItemNotFound;	/* no APPL mapping available */
					}
				}
				else
				{
					error = afpItemNotFound;	/* no APPL mapping available */
				}
				
				/* restore the resource chain and close the Desktop file */

MoreFiles/MoreFilesSrc/MoreDesktopMgr.c  view on Meta::CPAN

		index ++;
	}
	
	return ( error );
}

/*****************************************************************************/

/*
**	DTIconToResIcon
**
**	Map a Desktop Manager icon type to the corresponding resource type.
**	Return (OSType)0 if there is no corresponding resource type.
*/
static	OSType	DTIconToResIcon(short iconType)
{
	OSType	resType;
	
	switch ( iconType )
	{
		case kLargeIcon:
			resType = large1BitMask;
			break;
		case kLarge4BitIcon:
			resType = large4BitData;
			break;
		case kLarge8BitIcon:
			resType = large8BitData;
			break;
		case kSmallIcon:
			resType = small1BitMask;
			break;
		case kSmall4BitIcon:
			resType = small4BitData;
			break;
		case kSmall8BitIcon:
			resType = small8BitData;
			break;
		default:
			resType = (OSType)0;
			break;
	}
	
	return ( resType );
}

/*****************************************************************************/

/*
**	GetIconFromDesktopFile
**
**	INPUT a pointer to a non-existent Handle, because we'll allocate one
**
**	search each BNDL resource for the right fileCreator and once we get it
**		find the 'FREF' type in BNDL
**		for each localID in the type, open the FREF resource
**			if the FREF is the desired fileType
**				get its icon localID
**				get the ICN# type in BNDL
**				get the icon resource number from the icon localID
**				get the icon resource type from the desktop mgr's iconType
**				get the icon of that type and number
*/
static	OSErr	GetIconFromDesktopFile(ConstStr255Param volName,
									   short vRefNum,
									   short iconType,
									   OSType fileCreator,
									   OSType fileType,
									   Handle *iconHandle)
{
	OSErr			error;
	short			realVRefNum;
	Str255			desktopName;
	short			savedResFile;
	short			dfRefNum;
	BNDLRecHandle	theBndl = NULL;
	BundleTypePtr	theBundleType;
	short			iconLocalID;
	short			iconRsrcID;
	OSType			iconRsrcType;
	Handle			returnIconHandle;	
	char			bndlState;
	
	*iconHandle = NULL;
	
	error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
	if ( error == noErr )
	{
		error = GetDesktopFileName(realVRefNum, desktopName);
		if ( error == noErr )
		{
			savedResFile = CurResFile();
		
			/*
			**	Open the 'Desktop' file in the root directory. (because
			**	opening the resource file could preload unwanted resources,
			**	bracket the call with SetResLoad(s))
			*/
			SetResLoad(false);
			dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
			SetResLoad(true);
		
			if ( dfRefNum != -1 )
			{
				/*
				**	Find the BNDL resource with the specified creator.
				*/
				error = FindBundleGivenCreator(fileCreator, &theBndl);
				if ( error == noErr )
				{
					/* Lock the BNDL resource so it won't be purged when other resources are loaded */
					bndlState = HGetState((Handle)theBndl);
					HLock((Handle)theBndl);
					
					/* Find the 'FREF' BundleType record in the BNDL resource. */
					error = FindTypeInBundle(kFREFResType, theBndl, &theBundleType);
					if ( error == noErr )
					{
						/* Find the local ID in the 'FREF' resource with the specified fileType */
						error = GetLocalIDFromFREF(theBundleType, fileType, &iconLocalID);
						if ( error == noErr )
						{
							/* Find the 'ICN#' BundleType record in the BNDL resource. */
							error = FindTypeInBundle(kIconFamResType, theBndl, &theBundleType);
							if ( error == noErr )
							{
								/* Find the icon's resource ID in the 'ICN#' BundleType record */
								error = GetIconRsrcIDFromLocalID(theBundleType, iconLocalID, &iconRsrcID);
								if ( error == noErr )
								{
									/* Map Desktop Manager icon type to resource type */
									iconRsrcType = DTIconToResIcon(iconType);
									
									if ( iconRsrcType != (OSType)0 )
									{
										/* Load the icon */
										returnIconHandle = Get1Resource(iconRsrcType, iconRsrcID);
										if ( returnIconHandle != NULL )
										{
											/* Copy the resource handle, and return the copy */
											HandToHand(&returnIconHandle);
											if ( MemError() == noErr )
											{
												*iconHandle = returnIconHandle;
											}
											else
											{
												error = afpItemNotFound;
											}
										}
										else
										{
											error = afpItemNotFound;
										}
									}
								}
							}
						}
					}
					/* Restore the state of the BNDL resource */ 
					HSetState((Handle)theBndl, bndlState);
				}
				/* Restore the resource chain and close the Desktop file */
				UseResFile(savedResFile);
				CloseResFile(dfRefNum);
			}
			else
			{
				error = ResError(); /* could not open Desktop file */
			}
		}
		if ( (error != noErr) && (error != memFullErr) )
		{
			error = afpItemNotFound;	/* force an error we should return */
		}
	}
	
	return ( error );
}

/*****************************************************************************/

pascal	OSErr	DTGetIcon(ConstStr255Param volName,
						  short vRefNum,
						  short iconType,
						  OSType fileCreator,
						  OSType fileType,
						  Handle *iconHandle)
{
	OSErr error;
	DTPBRec pb;
	short dtRefNum;
	Boolean newDTDatabase;
	Size bufferSize;
	
	*iconHandle = NULL;
	error = DTOpen(volName, vRefNum, &dtRefNum, &newDTDatabase);
	if ( error == noErr )
	{
		/* there was a desktop database and it's now open */
		
		if ( !newDTDatabase )	/* don't bother to look in a new (empty) database */
		{
			/* get the buffer size for the requested icon type */
			switch ( iconType )
			{
				case kLargeIcon:
					bufferSize = kLargeIconSize;
					break;
				case kLarge4BitIcon:
					bufferSize = kLarge4BitIconSize;
					break;
				case kLarge8BitIcon:
					bufferSize = kLarge8BitIconSize;
					break;
				case kSmallIcon:
					bufferSize = kSmallIconSize;
					break;
				case kSmall4BitIcon:
					bufferSize = kSmall4BitIconSize;
					break;
				case kSmall8BitIcon:
					bufferSize = kSmall8BitIconSize;
					break;
				default:
					iconType = 0;
					bufferSize = 0;
					break;
			}
			if ( bufferSize != 0 )
			{
				*iconHandle = NewHandle(bufferSize);
				if ( *iconHandle != NULL )
				{
					HLock(*iconHandle);
		
					pb.ioDTRefNum = dtRefNum;
					pb.ioTagInfo = 0;
					pb.ioDTBuffer = **iconHandle;
					pb.ioDTReqCount = bufferSize;
					pb.ioIconType = iconType;
					pb.ioFileCreator = fileCreator;
					pb.ioFileType = fileType;
					error = PBDTGetIconSync(&pb);
	
					HUnlock(*iconHandle);
					
					if ( error != noErr )
					{
						DisposeHandle(*iconHandle);	/* dispose of the allocated memory */
						*iconHandle = NULL;
					}
				}
				else
				{
					error = memFullErr;	/* handle could not be allocated */
				}
			}
			else
			{
				error = paramErr;	/* unknown icon type requested */
			}
		}
		else
		{
			error = afpItemNotFound;	/* the desktop database was empty - nothing to return */
		}
	}
	else
	{
		/* There is no desktop database - try the Desktop file */
		
		error = GetIconFromDesktopFile(volName, vRefNum, iconType,
										fileCreator, fileType, iconHandle);
	}
	
	return ( error );
}

/*****************************************************************************/

pascal	OSErr	DTSetComment(short vRefNum,
							 long dirID,
							 ConstStr255Param name,
							 ConstStr255Param comment)
{
	DTPBRec pb;
	OSErr error;
	short dtRefNum;
	Boolean newDTDatabase;

	error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
	if ( error == noErr )
	{
		pb.ioDTRefNum = dtRefNum;
		pb.ioNamePtr = (StringPtr)name;
		pb.ioDirID = dirID;
		pb.ioDTBuffer = (Ptr)&comment[1];
		/* Truncate the comment to 200 characters just in case */
		/* some file system doesn't range check */
		if ( comment[0] <= 200 )
		{
			pb.ioDTReqCount = comment[0];
		}
		else
		{
			pb.ioDTReqCount = 200;
		}
		error = PBDTSetCommentSync(&pb);
	}
	return (error);
}

/*****************************************************************************/

pascal	OSErr	FSpDTSetComment(const FSSpec *spec,
							  ConstStr255Param comment)
{
	return (DTSetComment(spec->vRefNum, spec->parID, spec->name, comment));
}

/*****************************************************************************/

/*
**	GetCommentID
**
**	Get the comment ID number for the Desktop file's 'FCMT' resource ID from
**	the file or folders fdComment (frComment) field.
*/
static	OSErr	GetCommentID(short vRefNum,
							 long dirID,
							 ConstStr255Param name,
							 short *commentID)
{
	CInfoPBRec pb;
	OSErr error;

	error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
	*commentID = pb.hFileInfo.ioFlXFndrInfo.fdComment;
	return ( error );
}

/*****************************************************************************/

/*
**	GetCommentFromDesktopFile
**
**	Get a file or directory's Finder comment field (if any) from the
**	Desktop file's 'FCMT' resources.
*/
static	OSErr	GetCommentFromDesktopFile(short vRefNum,
										  long dirID,
										  ConstStr255Param name,
										  Str255 comment)
{
	OSErr error;
	short commentID;
	short realVRefNum;
	Str255 desktopName;
	short savedResFile;
	short dfRefNum;
	StringHandle commentHandle;
	
	/* Get the comment ID number */
	error = GetCommentID(vRefNum, dirID, name, &commentID);
	if ( error == noErr )
	{
		if ( commentID != 0 )	/* commentID == 0 means there's no comment */
		{
			error = DetermineVRefNum(name, vRefNum, &realVRefNum);
			if ( error == noErr )
			{
				error = GetDesktopFileName(realVRefNum, desktopName);
				if ( error == noErr )
				{
					savedResFile = CurResFile();
					/*
					**	Open the 'Desktop' file in the root directory. (because
					**	opening the resource file could preload unwanted resources,
					**	bracket the call with SetResLoad(s))
					*/
					SetResLoad(false);
					dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
					SetResLoad(true);
					
					if ( dfRefNum != -1)
					{
						/* Get the comment resource */
						commentHandle = (StringHandle)Get1Resource(kFCMTResType,commentID);
						if ( commentHandle != NULL )
						{
							if ( GetHandleSize((Handle)commentHandle) > 0 )
							{
								BlockMoveData(*commentHandle, comment, *commentHandle[0] + 1);
							}
							else
							{
								error = afpItemNotFound;	/* no comment available */
							}
						}
						else
						{
							error = afpItemNotFound;	/* no comment available */
						}
						
						/* restore the resource chain and close the Desktop file */
						UseResFile(savedResFile);
						CloseResFile(dfRefNum);
					}
					else
					{
						error = afpItemNotFound;
					}
				}
				else
				{
					error = afpItemNotFound;
				}
			}
		}
		else
		{
			error = afpItemNotFound;	/* no comment available */
		}
	}
	
	return ( error );
}

/*****************************************************************************/

pascal	OSErr	DTGetComment(short vRefNum,
							 long dirID,
							 ConstStr255Param name,
							 Str255 comment)
{
	DTPBRec pb;
	OSErr error;
	short dtRefNum;
	Boolean newDTDatabase;

	if (comment != NULL)
	{
		comment[0] = 0;	/* return nothing by default */
		
		/* attempt to open the desktop database */
		error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
		if ( error == noErr )
		{
			/* There was a desktop database and it's now open */
			
			if ( !newDTDatabase )
			{
				pb.ioDTRefNum = dtRefNum;
				pb.ioNamePtr = (StringPtr)name;
				pb.ioDirID = dirID;
				pb.ioDTBuffer = (Ptr)&comment[1];
				/*
				**	IMPORTANT NOTE #1: Inside Macintosh says that comments
				**	are up to 200 characters. While that may be correct for
				**	the HFS file system's Desktop Manager, other file
				**	systems (such as Apple Photo Access) return up to
				**	255 characters. Make sure the comment buffer is a Str255
				**	or you'll regret it.
				**
				**	IMPORTANT NOTE #2: Although Inside Macintosh doesn't
				**	mention it, ioDTReqCount is a input field to
				**	PBDTGetCommentSync. Some file systems (like HFS) ignore
				**	ioDTReqCount and always return the full comment --
				**	others (like AppleShare) respect ioDTReqCount and only
				**	return up to ioDTReqCount characters of the comment.
				*/
				pb.ioDTReqCount = sizeof(Str255) - 1;
				error = PBDTGetCommentSync(&pb);
				if (error == noErr)
				{
					comment[0] = (unsigned char)pb.ioDTActCount;
				}
			}
		}
		else
		{
			/* There is no desktop database - try the Desktop file */
			error = GetCommentFromDesktopFile(vRefNum, dirID, name, comment);
			if ( error != noErr )
			{
				error = afpItemNotFound;	/* return an expected error */
			}
		}
	}
	else
	{
		error = paramErr;
	}
	
	return (error);
}

/*****************************************************************************/

pascal	OSErr	FSpDTGetComment(const FSSpec *spec,
							  Str255 comment)
{
	return (DTGetComment(spec->vRefNum, spec->parID, spec->name, comment));
}

/*****************************************************************************/

pascal	OSErr	DTCopyComment(short srcVRefNum,
							  long srcDirID,
							  ConstStr255Param srcName,
							  short dstVRefNum,
							  long dstDirID,
							  ConstStr255Param dstName)
/* The destination volume must support the Desktop Manager for this to work */
{
	OSErr error;
	Str255 comment;

	error = DTGetComment(srcVRefNum, srcDirID, srcName, comment);
	if ( (error == noErr) && (comment[0] > 0) )
	{
		error = DTSetComment(dstVRefNum, dstDirID, dstName, comment);
	}
	return (error);
}

/*****************************************************************************/

pascal	OSErr	FSpDTCopyComment(const FSSpec *srcSpec,
							   const FSSpec *dstSpec)
/* The destination volume must support the Desktop Manager for this to work */
{
	return (DTCopyComment(srcSpec->vRefNum, srcSpec->parID, srcSpec->name,
						dstSpec->vRefNum, dstSpec->parID, dstSpec->name));
}

/*****************************************************************************/



( run in 0.708 second using v1.01-cache-2.11-cpan-140bd7fdf52 )