The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
/* $Header: /cvsroot/macperl/perl/macos/ext/Mac/Resources/Resources.xs,v 1.7 2003/10/28 05:53:31 pudge Exp $
 *
 *    Copyright (c) 1996 Matthias Neeracher
 *
 *    You may distribute under the terms of the Perl Artistic License,
 *    as specified in the README file.
 *
 * $Log: Resources.xs,v $
 * Revision 1.7  2003/10/28 05:53:31  pudge
 * Add Carbon compat. notes
 *
 * Revision 1.6  2003/05/08 03:15:16  pudge
 * Properly free stuff, get path size
 *
 * Revision 1.5  2003/04/06 21:45:41  pudge
 * Add FSCreateResourceFile and FSOpenResourceFile for creating/opening resource
 * files from data fork instead of resource fork
 *
 * Revision 1.4  2002/11/13 02:04:52  pudge
 * Aieeeeee!  Big ol' Carbon update.
 *
 * Revision 1.3  2002/01/23 05:44:42  pudge
 * Update whitespace etc., from Thomas
 *
 * Revision 1.2  2000/09/09 22:18:28  neeri
 * Dynamic libraries compile under 5.6
 *
 * Revision 1.1  2000/08/14 03:39:33  neeri
 * Checked into Sourceforge
 *
 * Revision 1.3  1998/04/07 01:03:11  neeri
 * MacPerl 5.2.0r4b1
 *
 * Revision 1.2  1997/11/18 00:53:19  neeri
 * MacPerl 5.1.5
 *
 * Revision 1.1  1997/04/07 20:50:41  neeri
 * Synchronized with MacPerl 5.1.4a1
 *
 */

#define MAC_CONTEXT

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#ifndef MACOS_TRADITIONAL
#include "../Carbon.h"
#endif
#include <Types.h>
#include <Memory.h>
#include <Resources.h>

#define ResErrorReturn	\
	if (gMacPerl_OSErr = ResError()) {	\
		XSRETURN_UNDEF;						\
	} else {							\
		XSRETURN_YES;						\
	}

#define ResErrorCheck						\
	if (gMacPerl_OSErr = ResError()) {	\
		XSRETURN_UNDEF;						\
	} else 0 	

#define ResErrorCheckRetval				\
	if (RETVAL == -1) {						\
		gMacPerl_OSErr = ResError();		\
		XSRETURN_UNDEF;						\
	} else 0

#define ResErrorCheckRetvalNULL			\
	if (!RETVAL) {								\
		gMacPerl_OSErr = ResError();		\
		XSRETURN_UNDEF;						\
	} else 0

MODULE = Mac::Resources	PACKAGE = Mac::Resources

=head2 Functions

=over 4

=item CloseResFile RFD

Given a file reference number for a file whose resource fork is open, the
CloseResFile procedure performs four tasks. First, it updates the file by calling
the &UpdateResFile procedure. Second, it releases the memory occupied by each
resource in the resource fork by calling the &DisposeHandle procedure. Third, it
releases the memory occupied by the resource map. The fourth task is to close the
resource fork.

=cut
void
CloseResFile(refNum)
	short	refNum

=item CurResFile

The CurResFile function returns the file reference number associated with the
current resource file. You can call this function when your application starts up
(before opening the resource fork of any other file) to get the file reference
number of your application's resource fork.

    $RFD = CurResFile;

=cut
short
CurResFile()

=item HomeResFile RESOURCE

Given a handle to a resource, the HomeResFile function returns the file reference
number for the resource fork containing the specified resource. If the given
handle isn't a handle to a resource, HomeResFile returns Ð1, and the &ResError
function returns the result code resNotFound. If HomeResFile returns 0, the
resource is in the System file's resource fork. If HomeResFile returns 1, the
resource is ROM-resident.

    $RFD = HomeResFile($Resource);

=cut
short
HomeResFile(theResource)
	Handle	theResource
	CLEANUP:
	ResErrorCheckRetval;

=item CreateResFile NAME

B<Mac OS only.>

The CreateResFile procedure creates an empty resource file.

    if ( CreateResFile("Resource.rsrc")) {
        # error occurred
    } else {
        # proceed
    }

