ftp.nice.ch/pub/next/graphics/convertors/Convert_MacPaint.NIHS.bs.tar.gz#/Convert_MacPaint/Source/Extractors/extractor.c

This is extractor.c in view mode; [Download] [Up]

/***********************************************************************\
Extract {PICT|FONT}, applications to extract Mac resources to separate files
Copyright (C) 1993 David John Burrowes

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

The author, David John Burrowes, can be reached at:
	davidjohn@kira.net.netcom.com
	David John Burrowes
	1926 Ivy #10
	San Mateo, CA 94403-1367
\***********************************************************************/

/*
	This is a 'quick hack' of aprogram.  It's goal is real
	simple: Allow me to view PICT files without having to
	make use of a Draw type program.  the theory being that
	this way I'll be using the mac's internal pict display
	engine natively, and am more apt to get accurate ideas
	of how things should look.
	Because this is just a quick hack for my own use, this
	will not deal gracefully with error conditions.  It's
	expected that one will hang and crash occasionally
	when using this program.
	Tough cookies.
	=)
*/

#define EXTRACTOR_MENU_ID 128
#define	FILE_MENU	129

#include <Types.h>
#include <Windows.h>
#include <QuickDraw.h>
#include <Fonts.h>
#include <Menus.h>
#include <Packages.h>
#include <Memory.h>
#include <Desk.h>
#include <OSEvents.h>
#include <OSUtils.h>
#include <ToolUtils.h>

#include <stdio.h>
#include <string.h>
#include <strings.h>		// for p2cstr and the reverse
#include <Resources.h>
#include <Errors.h>
#include <files.h>

typedef	enum ErrorType
{
	NoError,
	BadError,
	NoResourcesFound

} ErrorType;

//
//
//
static Boolean QuitFlag = false;

static int	storedCount = 0;

//
//
//
AnnounceError(char* theText)
{
	ParamText((Str255)theText, "\p", "\p", "\p");
	StopAlert(128, NULL);
	return 0;
}


#if defined(DEBUG)
#define	DEBUGMESSAGE(theText) {AnnounceError(theText);}
#else
#define	DEBUGMESSAGE(theText) {}
#endif

////////////////////////////////////////////////////////////////////////
//	Routine:	FileExists
//	Input:	a file name and a reference number
//	Output:	True, if the file exists.  False, otherwise.
//	Purpose:	This takes a file name and ref number, and checks to see if it exists.
//				It does this in what must be a pretty inefficient way, but my sleep
//				fogged eyes see no better in the high level routines, and a glance at the
//				low level revealed nothing (but 'twas only a glance).  This asks for the
//				Finder information about the file. Naturally, if the file exists, we don't
//				get an error when we do this.  =)
////////////////////////////////////////////////////////////////////////
Boolean FileExists (char* fullName, short refNum)
{
	OSErr theError;
	FInfo junk;
	
	theError = GetFInfo(fullName, refNum, &junk);
	
	if (theError == fnfErr)	// Any other error means the file exists, or something else is bad 
		return false;
	else return true;
}

