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.