=cut

#ifndef MACOS_TRADITIONAL

void
CreateResFile(fileName)
	Str255	fileName
	CODE:
	croak("Usage: Mac::Resourcecs::CreateResFile unsupported in Carbon");

#else

void
CreateResFile(fileName)
	Str255	fileName
	CLEANUP:
	ResErrorReturn;

#endif

=item OpenResFile NAME

B<Mac OS only.>

The OpenResFile function opens an existing resource file. It also makes this file
the current resource file.

    if ( defined($RFD = OpenResFile("Resource.rsrc")) ) {
        # proceed
    } else {
        # error occurred
    }

=cut

#ifndef MACOS_TRADITIONAL

short
OpenResFile(fileName)
	Str255	fileName
	CODE:
	croak("Usage: Mac::Resourcecs::OpenResFile unsupported in Carbon");

#else

short
OpenResFile(fileName)
	Str255	fileName
	CLEANUP:
	ResErrorCheckRetval;

#endif

=item UseResFile RFD

The UseResFile procedure searches the list of files whose resource forks have
been opened for the file specified by the RFD parameter. If the specified file
is found, the Resource Manager sets the current resource file to the specified
file. If there's no resource fork open for a file with that reference number,
UseResFile does nothing. To set the current resource file to the System file, use
0 for the refNum parameter.

    if (UseResFile($RFD)) {
        # error occurred
    } else {
        # proceed
    }

=cut
void
UseResFile(refNum)
	short	refNum
	CLEANUP:
	ResErrorReturn;


=item CountTypes

=item Count1Types

The CountTypes (Count1Types) function reads the resource maps in memory for all resource forks
(the current resource fork) open to your application. It returns an integer representing the 
total number of unique resource types.

    $types = Count1Types;

=cut
short
CountTypes()

short
Count1Types()

=item GetIndType INDEX

=item Get1IndType INDEX

Given an index number from 1 to the number of resource types in all resource
forks (the current resource fork)
open to your application (as returned by CountTypes), the GetIndType
procedure returns a resource type. You can call
GetIndType repeatedly over the entire range of the index to get all the resource
types available in all resource forks open to your application. If the given
index isn't in the range from 1 to the number of resource types as returned by
CountTypes, undef() is returned.

    # Load up @resourceTypes with the types from the current file.
    for (1 .. Count1Types) {
        $resourceTypes[$_-1] = Get1IndType($_);
    }

=cut
OSType
GetIndType(index)
	short	index
	CODE:
	GetIndType(&RETVAL, index);
	OUTPUT:
	RETVAL
	CLEANUP:
	ResErrorCheckRetvalNULL;

OSType
Get1IndType(index)
	short	index
	CODE:
	Get1IndType(&RETVAL, index);
	OUTPUT:
	RETVAL
	CLEANUP:
	ResErrorCheckRetvalNULL;

=item SetResLoad BOOL

Enable and disable automatic loading of resource data into memory for routines
that return handles to resources.

=cut
void
SetResLoad(load)
	Boolean	load

=item CountResources TYPE

=item Count1Resources TYPE

Get the total number of available resources of a given type. Count1Resources
looks only at the current resource fork.

    $totalDialogsAvailable = CountResources "DITL";

=cut
short
CountResources(theType)
	OSType	theType

short
Count1Resources(theType)
	OSType	theType

=item GetIndResource TYPE, INDEX

=item Get1IndResource TYPE, INDEX

Given an index ranging from 1 to the number of resources of a given type returned
by &CountResources (&Count1Resources) (that is, the number of resources of that type 
in all resource forks open to your application), the GetIndResource function returns a 
handle to a resource of the given type. If you call GetIndResource repeatedly over the
entire range of the index, it returns handles to all resources of the given type
in all resource forks open to your application.

    # Load up handles of this type of resource
    for (1 .. CountResources("DITL")) {
        $dialogs[$_] = GetIndResource("DITL", $_);
    }

=cut
Handle
GetIndResource(theType, index)
	OSType	theType
	short	index
	CLEANUP:
	ResErrorCheckRetvalNULL;