////////////////////////////////////////////////////////////////////////
//	Routine:	MainGoodFileName
//	Input:	a file name and a possible extension, a count of files processed, a refnum and dest name
//	Output:	A pointer to the file name, modified.
//	Purpose:	Given a file name and an extension, this puts them together.
//				Note: if root+extension > the max file name size (31 chars),
//				this removes characters from the root so they will fit.
//				This is more usefull for the batch processoing of a directory than
//				anything.  Note that if the file rootextension exists already, this
//				will propose the name root1extension, and this will repeat as often
//				as necessary to generate a unique name
//	Bugs:	Actually, after 30,000 attempts, it gives up and returns the name.
//				So, if someone has foo2.uue to foo30000.uue in their directory, bad
//				things might happen.  I figure if they've gone through the effort of
//				creating thirty thousand 'identical' files, they can deal with the consequences. =(.
////////////////////////////////////////////////////////////////////////
char *ConstructFileName (char* rootFileName, char* extension, unsigned int count, int refNum)
{
	unsigned int		numFiles = 1;
	int 	rootLength;
	int		totalLength;
	int		extensionLength;
	int		numLength;
	int		maxFileNameLength = 31;
	int		lengthDifference;
	char*	stringNumber	= NewPtr(20);
	Str255	scratch;
	char	*fullName	= NewPtr(256);

	if (count > 999)
		count = 0;
	//
	//	If the root+count+extension combination is larger than 31 characters,
	//	truncate root so extension will fit
	//
	rootLength = strlen(rootFileName);
	extensionLength = strlen(extension);
	totalLength = rootLength + 3 + extensionLength;
	lengthDifference = (maxFileNameLength - totalLength);
	if (lengthDifference < 0)
	{
		strncpy(scratch, rootFileName, rootLength+lengthDifference);	// Subtract the differentce from the rootlength
		scratch[rootLength+lengthDifference] = 0;
	}
	else
	{
		strcpy(scratch, rootFileName);
	}
	DEBUGMESSAGE("\pSprintf-ing");
	sprintf(fullName, "%s%0.3u%s", scratch, count, extension);
	c2pstr(fullName);

	//
	//	Now, check to see if the proposed file name is already in use.  If so,
	//	create a new file name with a number stuck between the root and the
	//	extension. Check if this name exists, and repeat if necessary.
	//
	while ((FileExists(fullName, refNum) == true) && (numFiles < 30000))
	{
		numFiles ++;	
		sprintf(stringNumber, "#%u", numFiles);
		numLength = strlen(stringNumber);
		//
		//	add the number to the name of the file (replacing chars)
		//
		totalLength = rootLength+3+numLength+extensionLength;
		//
		//	make room for the number in case root+extension doesn't leave enough room for it
		//
		lengthDifference = (maxFileNameLength - totalLength);
		if (lengthDifference < 0)
		{
			strncpy(scratch, rootFileName, rootLength+lengthDifference);
			scratch[rootLength+lengthDifference] = 0;
		}
		else
			strcpy(scratch, rootFileName);
		sprintf(fullName, "%s%0.3u%s%s", scratch, count, stringNumber, extension);
		c2pstr(fullName);
	}
	return fullName;
}





