• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/ap/gpl/amule/wxWidgets-2.8.12/src/mac/classic/morefile/
1/*
2	File:		MoreDesktopMgr.c
3
4	Contains:	A collection of useful high-level Desktop Manager routines.
5				If the Desktop Manager is not available, use the Desktop file
6				for 'read' operations.
7
8	Version:	MoreFiles
9
10	Copyright:	� 1992-2001 by Apple Computer, Inc., all rights reserved.
11
12	You may incorporate this sample code into your applications without
13	restriction, though the sample code has been provided "AS IS" and the
14	responsibility for its operation is 100% yours.  However, what you are
15	not permitted to do is to redistribute the source as "DSC Sample Code"
16	after having made changes. If you're going to re-distribute the source,
17	we require that you make it clear in the source that the code was
18	descended from Apple Sample Code, but that you've made changes.
19
20	File Ownership:
21
22		DRI:				Apple Macintosh Developer Technical Support
23
24		Other Contact:		Apple Macintosh Developer Technical Support
25							<http://developer.apple.com/bugreporter/>
26
27		Technology:			DTS Sample Code
28
29	Writers:
30
31		(JL)	Jim Luther
32		(NG)	Nitin Ganatra
33
34	Change History (most recent first):
35
36		 <2>	  2/7/01	JL		Added standard header. Updated names of includes. Updated
37									various routines to use new calling convention of the
38									MoreFilesExtras accessor functions.
39		<1>		12/06/99	JL		MoreFiles 1.5.
40*/
41
42#include <MacTypes.h>
43#include <MacErrors.h>
44#include <MacMemory.h>
45#include <Files.h>
46#include <Resources.h>
47#include <Icons.h>
48
49#define	__COMPILINGMOREFILES
50
51#include "MoreFiles.h"
52#include "MoreFilesExtras.h"
53#include "Search.h"
54#include "MoreDesktopMgr.h"
55
56/*****************************************************************************/
57
58/*	Desktop file notes:
59**
60**	�	The Desktop file is owned by the Finder and is normally open by the
61**		Finder. That means that we only have read-only access to the Desktop
62**		file.
63**	�	Since the Resource Manager doesn't support shared access to resource
64**		files and we're using read-only access, we don't ever leave the
65**		Desktop file open.  We open a path to it, get the data we want out
66**		of it, and then close the open path. This is the only safe way to
67**		open a resource file with read-only access since some other program
68**		could have it open with write access.
69**	�	The bundle related resources in the Desktop file are normally
70**		purgable, so when we're looking through them, we don't bother to
71**		release resources we're done looking at - closing the resource file
72**		(which we always do) will release them.
73**	�	Since we can't assume the Desktop file is named "Desktop"
74**		(it probably is everywhere but France), we get the Desktop
75**		file's name by searching the volume's root directory for a file
76**		with fileType == 'FNDR' and creator == 'ERIK'. The only problem with
77**		this scheme is that someone could create another file with that type
78**		and creator in the root directory and we'd find the wrong file.
79**		The chances of this are very slim.
80*/
81
82/*****************************************************************************/
83
84/* local defines */
85
86enum
87{
88	kBNDLResType	= 'BNDL',
89	kFREFResType	= 'FREF',
90	kIconFamResType	= 'ICN#',
91	kFCMTResType	= 'FCMT',
92	kAPPLResType	= 'APPL'
93};
94
95/*****************************************************************************/
96
97/* local data structures */
98
99#if PRAGMA_STRUCT_ALIGN
100#pragma options align=mac68k
101#endif
102
103struct IDRec
104{
105	short		localID;
106	short		rsrcID;
107};
108typedef struct IDRec IDRec;
109typedef	IDRec *IDRecPtr;
110
111struct BundleType
112{
113	OSType		type;			/* 'ICN#' or 'FREF' */
114	short		count;			/* number of IDRecs - 1 */
115	IDRec		idArray[1];
116};
117typedef struct BundleType BundleType;
118typedef BundleType *BundleTypePtr;
119
120struct BNDLRec
121{
122	OSType		signature;		/* creator type signature */
123	short		versionID;		/* version - should always be 0 */
124	short		numTypes;		/* number of elements in typeArray - 1 */
125	BundleType	typeArray[1];
126};
127typedef struct BNDLRec BNDLRec;
128typedef BNDLRec **BNDLRecHandle;
129
130struct FREFRec
131{
132	OSType		fileType;		/* file type */
133	short		iconID;			/* icon local ID */
134	Str255		fileName;		/* file name */
135};
136typedef struct FREFRec FREFRec;
137typedef FREFRec **FREFRecHandle;
138
139struct APPLRec
140{
141	OSType		creator;		/* creator type signature */
142	long		parID;			/* parent directory ID */
143	Str255		applName;		/* application name */
144};
145typedef struct APPLRec APPLRec;
146typedef APPLRec *APPLRecPtr;
147
148#if PRAGMA_STRUCT_ALIGN
149#pragma options align=reset
150#endif
151
152/*****************************************************************************/
153
154/* static prototypes */
155
156static	OSErr	GetDesktopFileName(short vRefNum,
157								   Str255 desktopName);
158
159static	OSErr	GetAPPLFromDesktopFile(ConstStr255Param volName,
160									   short vRefNum,
161									   OSType creator,
162									   short *applVRefNum,
163									   long *applParID,
164									   Str255 applName);
165
166static	OSErr	FindBundleGivenCreator(OSType creator,
167									   BNDLRecHandle *returnBndl);
168
169static	OSErr	FindTypeInBundle(OSType typeToFind,
170								 BNDLRecHandle theBndl,
171								 BundleTypePtr *returnBundleType);
172
173static	OSErr	GetLocalIDFromFREF(BundleTypePtr theBundleType,
174								   OSType fileType,
175								   short *iconLocalID);
176
177static	OSErr	GetIconRsrcIDFromLocalID(BundleTypePtr theBundleType,
178										 short iconLocalID,
179										 short *iconRsrcID);
180
181static	OSType	DTIconToResIcon(short iconType);
182
183static	OSErr	GetIconFromDesktopFile(ConstStr255Param volName,
184									   short vRefNum,
185									   short iconType,
186									   OSType fileCreator,
187									   OSType fileType,
188									   Handle *iconHandle);
189
190static	OSErr	GetCommentID(short vRefNum,
191							 long dirID,
192							 ConstStr255Param name,
193							 short *commentID);
194
195static	OSErr	GetCommentFromDesktopFile(short vRefNum,
196										  long dirID,
197										  ConstStr255Param name,
198										  Str255 comment);
199
200/*****************************************************************************/
201
202/*
203**	GetDesktopFileName
204**
205**	Get the name of the Desktop file.
206*/
207static	OSErr	GetDesktopFileName(short vRefNum,
208								   Str255 desktopName)
209{
210	OSErr			error;
211	HParamBlockRec	pb;
212	short			index;
213	Boolean			found;
214
215	pb.fileParam.ioNamePtr = desktopName;
216	pb.fileParam.ioVRefNum = vRefNum;
217	pb.fileParam.ioFVersNum = 0;
218	index = 1;
219	found = false;
220	do
221	{
222		pb.fileParam.ioDirID = fsRtDirID;
223		pb.fileParam.ioFDirIndex = index;
224		error = PBHGetFInfoSync(&pb);
225		if ( error == noErr )
226		{
227			if ( (pb.fileParam.ioFlFndrInfo.fdType == 'FNDR') &&
228				 (pb.fileParam.ioFlFndrInfo.fdCreator == 'ERIK') )
229			{
230				found = true;
231			}
232		}
233		++index;
234	} while ( (error == noErr) && !found );
235
236	return ( error );
237}
238
239/*****************************************************************************/
240
241pascal	OSErr	DTOpen(ConstStr255Param volName,
242					   short vRefNum,
243					   short *dtRefNum,
244					   Boolean *newDTDatabase)
245{
246	OSErr error;
247	GetVolParmsInfoBuffer volParmsInfo;
248	long infoSize;
249	DTPBRec pb;
250
251	/* Check for volume Desktop Manager support before calling */
252	infoSize = sizeof(GetVolParmsInfoBuffer);
253	error = HGetVolParms(volName, vRefNum, &volParmsInfo, &infoSize);
254	if ( error == noErr )
255	{
256		if ( hasDesktopMgr(&volParmsInfo) )
257		{
258			pb.ioNamePtr = (StringPtr)volName;
259			pb.ioVRefNum = vRefNum;
260			error = PBDTOpenInform(&pb);
261			/* PBDTOpenInform informs us if the desktop was just created */
262			/* by leaving the low bit of ioTagInfo clear (0) */
263			*newDTDatabase = ((pb.ioTagInfo & 1L) == 0);
264			if ( error == paramErr )
265			{
266				error = PBDTGetPath(&pb);
267				/* PBDTGetPath doesn't tell us if the database is new */
268				/* so assume it is not new */
269				*newDTDatabase = false;
270			}
271			*dtRefNum = pb.ioDTRefNum;
272		}
273		else
274		{
275			error = paramErr;
276		}
277	}
278	return ( error );
279}
280
281/*****************************************************************************/
282
283/*
284**	GetAPPLFromDesktopFile
285**
286**	Get a application's location from the
287**	Desktop file's 'APPL' resources.
288*/
289static	OSErr	GetAPPLFromDesktopFile(ConstStr255Param volName,
290									   short vRefNum,
291									   OSType creator,
292									   short *applVRefNum,
293									   long *applParID,
294									   Str255 applName)
295{
296	OSErr error;
297	short realVRefNum;
298	Str255 desktopName;
299	short savedResFile;
300	short dfRefNum;
301	Handle applResHandle;
302	Boolean foundCreator;
303	Ptr applPtr;
304	long applSize;
305
306	error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
307	if ( error == noErr )
308	{
309		error = GetDesktopFileName(realVRefNum, desktopName);
310		if ( error == noErr )
311		{
312			savedResFile = CurResFile();
313			/*
314			**	Open the 'Desktop' file in the root directory. (because
315			**	opening the resource file could preload unwanted resources,
316			**	bracket the call with SetResLoad(s))
317			*/
318			SetResLoad(false);
319			dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
320			SetResLoad(true);
321
322			if ( dfRefNum != -1)
323			{
324				/* Get 'APPL' resource ID 0 */
325				applResHandle = Get1Resource(kAPPLResType, 0);
326				if ( applResHandle != NULL )
327				{
328					applSize = GetHandleSize((Handle)applResHandle);
329					if ( applSize != 0 )	/* make sure the APPL resource isn't empty */
330					{
331						foundCreator = false;
332						applPtr = *applResHandle;
333
334						/* APPL's don't have a count so I have to use the size as the bounds */
335						while ( (foundCreator == false) &&
336								(applPtr < (*applResHandle + applSize)) )
337						{
338							if ( ((APPLRecPtr)applPtr)->creator == creator )
339							{
340								foundCreator = true;
341							}
342							else
343							{
344								/* fun with pointer math... */
345								applPtr += sizeof(OSType) +
346										   sizeof(long) +
347										   ((APPLRecPtr)applPtr)->applName[0] + 1;
348								/* application mappings are word aligned within the resource */
349								if ( ((unsigned long)applPtr % 2) != 0 )
350								{
351									applPtr += 1;
352								}
353							}
354						}
355						if ( foundCreator == true )
356						{
357							*applVRefNum = realVRefNum;
358							*applParID = ((APPLRecPtr)applPtr)->parID;
359							BlockMoveData(((APPLRecPtr)applPtr)->applName,
360										  applName,
361										  ((APPLRecPtr)applPtr)->applName[0] + 1);
362							/* error is already noErr */
363						}
364						else
365						{
366							error = afpItemNotFound;	/* didn't find a creator match */
367						}
368					}
369					else
370					{
371						error = afpItemNotFound;	/* no APPL mapping available */
372					}
373				}
374				else
375				{
376					error = afpItemNotFound;	/* no APPL mapping available */
377				}
378
379				/* restore the resource chain and close the Desktop file */
380				UseResFile(savedResFile);
381				CloseResFile(dfRefNum);
382			}
383			else
384			{
385				error = afpItemNotFound;
386			}
387		}
388	}
389
390	return ( error );
391}
392
393/*****************************************************************************/
394
395pascal	OSErr	DTXGetAPPL(ConstStr255Param volName,
396						   short vRefNum,
397						   OSType creator,
398						   Boolean searchCatalog,
399						   short *applVRefNum,
400						   long *applParID,
401						   Str255 applName)
402{
403	OSErr error;
404	UniversalFMPB pb;
405	short dtRefNum;
406	Boolean newDTDatabase;
407	short realVRefNum;
408	short index;
409	Boolean applFound;
410	FSSpec spec;
411	long actMatchCount;
412
413	/* get the real vRefNum */
414	error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
415	if ( error == noErr )
416	{
417		error = DTOpen(volName, vRefNum, &dtRefNum, &newDTDatabase);
418		if ( error == noErr )
419		{
420			if ( !newDTDatabase )
421			{
422				index = 0;
423				applFound = false;
424				do
425				{
426					pb.dtPB.ioNamePtr = applName;
427					pb.dtPB.ioDTRefNum = dtRefNum;
428					pb.dtPB.ioIndex = index;
429					pb.dtPB.ioFileCreator = creator;
430					error = PBDTGetAPPLSync(&pb.dtPB);
431					if ( error == noErr )
432					{
433						/* got a match - see if it is valid */
434
435						*applVRefNum = realVRefNum; /* get the vRefNum now */
436						*applParID = pb.dtPB.ioAPPLParID; /* get the parent ID now */
437
438						/* pb.hPB.fileParam.ioNamePtr is already set */
439						pb.hPB.fileParam.ioVRefNum = realVRefNum;
440						pb.hPB.fileParam.ioFVersNum = 0;
441						pb.hPB.fileParam.ioDirID = *applParID;
442						pb.hPB.fileParam.ioFDirIndex = 0;	/* use ioNamePtr and ioDirID */
443						if ( PBHGetFInfoSync(&pb.hPB) == noErr )
444						{
445							if ( (pb.hPB.fileParam.ioFlFndrInfo.fdCreator == creator) &&
446								 (pb.hPB.fileParam.ioFlFndrInfo.fdType == 'APPL') )
447							{
448								applFound = true;
449							}
450						}
451					}
452					++index;
453				} while ( (error == noErr) && !applFound );
454				if ( error != noErr )
455				{
456					error = afpItemNotFound;
457				}
458			}
459			else
460			{
461				/* Desktop database is empty (new), set error to try CatSearch */
462				error = afpItemNotFound;
463			}
464		}
465		/* acceptable errors from Desktop Manager to continue are paramErr or afpItemNotFound */
466		if ( error == paramErr )
467		{
468			/* if paramErr, the volume didn't support the Desktop Manager */
469			/* try the Desktop file */
470
471			error = GetAPPLFromDesktopFile(volName, vRefNum, creator,
472											applVRefNum, applParID, applName);
473			if ( error == noErr )
474			{
475				/* got a match - see if it is valid */
476
477				pb.hPB.fileParam.ioNamePtr = applName;
478				pb.hPB.fileParam.ioVRefNum = *applVRefNum;
479				pb.hPB.fileParam.ioFVersNum = 0;
480				pb.hPB.fileParam.ioDirID = *applParID;
481				pb.hPB.fileParam.ioFDirIndex = 0;	/* use ioNamePtr and ioDirID */
482				if ( PBHGetFInfoSync(&pb.hPB) == noErr )
483				{
484					if ( (pb.hPB.fileParam.ioFlFndrInfo.fdCreator != creator) ||
485						 (pb.hPB.fileParam.ioFlFndrInfo.fdType != 'APPL') )
486					{
487						error = afpItemNotFound;
488					}
489				}
490				else if ( error == fnfErr )
491				{
492					error = afpItemNotFound;
493				}
494			}
495		}
496		/* acceptable error from DesktopFile code to continue is afpItemNotFound */
497		if ( (error == afpItemNotFound) && searchCatalog)
498		{
499			/* Couldn't be found in the Desktop file either, */
500			/* try searching with CatSearch if requested */
501
502			error = CreatorTypeFileSearch(NULL, realVRefNum, creator, kAPPLResType, &spec, 1,
503											&actMatchCount, true);
504			if ( (error == noErr) || (error == eofErr) )
505			{
506				if ( actMatchCount > 0 )
507				{
508					*applVRefNum = spec.vRefNum;
509					*applParID = spec.parID;
510					BlockMoveData(spec.name, applName, spec.name[0] + 1);
511				}
512				else
513				{
514					error = afpItemNotFound;
515				}
516			}
517		}
518	}
519
520	return ( error );
521}
522
523/*****************************************************************************/
524
525pascal	OSErr	FSpDTXGetAPPL(ConstStr255Param volName,
526							  short vRefNum,
527							  OSType creator,
528							  Boolean searchCatalog,
529							  FSSpec *spec)
530{
531	return ( DTXGetAPPL(volName, vRefNum, creator, searchCatalog,
532						&(spec->vRefNum), &(spec->parID), spec->name) );
533}
534
535/*****************************************************************************/
536
537pascal	OSErr	DTGetAPPL(ConstStr255Param volName,
538						  short vRefNum,
539						  OSType creator,
540						  short *applVRefNum,
541						  long *applParID,
542						  Str255 applName)
543{
544	/* Call DTXGetAPPL with the "searchCatalog" parameter true */
545	return ( DTXGetAPPL(volName, vRefNum, creator, true,
546						applVRefNum, applParID, applName) );
547}
548
549/*****************************************************************************/
550
551pascal	OSErr	FSpDTGetAPPL(ConstStr255Param volName,
552							 short vRefNum,
553							 OSType creator,
554							 FSSpec *spec)
555{
556	/* Call DTXGetAPPL with the "searchCatalog" parameter true */
557	return ( DTXGetAPPL(volName, vRefNum, creator, true,
558						&(spec->vRefNum), &(spec->parID), spec->name) );
559}
560
561/*****************************************************************************/
562
563/*
564**	FindBundleGivenCreator
565**
566**	Search the current resource file for the 'BNDL' resource with the given
567**	creator and return a handle to it.
568*/
569static	OSErr	FindBundleGivenCreator(OSType creator,
570									   BNDLRecHandle *returnBndl)
571{
572	OSErr			error;
573	short			numOfBundles;
574	short			index;
575	BNDLRecHandle	theBndl;
576
577	error = afpItemNotFound;	/* default to not found */
578
579	/* Search each BNDL resource until we find the one with a matching creator. */
580
581	numOfBundles = Count1Resources(kBNDLResType);
582	index = 1;
583	*returnBndl = NULL;
584
585	while ( (index <= numOfBundles) && (*returnBndl == NULL) )
586	{
587		theBndl = (BNDLRecHandle)Get1IndResource(kBNDLResType, index);
588
589		if ( theBndl != NULL )
590		{
591			if ( (*theBndl)->signature == creator )
592			{
593				/* numTypes and typeArray->count will always be the actual count minus 1, */
594				/* so 0 in both fields is valid. */
595				if ( ((*theBndl)->numTypes >= 0) && ((*theBndl)->typeArray->count >= 0) )
596				{
597					/* got it */
598					*returnBndl = theBndl;
599					error = noErr;
600				}
601			}
602		}
603
604		index ++;
605	}
606
607	return ( error );
608}
609
610/*****************************************************************************/
611
612/*
613**	FindTypeInBundle
614**
615**	Given a Handle to a BNDL return a pointer to the desired type
616**	in it. If the type is not found, or if the type's count < 0,
617**	return afpItemNotFound.
618*/
619static	OSErr	FindTypeInBundle(OSType typeToFind,
620								 BNDLRecHandle theBndl,
621								 BundleTypePtr *returnBundleType)
622{
623	OSErr			error;
624	short			index;
625	Ptr				ptrIterator;	/* use a Ptr so we can do ugly pointer math */
626
627	error = afpItemNotFound;	/* default to not found */
628
629	ptrIterator = (Ptr)((*theBndl)->typeArray);
630	index = 0;
631	*returnBundleType = NULL;
632
633	while ( (index < ((*theBndl)->numTypes + 1)) &&
634			(*returnBundleType == NULL) )
635	{
636		if ( (((BundleTypePtr)ptrIterator)->type == typeToFind) &&
637			 (((BundleTypePtr)ptrIterator)->count >= 0) )
638		{
639				*returnBundleType = (BundleTypePtr)ptrIterator;
640				error = noErr;
641		}
642		else
643		{
644			ptrIterator += ( sizeof(OSType) +
645							 sizeof(short) +
646							 ( sizeof(IDRec) * (((BundleTypePtr)ptrIterator)->count + 1) ) );
647			++index;
648		}
649	}
650
651	return ( error );
652}
653
654/*****************************************************************************/
655
656/*
657**	GetLocalIDFromFREF
658**
659**	Given a pointer to a 'FREF' BundleType record, load each 'FREF' resource
660**	looking for a matching fileType. If a matching fileType is found, return
661**	its icon local ID. If no match is found, return afpItemNotFound as the
662**	function result.
663*/
664static	OSErr	GetLocalIDFromFREF(BundleTypePtr theBundleType,
665								   OSType fileType,
666								   short *iconLocalID)
667{
668	OSErr			error;
669	short			index;
670	IDRecPtr		idIterator;
671	FREFRecHandle	theFref;
672
673	error = afpItemNotFound;	/* default to not found */
674
675	/* For each localID in this type, get the FREF resource looking for fileType */
676	index = 0;
677	idIterator = &theBundleType->idArray[0];
678	*iconLocalID = 0;
679
680	while ( (index <= theBundleType->count) && (*iconLocalID == 0) )
681	{
682		theFref = (FREFRecHandle)Get1Resource(kFREFResType, idIterator->rsrcID);
683		if ( theFref != NULL )
684		{
685			if ( (*theFref)->fileType == fileType )
686			{
687				*iconLocalID = (*theFref)->iconID;
688				error = noErr;
689			}
690		}
691
692		++idIterator;
693		++index;
694	}
695
696	return ( error );
697}
698
699/*****************************************************************************/
700
701/*
702**	GetIconRsrcIDFromLocalID
703**
704**	Given a pointer to a 'ICN#' BundleType record, look for the IDRec with
705**	the localID that matches iconLocalID. If a matching IDRec is found,
706**	return the IDRec's rsrcID field value. If no match is found, return
707**	afpItemNotFound as the function result.
708*/
709static	OSErr	GetIconRsrcIDFromLocalID(BundleTypePtr theBundleType,
710										 short iconLocalID,
711										 short *iconRsrcID)
712{
713	OSErr		error;
714	short		index;
715	IDRecPtr	idIterator;
716
717	error = afpItemNotFound;	/* default to not found */
718
719	/* Find the rsrcID of the icon family type, given the localID */
720	index = 0;
721	idIterator = &theBundleType->idArray[0];
722	*iconRsrcID = 0;
723
724	while ( (index <= theBundleType->count) && (*iconRsrcID == 0) )
725	{
726		if ( idIterator->localID == iconLocalID )
727		{
728			*iconRsrcID = idIterator->rsrcID;
729			error = noErr;
730		}
731
732		idIterator ++;
733		index ++;
734	}
735
736	return ( error );
737}
738
739/*****************************************************************************/
740
741/*
742**	DTIconToResIcon
743**
744**	Map a Desktop Manager icon type to the corresponding resource type.
745**	Return (OSType)0 if there is no corresponding resource type.
746*/
747static	OSType	DTIconToResIcon(short iconType)
748{
749	OSType	resType;
750
751	switch ( iconType )
752	{
753		case kLargeIcon:
754			resType = large1BitMask;
755			break;
756		case kLarge4BitIcon:
757			resType = large4BitData;
758			break;
759		case kLarge8BitIcon:
760			resType = large8BitData;
761			break;
762		case kSmallIcon:
763			resType = small1BitMask;
764			break;
765		case kSmall4BitIcon:
766			resType = small4BitData;
767			break;
768		case kSmall8BitIcon:
769			resType = small8BitData;
770			break;
771		default:
772			resType = (OSType)0;
773			break;
774	}
775
776	return ( resType );
777}
778
779/*****************************************************************************/
780
781/*
782**	GetIconFromDesktopFile
783**
784**	INPUT a pointer to a non-existent Handle, because we'll allocate one
785**
786**	search each BNDL resource for the right fileCreator and once we get it
787**		find the 'FREF' type in BNDL
788**		for each localID in the type, open the FREF resource
789**			if the FREF is the desired fileType
790**				get its icon localID
791**				get the ICN# type in BNDL
792**				get the icon resource number from the icon localID
793**				get the icon resource type from the desktop mgr's iconType
794**				get the icon of that type and number
795*/
796static	OSErr	GetIconFromDesktopFile(ConstStr255Param volName,
797									   short vRefNum,
798									   short iconType,
799									   OSType fileCreator,
800									   OSType fileType,
801									   Handle *iconHandle)
802{
803	OSErr			error;
804	short			realVRefNum;
805	Str255			desktopName;
806	short			savedResFile;
807	short			dfRefNum;
808	BNDLRecHandle	theBndl = NULL;
809	BundleTypePtr	theBundleType;
810	short			iconLocalID;
811	short			iconRsrcID;
812	OSType			iconRsrcType;
813	Handle			returnIconHandle;
814	char			bndlState;
815
816	*iconHandle = NULL;
817
818	error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
819	if ( error == noErr )
820	{
821		error = GetDesktopFileName(realVRefNum, desktopName);
822		if ( error == noErr )
823		{
824			savedResFile = CurResFile();
825
826			/*
827			**	Open the 'Desktop' file in the root directory. (because
828			**	opening the resource file could preload unwanted resources,
829			**	bracket the call with SetResLoad(s))
830			*/
831			SetResLoad(false);
832			dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
833			SetResLoad(true);
834
835			if ( dfRefNum != -1 )
836			{
837				/*
838				**	Find the BNDL resource with the specified creator.
839				*/
840				error = FindBundleGivenCreator(fileCreator, &theBndl);
841				if ( error == noErr )
842				{
843					/* Lock the BNDL resource so it won't be purged when other resources are loaded */
844					bndlState = HGetState((Handle)theBndl);
845					HLock((Handle)theBndl);
846
847					/* Find the 'FREF' BundleType record in the BNDL resource. */
848					error = FindTypeInBundle(kFREFResType, theBndl, &theBundleType);
849					if ( error == noErr )
850					{
851						/* Find the local ID in the 'FREF' resource with the specified fileType */
852						error = GetLocalIDFromFREF(theBundleType, fileType, &iconLocalID);
853						if ( error == noErr )
854						{
855							/* Find the 'ICN#' BundleType record in the BNDL resource. */
856							error = FindTypeInBundle(kIconFamResType, theBndl, &theBundleType);
857							if ( error == noErr )
858							{
859								/* Find the icon's resource ID in the 'ICN#' BundleType record */
860								error = GetIconRsrcIDFromLocalID(theBundleType, iconLocalID, &iconRsrcID);
861								if ( error == noErr )
862								{
863									/* Map Desktop Manager icon type to resource type */
864									iconRsrcType = DTIconToResIcon(iconType);
865
866									if ( iconRsrcType != (OSType)0 )
867									{
868										/* Load the icon */
869										returnIconHandle = Get1Resource(iconRsrcType, iconRsrcID);
870										if ( returnIconHandle != NULL )
871										{
872											/* Copy the resource handle, and return the copy */
873											HandToHand(&returnIconHandle);
874											if ( MemError() == noErr )
875											{
876												*iconHandle = returnIconHandle;
877											}
878											else
879											{
880												error = afpItemNotFound;
881											}
882										}
883										else
884										{
885											error = afpItemNotFound;
886										}
887									}
888								}
889							}
890						}
891					}
892					/* Restore the state of the BNDL resource */
893					HSetState((Handle)theBndl, bndlState);
894				}
895				/* Restore the resource chain and close the Desktop file */
896				UseResFile(savedResFile);
897				CloseResFile(dfRefNum);
898			}
899			else
900			{
901				error = ResError(); /* could not open Desktop file */
902			}
903		}
904		if ( (error != noErr) && (error != memFullErr) )
905		{
906			error = afpItemNotFound;	/* force an error we should return */
907		}
908	}
909
910	return ( error );
911}
912
913/*****************************************************************************/
914
915pascal	OSErr	DTGetIcon(ConstStr255Param volName,
916						  short vRefNum,
917						  short iconType,
918						  OSType fileCreator,
919						  OSType fileType,
920						  Handle *iconHandle)
921{
922	OSErr error;
923	DTPBRec pb;
924	short dtRefNum;
925	Boolean newDTDatabase;
926	Size bufferSize;
927
928	*iconHandle = NULL;
929	error = DTOpen(volName, vRefNum, &dtRefNum, &newDTDatabase);
930	if ( error == noErr )
931	{
932		/* there was a desktop database and it's now open */
933
934		if ( !newDTDatabase )	/* don't bother to look in a new (empty) database */
935		{
936			/* get the buffer size for the requested icon type */
937			switch ( iconType )
938			{
939				case kLargeIcon:
940					bufferSize = kLargeIconSize;
941					break;
942				case kLarge4BitIcon:
943					bufferSize = kLarge4BitIconSize;
944					break;
945				case kLarge8BitIcon:
946					bufferSize = kLarge8BitIconSize;
947					break;
948				case kSmallIcon:
949					bufferSize = kSmallIconSize;
950					break;
951				case kSmall4BitIcon:
952					bufferSize = kSmall4BitIconSize;
953					break;
954				case kSmall8BitIcon:
955					bufferSize = kSmall8BitIconSize;
956					break;
957				default:
958					iconType = 0;
959					bufferSize = 0;
960					break;
961			}
962			if ( bufferSize != 0 )
963			{
964				*iconHandle = NewHandle(bufferSize);
965				if ( *iconHandle != NULL )
966				{
967					HLock(*iconHandle);
968
969					pb.ioDTRefNum = dtRefNum;
970					pb.ioTagInfo = 0;
971					pb.ioDTBuffer = **iconHandle;
972					pb.ioDTReqCount = bufferSize;
973					pb.ioIconType = iconType;
974					pb.ioFileCreator = fileCreator;
975					pb.ioFileType = fileType;
976					error = PBDTGetIconSync(&pb);
977
978					HUnlock(*iconHandle);
979
980					if ( error != noErr )
981					{
982						DisposeHandle(*iconHandle);	/* dispose of the allocated memory */
983						*iconHandle = NULL;
984					}
985				}
986				else
987				{
988					error = memFullErr;	/* handle could not be allocated */
989				}
990			}
991			else
992			{
993				error = paramErr;	/* unknown icon type requested */
994			}
995		}
996		else
997		{
998			error = afpItemNotFound;	/* the desktop database was empty - nothing to return */
999		}
1000	}
1001	else
1002	{
1003		/* There is no desktop database - try the Desktop file */
1004
1005		error = GetIconFromDesktopFile(volName, vRefNum, iconType,
1006										fileCreator, fileType, iconHandle);
1007	}
1008
1009	return ( error );
1010}
1011
1012/*****************************************************************************/
1013
1014pascal	OSErr	DTSetComment(short vRefNum,
1015							 long dirID,
1016							 ConstStr255Param name,
1017							 ConstStr255Param comment)
1018{
1019	DTPBRec pb;
1020	OSErr error;
1021	short dtRefNum;
1022	Boolean newDTDatabase;
1023
1024	error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
1025	if ( error == noErr )
1026	{
1027		pb.ioDTRefNum = dtRefNum;
1028		pb.ioNamePtr = (StringPtr)name;
1029		pb.ioDirID = dirID;
1030		pb.ioDTBuffer = (Ptr)&comment[1];
1031		/* Truncate the comment to 200 characters just in case */
1032		/* some file system doesn't range check */
1033		if ( comment[0] <= 200 )
1034		{
1035			pb.ioDTReqCount = comment[0];
1036		}
1037		else
1038		{
1039			pb.ioDTReqCount = 200;
1040		}
1041		error = PBDTSetCommentSync(&pb);
1042	}
1043	return (error);
1044}
1045
1046/*****************************************************************************/
1047
1048pascal	OSErr	FSpDTSetComment(const FSSpec *spec,
1049							  ConstStr255Param comment)
1050{
1051	return (DTSetComment(spec->vRefNum, spec->parID, spec->name, comment));
1052}
1053
1054/*****************************************************************************/
1055
1056/*
1057**	GetCommentID
1058**
1059**	Get the comment ID number for the Desktop file's 'FCMT' resource ID from
1060**	the file or folders fdComment (frComment) field.
1061*/
1062static	OSErr	GetCommentID(short vRefNum,
1063							 long dirID,
1064							 ConstStr255Param name,
1065							 short *commentID)
1066{
1067	CInfoPBRec pb;
1068	OSErr error;
1069
1070	error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
1071	*commentID = pb.hFileInfo.ioFlXFndrInfo.fdComment;
1072	return ( error );
1073}
1074
1075/*****************************************************************************/
1076
1077/*
1078**	GetCommentFromDesktopFile
1079**
1080**	Get a file or directory's Finder comment field (if any) from the
1081**	Desktop file's 'FCMT' resources.
1082*/
1083static	OSErr	GetCommentFromDesktopFile(short vRefNum,
1084										  long dirID,
1085										  ConstStr255Param name,
1086										  Str255 comment)
1087{
1088	OSErr error;
1089	short commentID;
1090	short realVRefNum;
1091	Str255 desktopName;
1092	short savedResFile;
1093	short dfRefNum;
1094	StringHandle commentHandle;
1095
1096	/* Get the comment ID number */
1097	error = GetCommentID(vRefNum, dirID, name, &commentID);
1098	if ( error == noErr )
1099	{
1100		if ( commentID != 0 )	/* commentID == 0 means there's no comment */
1101		{
1102			error = DetermineVRefNum(name, vRefNum, &realVRefNum);
1103			if ( error == noErr )
1104			{
1105				error = GetDesktopFileName(realVRefNum, desktopName);
1106				if ( error == noErr )
1107				{
1108					savedResFile = CurResFile();
1109					/*
1110					**	Open the 'Desktop' file in the root directory. (because
1111					**	opening the resource file could preload unwanted resources,
1112					**	bracket the call with SetResLoad(s))
1113					*/
1114					SetResLoad(false);
1115					dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
1116					SetResLoad(true);
1117
1118					if ( dfRefNum != -1)
1119					{
1120						/* Get the comment resource */
1121						commentHandle = (StringHandle)Get1Resource(kFCMTResType,commentID);
1122						if ( commentHandle != NULL )
1123						{
1124							if ( GetHandleSize((Handle)commentHandle) > 0 )
1125							{
1126								BlockMoveData(*commentHandle, comment, *commentHandle[0] + 1);
1127							}
1128							else
1129							{
1130								error = afpItemNotFound;	/* no comment available */
1131							}
1132						}
1133						else
1134						{
1135							error = afpItemNotFound;	/* no comment available */
1136						}
1137
1138						/* restore the resource chain and close the Desktop file */
1139						UseResFile(savedResFile);
1140						CloseResFile(dfRefNum);
1141					}
1142					else
1143					{
1144						error = afpItemNotFound;
1145					}
1146				}
1147				else
1148				{
1149					error = afpItemNotFound;
1150				}
1151			}
1152		}
1153		else
1154		{
1155			error = afpItemNotFound;	/* no comment available */
1156		}
1157	}
1158
1159	return ( error );
1160}
1161
1162/*****************************************************************************/
1163
1164pascal	OSErr	DTGetComment(short vRefNum,
1165							 long dirID,
1166							 ConstStr255Param name,
1167							 Str255 comment)
1168{
1169	DTPBRec pb;
1170	OSErr error;
1171	short dtRefNum;
1172	Boolean newDTDatabase;
1173
1174	if (comment != NULL)
1175	{
1176		comment[0] = 0;	/* return nothing by default */
1177
1178		/* attempt to open the desktop database */
1179		error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
1180		if ( error == noErr )
1181		{
1182			/* There was a desktop database and it's now open */
1183
1184			if ( !newDTDatabase )
1185			{
1186				pb.ioDTRefNum = dtRefNum;
1187				pb.ioNamePtr = (StringPtr)name;
1188				pb.ioDirID = dirID;
1189				pb.ioDTBuffer = (Ptr)&comment[1];
1190				/*
1191				**	IMPORTANT NOTE #1: Inside Macintosh says that comments
1192				**	are up to 200 characters. While that may be correct for
1193				**	the HFS file system's Desktop Manager, other file
1194				**	systems (such as Apple Photo Access) return up to
1195				**	255 characters. Make sure the comment buffer is a Str255
1196				**	or you'll regret it.
1197				**
1198				**	IMPORTANT NOTE #2: Although Inside Macintosh doesn't
1199				**	mention it, ioDTReqCount is a input field to
1200				**	PBDTGetCommentSync. Some file systems (like HFS) ignore
1201				**	ioDTReqCount and always return the full comment --
1202				**	others (like AppleShare) respect ioDTReqCount and only
1203				**	return up to ioDTReqCount characters of the comment.
1204				*/
1205				pb.ioDTReqCount = sizeof(Str255) - 1;
1206				error = PBDTGetCommentSync(&pb);
1207				if (error == noErr)
1208				{
1209					comment[0] = (unsigned char)pb.ioDTActCount;
1210				}
1211			}
1212		}
1213		else
1214		{
1215			/* There is no desktop database - try the Desktop file */
1216			error = GetCommentFromDesktopFile(vRefNum, dirID, name, comment);
1217			if ( error != noErr )
1218			{
1219				error = afpItemNotFound;	/* return an expected error */
1220			}
1221		}
1222	}
1223	else
1224	{
1225		error = paramErr;
1226	}
1227
1228	return (error);
1229}
1230
1231/*****************************************************************************/
1232
1233pascal	OSErr	FSpDTGetComment(const FSSpec *spec,
1234							  Str255 comment)
1235{
1236	return (DTGetComment(spec->vRefNum, spec->parID, spec->name, comment));
1237}
1238
1239/*****************************************************************************/
1240
1241pascal	OSErr	DTCopyComment(short srcVRefNum,
1242							  long srcDirID,
1243							  ConstStr255Param srcName,
1244							  short dstVRefNum,
1245							  long dstDirID,
1246							  ConstStr255Param dstName)
1247/* The destination volume must support the Desktop Manager for this to work */
1248{
1249	OSErr error;
1250	Str255 comment;
1251
1252	error = DTGetComment(srcVRefNum, srcDirID, srcName, comment);
1253	if ( (error == noErr) && (comment[0] > 0) )
1254	{
1255		error = DTSetComment(dstVRefNum, dstDirID, dstName, comment);
1256	}
1257	return (error);
1258}
1259
1260/*****************************************************************************/
1261
1262pascal	OSErr	FSpDTCopyComment(const FSSpec *srcSpec,
1263							   const FSSpec *dstSpec)
1264/* The destination volume must support the Desktop Manager for this to work */
1265{
1266	return (DTCopyComment(srcSpec->vRefNum, srcSpec->parID, srcSpec->name,
1267						dstSpec->vRefNum, dstSpec->parID, dstSpec->name));
1268}
1269
1270/*****************************************************************************/
1271