Handle
Get1IndResource(theType, index)
	OSType	theType
	short	index
	CLEANUP:
	ResErrorCheckRetvalNULL;

=item GetResource TYPE, ID

=item Get1Resource TYPE, ID

Get resource data for a resource specified by resource type and resource ID.

    $SFGdialog = GetResource("DITL", 6042);
    if ( defined $SFGdialog ) {
        # proceed
    }

=cut
Handle
GetResource(theType, theID)
	OSType	theType
	short	theID
	CLEANUP:
	ResErrorCheckRetvalNULL;

Handle
Get1Resource(theType, theID)
	OSType	theType
	short	theID
	CLEANUP:
	ResErrorCheckRetvalNULL;

=item GetNamedResource TYPE, NAME

=item Get1NamedResource TYPE, NAME

The GetNamedResource (Get1NamedResource) function searches the resource maps in memory for the
resource specified by the parameters $TYPE and $NAME.

    $SFGdialog = GetNamedResource("DITL", "Standard Get");
    if ( defined $SFGdialog ) {
        # proceed
    }

=cut
Handle
GetNamedResource(theType, name)
	OSType	theType
	Str255	name
	CLEANUP:
	ResErrorCheckRetvalNULL;

Handle
Get1NamedResource(theType, name)
	OSType	theType
	Str255	name
	CLEANUP:
	ResErrorCheckRetvalNULL;

=item LoadResource HANDLE

Given a handle to a resource, LoadResource reads the resource data into memory.
If the HANDLE parameter doesn't contain a handle to a resource, then LoadResource
returns undef.

    if (LoadResource($HANDLE) ) {
        # proceed
    } else {
        # error occurred
    }

=cut
void
LoadResource(theResource)
	Handle	theResource
	CLEANUP:
	ResErrorReturn;

=item ReleaseResource HANDLE

Given a handle to a resource, ReleaseResource releases the memory occupied by the
resource data, if any, and sets the master pointer of the resource's handle in
the resource map in memory to NIL. If your application previously obtained a
handle to that resource, the handle is no longer valid. If your application
subsequently calls the Resource Manager to get the released resource, the
Resource Manager assigns a new handle. 

    if ( ReleaseResource($HANDLE) ) {
        # proceed
    } else {
        # error occurred
    }

=cut
void
ReleaseResource(theResource)
	Handle	theResource
	CLEANUP:
	ResErrorReturn;

=item DetachResource HANDLE

Given a handle to a resource, ReleaseResource releases the memory occupied by the
resource data, if any, and sets the master pointer of the resource's handle in
the resource map in memory to NIL. If your application previously obtained a
handle to that resource, the handle is no longer valid. If your application
subsequently calls the Resource Manager to get the released resource, the
Resource Manager assigns a new handle. 

    if ( DetachResource($HANDLE) ) {
        # proceed
    } else {
        # error occurred
    }

=cut
void
DetachResource(theResource)
	Handle	theResource
	CLEANUP:
	ResErrorReturn;

=item UniqueID TYPE

=item Unique1ID TYPE

The UniqueID function returns as its function result a resource ID greater than 0
that isn't currently assigned to any resource of the specified type in any open
resource fork. You should use this function before adding a new resource to
ensure that you don't duplicate a resource ID and override an existing resource.
Unique1ID ensures uniqueness within the current resource fork.

    $id = Unique1ID("DITL");

=cut
short
UniqueID(theType)
	OSType	theType

short
Unique1ID(theType)
	OSType	theType


=item GetResAttrs HANDLE

Given a handle to a resource, the GetResAttrs function returns the resource's
attributes as recorded in its entry in the resource map in memory. If the value
of the theResource parameter isn't a handle to a valid resource, undef is returned.

    $resAttrs = GetResAttrs($HANDLE);
    if ( defined $resAttrs ) {
        # proceed
    }

=cut
short
GetResAttrs(theResource)
	Handle	theResource
	CLEANUP:
	ResErrorCheck;

=item GetResInfo HANDLE

Given a handle to a resource, the GetResInfo procedure returns the resource's
resource ID, resource type, and resource name. If the handle isn't a valid handle
to a resource, undef is returned.

    ($id, $type, $name) = GetResInfo($HANDLE);
    if ( defined $id ) {
        # proceed
    }