/*======================================================================
	function:	ExtractResourcesIn
	Input:		the name of the mac paint file
	Output:		none
	Descript:		Given a file name and a type, copy all the resources of that type out to separate
				files
\*======================================================================*/
ErrorType ExtractResourcesIn(char*	filename, ResType  resourceType)
{
	short		refNum;
	short		result;
	short		homeRefNum;
	short		rsrcCount = storedCount;
	short		index;
	short		headerindex;
	short		volrefnum	= 0;
	short		fileNum;
	short		resID;
	char*		sourceName;
	char*		pasName	= NULL;
	long		rsrcSize;
	int			numRsrc;
	long		theSize;
	Ptr			tempHeader;
	Handle		resource;
	ResType		theResType;
	Str255		resName;
	ErrorType	status		= NoError;
	
	#if defined(DEBUG)
		char*		DebugString = NewPtr(256);
	#endif

//	DEBUGMESSAGE(filename);
	if (strncmp(filename, "\006System", 7) == 0)
		result = 0;
	else
		result = OpenResFile(filename);
	if (result == -1)
	{
		AnnounceError("\pUnable to open that file!");
		status = BadError;
	}
	else
	{
//		DEBUGMESSAGE("\pno error");
		refNum = result;
		SetResLoad(false);
		numRsrc= CountResources(resourceType);
		if (numRsrc > 0)
		{
			for (index = 1; index <= numRsrc; index++)
			{
				resource = GetIndResource(resourceType, index);
				//
				//	If this resource isn't in the specified file, but in another in the lookup path,
				//	then skip it.  Additionally, don't process the resource if it has no length.
				//
				homeRefNum = HomeResFile(resource);
				rsrcSize = SizeResource(resource);
				if ((homeRefNum == refNum) && (rsrcSize != 0))
				{
					rsrcCount++;
					GetResInfo(resource, &resID, &theResType, resName);
					SetResLoad(true);
					LoadResource(resource);
//					DEBUGMESSAGE("\pLoaded the resource");
					if (resName[0] != 0)
					{
						sourceName = NewPtr(resName[0]+1);
						strncpy(sourceName, &resName[1], resName[0]);
						sourceName[resName[0]] = 0;
					}
					else
					{
						sourceName = NewPtr(filename[0]+1);
						strncpy(sourceName, &filename[1], filename[0]);
						sourceName[filename[0]] = 0;
					}

					//
					//	Ignoring the error codes!!  way bad.
					//
					if (resourceType == 'PICT')
					{
						pasName = ConstructFileName(sourceName, ".PICT", rsrcCount, volrefnum);
						Create(pasName, volrefnum, 'MDRW', 'PICT');
					}
					else
					{
						pasName = ConstructFileName(sourceName, ".FONT", rsrcCount, volrefnum);
						Create(pasName, volrefnum, 'ExRS', 'BIN!');
					}
					result = FSOpen(pasName, volrefnum, &fileNum);
					if (result != noErr)
					{
						AnnounceError("\pUnable to open the destination file!");
						status = BadError;
					}
					else
					{
						if (resourceType == 'PICT')
						{
							//
							//	Write out a leading 512 byte header for pict files only
							//
							tempHeader = NewPtr(512);
							for (headerindex = 0; headerindex < 512; headerindex+=16)
								strcpy((char*)&tempHeader[index], "ExtractPICT V1.0");
							theSize = 512;
							FSWrite(fileNum, &theSize, tempHeader);
							DisposPtr(tempHeader);
						}
						FSWrite(fileNum, &rsrcSize, *resource);
						FSClose(fileNum);
					}
					ReleaseResource(resource);
				}
				if (pasName != NULL)
					DisposPtr(pasName);
				pasName = NULL;
			}		
		}
		SetResLoad(true);	// in case it wasn't already
		if (refNum!= 0)
			CloseResFile(refNum);
	}

	storedCount = rsrcCount;
	if ((rsrcCount == 0) && (status == NoError))
		status = NoResourcesFound;
	#if defined(DEBUG)
		DisposPtr(DebugString);
	#endif
	return status;	// what about status
}





char*	GetSourceFile()
{
	Point	where;
	SFTypeList	myBogusList;
	SFReply	reply;
	Rect		badRect;
	char*	newName	= NULL;

	badRect.top = 0;
	badRect.left = 0;
	badRect.right = 255;
	badRect.bottom = 255;
	
	where.h = 10;
	where.v = 10;
	
	SFGetFile(where, "\pGet a file", NULL, -1, &myBogusList, NULL, &reply);

	if (reply.good == true)
	{
		SetVol(NULL, reply.vRefNum);
		newName = NewPtr(65);
		//
		//	Copying AS pascal string.
		//
		strncpy(newName, &(reply.fName) , 1+(reply.fName)[0]);
	}
	else
		newName = NULL;
	
	return (char*) newName;
}




void DoMenuStuff(long  results)
{
	long int	menuid, menuitem;
	char*	theName;
	CursHandle	myCursor;
	ErrorType	status 	= NoError;
	Boolean			foundSome;

	menuid = HiWord(results);
	menuitem = LoWord(results);
	if (menuid == FILE_MENU) 
	{
		if (menuitem == 3)
			QuitFlag = true;	// Setting a global
		else if (menuitem == 1)
		{
			theName = GetSourceFile();
			if (theName != NULL)
			{
				myCursor = GetCursor(watchCursor);
				SetCursor(*myCursor);
				status = NoError;
				storedCount = 0;
				#if defined(FONT)
					foundSome = false;
					status = ExtractResourcesIn(theName, 'FONT');
					if (status == NoError)
						foundSome = true;
					status = ExtractResourcesIn(theName, 'NFNT');
					if ((foundSome == true) && (status == NoResourcesFound))
						status = NoError;
				#else
					status =  ExtractResourcesIn(theName, 'PICT');
				#endif
				SetCursor(&qd.arrow);
				if (status == NoError)
					AnnounceError("\pOne or more files were written");
				else if (status == NoResourcesFound)
					AnnounceError("\pNothing was there to be extracted.");
				else
					AnnounceError("\pSome error occurred while processing!");
	
				DisposPtr(theName);
			}
		}
	}
	HiliteMenu(0);
}