=cut
void
GetResInfo(theResource)
	Handle	theResource
	PPCODE:
	{
		short		theID;
		OSType	theType;
		Str255	name;
		
		GetResInfo(theResource, &theID, &theType, name);
		ResErrorCheck;

		EXTEND(sp, 3);
		XS_PUSH(short, theID);
		XS_PUSH(OSType, theType);
		if (*name)
			XS_PUSH(Str255, name);
	}

=item SetResInfo HANDLE, ID, NAME

Given a handle to a resource, SetResInfo changes the resource ID and the resource
name of the specified resource to the values given in ID and NAME. If you pass
an empty string for the name parameter, the resource name is not changed.

=cut
void
SetResInfo(theResource, theID, name)
	Handle	theResource
	short	theID
	Str255	name
	CLEANUP:
	ResErrorReturn;

=item AddResource HANDLE, TYPE, ID, NAME

Given a handle to any type of data in memory (but not a handle to an existing
resource), AddResource adds the given handle, resource type, resource ID, and
resource name to the current resource file's resource map in memory. The
AddResource procedure sets the resChanged attribute to 1; it does not set any of
the resource's other attributesÑthat is, all other attributes are set to 0.

=cut
void
AddResource(theData, theType, theID, name)
	Handle	theData
	OSType	theType
	short	theID
	Str255	name
	CLEANUP:
	ResErrorReturn;

=item GetResourceSizeOnDisk HANDLE

Given a handle to a resource, the GetResourceSizeOnDisk function checks the
resource on disk (not in memory) and returns its exact size, in bytes. If the
handle isn't a handle to a valid resource, undef is returned.

	$size = GetResourceSizeOnDisk($HANDLE);
	if ( defined $size ) {
		# proceed
	}

=cut
long
GetResourceSizeOnDisk(theResource)
	Handle	theResource
	CLEANUP:
	ResErrorCheckRetval;

=item GetMaxResourceSize HANDLE

Like &GetResourceSizeOnDisk, GetMaxResourceSize takes a handle and returns the
size of the corresponding resource. However, GetMaxResourceSize does not check
the resource on disk; instead, it either checks the resource size in memory or,
if the resource is not in memory, calculates its size, in bytes, on the basis of
information in the resource map in memory. This gives you an approximate size for
the resource that you can count on as the resource's maximum size. It's possible
that the resource is actually smaller than the offsets in the resource map
indicate because the file has not yet been compacted. If you want the exact size
of a resource on disk, either call &GetResourceSizeOnDisk or call &UpdateResFile
before calling GetMaxResourceSize.

    $size = GetMaxResourceSize($HANDLE);
    if ( defined $size ) {
        # proceed
    }

=cut
long
GetMaxResourceSize(theResource)
	Handle	theResource
	CLEANUP:
	ResErrorCheckRetval;

=item RsrcMapEntry HANDLE

B<Mac OS only.>

Given a handle to a resource, RsrcMapEntry returns the offset of the specified
resource's entry from the beginning of the resource map in memory. If it doesn't
find the resource entry, RsrcMapEntry returns 0, and the ResError function
returns the result code resNotFound. If you pass a handle whose value is NIL,
RsrcMapEntry returns arbitrary data. 

    $offset = RsrcMapEntry($HANDLE);
    if ( defined $offset ) {
        # proceed
    }

=cut

#ifndef MACOS_TRADITIONAL

long
RsrcMapEntry(theResource)
	Handle	theResource
	CODE:
	croak("Usage: Mac::Resourcecs::RsrcMapEntry unsupported in Carbon");

#else

long
RsrcMapEntry(theResource)
	Handle	theResource
	CLEANUP:
	ResErrorCheckRetvalNULL;

#endif

=item SetResAttrs HANDLE, ATTRS

Given a handle to a resource, SetResAttrs changes the resource attributes of the
resource to those specified in the attrs parameter. The SetResAttrs procedure
changes the information in the resource map in memory, not in the file on disk.
The resProtected attribute changes immediately. Other attribute changes take
effect the next time the specified resource is read into memory but are not made
permanent until the Resource Manager updates the resource fork.

    if ( SetResAttrs($HANDLE, $ATTRS) ) {
        # proceed
    } else {
        # error
    }

=cut
void
SetResAttrs(theResource, attrs)
	Handle	theResource
	short	attrs
	CLEANUP:
	ResErrorReturn;

=item ChangedResource HANDLE

Given a handle to a resource, the ChangedResource procedure sets the resChanged
attribute for that resource in the resource map in memory. If the resChanged
attribute for a resource has been set and your application calls &UpdateResFile or
quits, the Resource Manager writes the resource data for that resource (and for
all other resources whose resChanged attribute is set) and the entire resource
map to the resource fork of the corresponding file on disk. If the resChanged
attribute for a resource has been set and your application calls &WriteResource,
the Resource Manager writes only the resource data for that resource to disk.

    if ( ChangedResource($HANDLE) ) {
        # proceed
    } else {
        # error
    }

=cut
void
ChangedResource(theResource)
	Handle	theResource
	CLEANUP:
	ResErrorReturn;

=item RemoveResource HANDLE

Given a handle to a resource in the current resource file, RemoveResource removes
the resource entry (resource type, resource ID, resource name, if any, and
resource attributes) from the current resource file's resource map in memory. 

    if ( RemoveResource($HANDLE) ) {
        # proceed
    } else {
        # error
    }

=cut
void
RemoveResource(theResource)
	Handle	theResource
	CLEANUP:
	ResErrorReturn;

=item UpdateResFile RFD

Given the reference number of a file whose resource fork is open, UpdateResFile
performs three tasks. The first task is to change, add, or remove resource data
in the file's resource fork to match the resource map in memory. Changed resource
data for each resource is written only if that resource's resChanged bit has been
set by a successful call to &ChangedResource or &AddResource. The UpdateResFile
procedure calls the &WriteResource procedure to write changed or added resources
to the resource fork.

    if ( UpdateResFile($RFD) ) {
        # proceed
    } else {
        # error
    }

=cut
void
UpdateResFile(refNum)
	short	refNum
	CLEANUP:
	ResErrorReturn;

=item WriteResource HANDLE

Given a handle to a resource, WriteResource checks the resChanged attribute of
that resource. If the resChanged attribute is set to 1 (after a successful call
to the &ChangedResource or &AddResource procedure), WriteResource writes the
resource data in memory to the resource fork, then clears the resChanged
attribute in the resource's resource map in memory.

    if ( WriteResource($HANDLE) ) {
        # proceed
    } else {
        # error
    }

=cut
void
WriteResource(theResource)
	Handle	theResource
	CLEANUP:
	ResErrorReturn;

=item SetResPurge INSTALL

Specify TRUE in the install parameter to make the Memory Manager pass the handle
for a resource to the Resource Manager before purging the resource data to which
the handle points. The Resource Manager determines whether the handle points to a
resource in the application heap. It also checks if the resource's resChanged
attribute is set to 1. If these two conditions are met, the Resource Manager
calls the &WriteResource procedure to write the resource's resource data to the
resource fork before returning control to the Memory Manager.

Specify FALSE in the install parameter to restore the normal state, so that the
Memory Manager purges resource data when it needs to without calling the Resource
Manager.

    if ( SetResPurge(1) ) {
        # proceed
    } else {
        # error
    }

=cut
void
SetResPurge(install)
	Boolean	install
	CLEANUP:
	ResErrorReturn;

=item GetResFileAttrs RFD

Given a file reference number, the GetResFileAttrs function returns the
attributes of the file's resource fork. Specify 0 in $RFD to get
the attributes of the System file's resource fork. If there's no open resource
fork for the given file reference number, undef is returned.

    $rfa = GetResFileAttrs($RFD);
    if ( defined $rfa ) {
        # proceed
    }

=cut
short
GetResFileAttrs(refNum)
	short	refNum
	CLEANUP:
	ResErrorCheck;

=item SetResFileAttrs RFD, ATTRS