////
//
//	The main, of course.
//
////
main()
{
	WindowPtr	tempWindow;
	EventRecord	theEvent;
	Handle		myMenuBar;
	long int	results;
	long int	location;
	GrafPtr		savePort;
	WindowPtr 	myWindow;
	TEHandle 	myTextField;
	int			TEXTNumChars;
	Handle		TEXTHandle;
	Rect		boundsRect;
	char*		dumbString;

	//
	//	Initthe things we need
	//
	InitGraf((Ptr) &qd.thePort);
	InitFonts();
	InitWindows();
	InitMenus();
	TEInit();
	InitDialogs(nil);
	InitCursor();
	
	//
	//	Setup
	//
	FlushEvents(everyEvent, 0);
	myMenuBar = GetNewMBar(EXTRACTOR_MENU_ID);
	SetMenuBar (myMenuBar);
	DisposHandle(myMenuBar);
	DrawMenuBar();

	SetRect(&boundsRect, 10, 40, 300, 210);
	myWindow = NewWindow(nil, &boundsRect, "\pAbout this app", true,
		4, (WindowPtr) -1, false, 0);
	QuitFlag = false;
	GetPort(&savePort);
	SetPort((GrafPtr) myWindow);
	SetRect(&boundsRect, 0, 0, 290, 170);
	TextSize(9);
	myTextField = TENew(&boundsRect, &boundsRect);
	SetPort((GrafPtr) savePort);



	#if defined(FONT)
		TEXTHandle = GetResource ('TEXT', 128);
	#else
		TEXTHandle = GetResource ('TEXT', 129);
	#endif
	
	TEXTNumChars = SizeResource(TEXTHandle) -1;
	HLock(TEXTHandle);
	TEInsert((Ptr)(*TEXTHandle), TEXTNumChars, myTextField);
	HUnlock(TEXTHandle);
	
	TESetSelect(32767, 32767, myTextField);
	TECalText(myTextField);
	
	//
	//	I later do a OpenResFile(), and a sprintf() after it.
	//	On my plus, this caused sprintf to crash, unless I had called
	//	it before the openres file (which is why this is there).  it didn't
	//	happen on the quadra at work.  All i can figure is that there's a bug
	//	here related to openresfile which keeps the seg loader from finding the
	//	code for sprintf later...
	//
	dumbString = NewPtr(100);
	sprintf(dumbString, "Stuuupid %d", 45);
	DisposPtr(dumbString);

	while (QuitFlag == false)
	{
		if (GetNextEvent(everyEvent, &theEvent) != true)
			SystemTask();
		else
		{
			switch (theEvent.what)
			{
				case keyDown :
					results = MenuKey((theEvent.message & charCodeMask));
					DoMenuStuff(results);
					break;
				case mouseDown :
					location = FindWindow(theEvent.where, &tempWindow);
					switch (location)
					{
						case 1:
							results = MenuSelect(theEvent.where);
							DoMenuStuff(results);
							break;
						case 4 : // in drag
							boundsRect.top = 0;
							boundsRect.left = 0;
							boundsRect.right = 512;
							boundsRect.bottom = 340;	// hardcoded and GROSSS bounds rectangle
							DragWindow( myWindow, theEvent.where, &boundsRect);
							break;
					}
					break;
				case updateEvt :
					BeginUpdate(myWindow);
					GetPort(&savePort);
					SetPort((GrafPtr) myWindow);
					TEUpdate(&((*myTextField)->viewRect), myTextField);
					SetPort(savePort);
					EndUpdate(myWindow);
					break;
				case	 activateEvt:
					if ((theEvent.modifiers && activeFlag) != 0)
						TEActivate (myTextField);
					else
						TEDeactivate(myTextField);
					break;
			}
		}
	}
	TEDispose(myTextField);
	CloseWindow(myWindow);
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.