Given a file reference number, the SetResFileAttrs procedure sets the attributes
of the file's resource fork to those specified in the attrs parameter. If the
refNum parameter is 0, it represents the System file's resource fork. However,
you shouldn't change the attributes of the System file's resource fork. If
there's no resource fork with the given reference number, SetResFileAttrs does
nothing, and the ResError function returns the result code noErr.

    if ( SetResFileAttrs($RFD, $ATTRS) ) {
        # proceed
    } else {
        # error
    }

=cut
void
SetResFileAttrs(refNum, attrs)
	short	refNum
	short	attrs
	CLEANUP:
	ResErrorReturn;

=item RGetResource TYPE, ID

B<Mac OS only.>

The RGetResource function searches the resource maps in memory for the resource
specified by the parameters $TYPE and $ID. The resource maps in memory, which
represent all open resource forks, are arranged as a linked list. The
RGetResource function first uses GetResource to search this list. The GetResource
function starts with the current resource file and progresses through the list in
order (that is, in reverse chronological order in which the resource forks were
opened) until it finds the resource's entry in one of the resource maps. If
GetResource doesn't find the specified resource in its search of the resource
maps of open resource forks (which includes the System file's resource fork),
RGetResource sets the global variable RomMapInsert to TRUE, then calls
GetResource again. In response, GetResource performs the same search, but this
time it looks in the resource map of the ROM-resident resources before searching
the resource map of the System file. 

    $handle = RGetResource("DITL", 6042);
    if ( defined $handle ) {
        # proceed
    }

=cut

#ifndef MACOS_TRADITIONAL

Handle
RGetResource(theType, theID)
	OSType	theType
	short	theID
	CODE:
	croak("Usage: Mac::Resourcecs::RGetResource unsupported in Carbon");

#else

Handle
RGetResource(theType, theID)
	OSType	theType
	short	theID
	CLEANUP:
	ResErrorCheckRetvalNULL;

#endif

=item FSpOpenResFile SPEC, PERMISSION

The FSpOpenResFile function opens the resource fork of the file identified by the
spec parameter. It also makes this file the current resource file.

    $sp = FSpOpenResFile($SPEC);
    if ( defined $sp ) {
        # proceed
    }

In addition to opening the resource fork for the file with the specified name,
FSpOpenResFile lets you specify in the permission parameter the read/write permission
of the resource fork the first time it is opened.

=cut
short
FSpOpenResFile(spec, permission)
	FSSpec	&spec
	SInt8	permission
	CLEANUP:
	ResErrorCheckRetval;

=item FSOpenResourceFile REF, FORKNAME, PERMISSION

B<Mac OS X only.>

The FSOpenResourceFile function is like FSpOpenResFile, except that it can open
a resource file using the data fork or resource fork.  $REF is the
path to the resource file.  $FORKNAME is
"rsrc" for a resource fork; else the data fork will be used.  It also makes this
file the current resource file.

=cut
short
FSOpenResourceFile(ref, forkName, permissions)
	FSRef		&ref
	char *		forkName
	SInt8		permissions
	CODE:
	{
#ifdef MACOS_TRADITIONAL
	croak("Usage: Mac::Resources::FSOpenResourceFile unsupported in Mac OS");
#else
		SInt16			refNum;
		HFSUniStr255		forkNameU;

		if (strEQ(forkName, "rsrc"))
			FSGetResourceForkName(&forkNameU);
		else
			FSGetDataForkName(&forkNameU);

		gMacPerl_OSErr = FSOpenResourceFile(&ref,
			forkNameU.length, forkNameU.unicode,
			permissions, &refNum
		);

		if (!gMacPerl_OSErr)
			RETVAL = refNum;
		else
			RETVAL = 0;
#endif
	}
	OUTPUT:
	RETVAL

=item FSpCreateResFile SPEC, CREATOR, FILETYPE, SCRIPTTAG

The FSpCreateResFile procedure creates an empty resource fork for a file with the
specified $FILETYPE, $CREATOR, and $SCRIPTTAG in the location and with the name
designated by the spec parameter. (An empty resource fork contains no resource
data but does include a resource map.) 

    if ( FSpCreateResFile($SPEC, $CREATOR, $FILETYPE, $SCRIPTTAG) ) {
        # proceed
    } else {
        # error
    }

=cut
void
FSpCreateResFile(spec, creator, fileType, scriptTag)
	FSSpec		&spec
	OSType		creator
	OSType		fileType
	SInt8			scriptTag
	CLEANUP:
	ResErrorReturn;


=item FSCreateResourceFile PARENTREF, FILENAME, FORKNAME

B<Mac OS X only.>

The FSCreateResourceFile procedure is like FSpCreateResFile, except that it can
create a resource file in the data fork or resource fork.  $PARENTREF is the
oath of the directory where the new $FILENAME will be located.  $FORKNAME is
"rsrc" for a resource fork; else the data fork will be used.

=cut
void
FSCreateResourceFile(parentRef, name, forkName)
	FSRef		&parentRef
	Str255		name
	char *		forkName
	CODE:
	{
#ifdef MACOS_TRADITIONAL
	croak("Usage: Mac::Resources::FSCreateResourceFile unsupported in Mac OS");
#else
		HFSUniStr255		forkNameU;
		UnicodeMappingPtr	iUnicodeMapping = malloc(sizeof(UnicodeMapping));
		TextToUnicodeInfo	oTextToUnicodeInfo;
		UniChar *		uName = malloc(sizeof(UniChar) * sizeof(Str255));
		UniCharCount		uNameLength;

		iUnicodeMapping->unicodeEncoding = kTextEncodingUnicodeDefault;
		iUnicodeMapping->otherEncoding   = kTextEncodingISOLatin1;
		iUnicodeMapping->mappingVersion  = kUnicodeUseLatestMapping;

		CreateTextToUnicodeInfo(iUnicodeMapping, &oTextToUnicodeInfo);
		ConvertFromPStringToUnicode(
			oTextToUnicodeInfo, name, sizeof(UniChar) * sizeof(Str255),
			&uNameLength, uName
		);

		if (strEQ(forkName, "rsrc"))
			FSGetResourceForkName(&forkNameU);
		else
			FSGetDataForkName(&forkNameU);

		gMacPerl_OSErr = FSCreateResourceFile(&parentRef,
			(uNameLength / sizeof(UniChar)), uName,
			NULL, NULL,
			forkNameU.length, forkNameU.unicode,
			NULL, NULL
		);

		free(uName);
		free(iUnicodeMapping);
	}
#endif
	CLEANUP:
	ResErrorReturn;

=item ReadPartialResource HANDLE, OFFSET, BYTECOUNT

The ReadPartialResource procedure reads the resource subsection identified by the
theResource, offset, and count parameters.

    $data = ReadPartialResource($rsrc, 2000, 256);

=cut
SV *
ReadPartialResource(theResource, offset, count)
	Handle	theResource
	long	offset
	long	count
	CODE:
	RETVAL = newSV(count);
	ReadPartialResource(theResource, offset, SvPV_nolen(RETVAL), count);
	ResErrorCheck;
	OUTPUT:
	RETVAL

=item WritePartialResource HANDLE, OFFSET, DATA

The WritePartialResource procedure writes the data specified by DATA 
to the resource subsection identified by the HANDLE and OFFSET parameters.

    if ( WritePartialResource($HANDLE, $OFFSET, $DATA) ) {
        # proceed
    } else {
        # error
    }

=cut
void
WritePartialResource(theResource, offset, data)
	Handle	theResource
	long	offset
	SV *	data
	CODE: 
	{
		STRLEN	count;
		void *	buffer = SvPV(data, count);
		WritePartialResource(theResource, offset, buffer, count);
		ResErrorReturn;
	}

=item SetResourceSize HANDLE, SIZE

Given a handle to a resource, SetResourceSize sets the size field of the
specified resource on disk without writing the resource data. You can change the
size of any resource, regardless of the amount of memory you have available.

    if ( SetResource($HANDLE, $SIZE) ) {
        # proceed
    } else {
        # error
    }

=cut
void
SetResourceSize(theResource, newSize)
	Handle	theResource
	long	newSize
	CLEANUP:
	ResErrorReturn;

=back

=cut