TweetFollow Us on Twitter

PPC Data Fork Tool
Volume Number:12
Issue Number:12
Column Tag:Toolbox Techniques

Leave the Data (Fork) Alone!

A developer utility to restructure fat/PowerPC applications

By Roger Smith

Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.

Warning!

This article may change your life forever. Okay, maybe that’s a bit dramatic, but hopefully by the time you finish reading it, you will have discarded all previous knowledge on how to structure fat binaries. The utility MoveData that we will examine shortly, grew out of a need to create a fat application which stored data in its data fork. It turns out that the default model of native applications storing code in the data fork, is merely a default. Apple designed the Power Macintosh runtime architecture with sufficient flexibility to allow you to locate code fragments just about anywhere you could imagine. Bottom line, MoveData might actually save you significant amounts of development effort!

Outline

There is a certain category of applications that allow a user to create self-running and self-contained documents. For example, a graphic artist might use a multimedia presentation program to create an informative self-running presentation to give to end users without the full package. A file compression program might create an archive that when run, automatically un-archives its contents to fill your hard drive. In addition to these documents being self-running, where appropriate, it should also be possible to re-open, edit and re-save them with a minimal amount of hassle. How many times have you just peeked inside a self-extracting archive and manually extracted 1 or 2 files without un-archiving the entire contents? It would be great if these self-running documents ran native on 68K and PPC machines.

Most applications create documents where the stored information is in the data fork of the files. These applications generally use a subset of the File Manager routines for manipulating this data. Under the 68K model, this approach lends itself easily to design a self-running document. In this instance, a stripped down version of your application checks on startup to see if its data fork is empty. If it is not [empty] it assumes that it is a self running document and proceeds to load and handle the data in the data fork. The function checkforSelfContained() (see Listing 4) shows how to do this, making use of some Process Manager routines to obtain an FSSpec for the current application. It then uses this FSSpec as a basis for the subsequent calls to the File Manager to open and process the “Data” in the data fork of the application.

Developing on Power Macintosh.

The above approach breaks under the default PowerPC model since the application would ultimately try to load itself as data, (recall that by default the code for a PowerPC application resides in the data fork). If your application were attempting to interpret sound data, it could lead to some rather interesting “industrial” music. The exercise of creating a top musical hit using this approach is left as an exercise to the readers. (Hint: start with a Microsoft application!) What is a developer supposed to do?

CFRG Resource

Apple defined ‘cfrg’ resource (code fragment), which was introduced with the Power Macintosh, as the key to understanding the MoveData utility. Using ResEdit to edit this resource is tedious at best, as you will have to roll your own template to handle a resource that contains fields that vary in size. Using Resorcerer™ makes editing and changing this resource a simple task.

.

Figure 1. Application resource list in Resourcer.

Open the ‘cfrg’ editor by double clicking on the ‘cfrg’ resource.

Figure 2. The ‘cfrg’ resource editor in Resourcer.

Normally the various fields are filled in at link time, and you need not worry about them. The two fields that form the heart of the MoveData utility are the usage field and where does fragment start. I have defined a C structure called codeFragRecord (located in the file DSGlobals.h) that mirrors this layout.


codeFragRecord
Listing 1. Structure definition to mimic the ‘cfrg’ layout illustrated in Figure 2.

typedef struct fragDescriptors
{
 long   CodeType;
 long   UpdateLevel;
 long   CurrentVersion;
 long   OldestDefVersion;
 long   AppStackSize;
 short  AppLibDirectory;
 Byte   TypeOfFrag;
 Byte   LocationOfFrag;
 long   OffsetToFrag;
 long   LengthOfFrag;
 long   Reserved1;
 long   Reserved2;
 Str255 Fragname;
}fragDescriptors;

typedef struct fragDescriptors fragDescriptors;

typedef fragDescriptors FragArray[1];

typedef struct codeFragRecord
{
 long   Reserved1;
 long   Reserved2;
 long   Version;
 long   Reserved3;
 long   Reserved4;
 long   Reserved5;
 long   Reserved6;
 long   NumberofFrags;
 FragArrayfragArray; // array[0..0] of fragDescriptors;       
}codeFragRecord;

typedef struct codeFragRecord *codeFragRecPtr, **codeFragRecHandle;

Problem Identified

Given the task of designing a fat application that stores its data in its own data fork, you could take one of the following approaches.

(1) Write additional code to handle the case of loading and saving documents. This code would need to calculate offsets to move the file’s mark to skip over the code fragment.

(2) Compile your PowerPC application as a code resource. Write additional code compiled in the 68K version of your application that checks the environment on startup. If running on a PowerPC, load and execute the PowerPC resource (often referred to as an accelerated resource).

(3) Not to write code, instead tell the Code Fragment Manager to look in a particular resource to find the code it should load and execute.

Going back to the ‘cfrg’ editor in Resorcerer™ for a moment, we see that the usage field allows us to pick one of three options for our code fragment. If generating an application, this field is set by your development environment to indicate that the fragment is an application. Internally, the code fragment manager uses this to determine how to prepare a particular fragment and load it into memory. Refer to Inside Macintosh, PowerPC System Software if you need additional information.

Figure 3. The usage field popup in the ‘cfrg’ resource.

More importantly the where does fragment start field allows you to change from the default location in the data fork.

Figure 4. The where does fragment start popup.

To indicate to the code fragment manager that it should load the code from a resource instead of the data fork, select the segmented resource option.

Figure 5. Change the location to point to a code resource.

Enter the resource type and ID.

Figure 6. Code fragment manager set to look
for PCOD resource with ID 0 on startup.

Cut and paste the code from the data fork into the resource type you specified. On a PowerPC your fat application will load and execute from a resource, and the data fork reverts to its historical role. (Note: ‘PCOD’ is an arbitrary resource type I chose, if you need to use a different resource type, change the appropriate define in the DSGlobals.h header file.)

General Notes

You may be thinking, if I can do all of this with Resorcerer™, why do I need another developer utility? I initially took this approach. However, while I was developing my fat application I ran into the situation where copying and pasting 1MB of code out of the data fork and into a new resource required me to set Resorcerer™’s preferred memory size to >10MB. This procedure is slow and tedious if part of a regular build cycle. Using the simple AppleScript I provide automates the entire build process and reduces any chance of user error.

Code Listing

All programs were developed using CodeWarrior 7 which ships with the latest universal headers (known as the 2.1 universal interfaces). If you are using a previous version of CodeWarrior, or a different development environment, you may have to do some tweaking. For example, the GetKeys interface changed from long to unsigned long in the 2.1 headers.

There are two applications that accompany this article. The MoveData utility uses the excellent DropShell framework by Marshall Clow, Leonard Rosenthol, and Stephan Somogyi. DropShell is available on the CW7 CD and on most on-line services. Refer to its documentation for more information. To use MoveData, drag the application you wish to alter over its icon, (or select it via the Open option under the File menu). MoveData will move the PowerPC code from the data fork into a code resource, and update the ‘cfrg’ resource to point to the correct location. Should you wish to reverse the operation, hold down the option key when you drop the application onto the MoveData icon. It copies the PowerPC code from the resource back to the data fork.

The Demo program is a simple program that illustrates the technique of creating a self-running fat binary that reads and writes data from its data fork. After you build and run the program for the first time, it will prompt you to locate a text file, which it will copy into its data fork. On subsequent invocations of the demo program, it will read and display the contents of the data fork, then write the contents back to the data fork of the application reversed.

UpdateCFRG
Listing 2: DSUserProcs.c
// Routine to update the ‘cfrg’ resource. Pass in the updated information and it will 
// update the ‘cfrg’ resource in the file specified by resRef. The Code fragment 
// manager checks for this resource first on startup if running on a PowerPC. 

static  OSErr UpdateCFRG(short resRef,
 Byte fragmentType,
 Byte fragmentLocation,
 long fragmentOffset,
 long   fragmentLength)
 {
 codeFragRecHandle cfrgHndl;
 codeFragRecPtr  cfrgRecPtr;
 
 OSErr  theError = -1;
 
 cfrgHndl = (codeFragRecHandle) Get1Resource(‘cfrg’,0);
 
 if (cfrgHndl != NULL)
 {
 HLock((Handle) cfrgHndl);
 (**cfrgHndl).fragArray[0].TypeOfFrag = fragmentType;
 (**cfrgHndl).fragArray[0].LocationOfFrag 
 = fragmentLocation;
 
 (**cfrgHndl).fragArray[0].OffsetToFrag= fragmentOffset;
 (**cfrgHndl).fragArray[0].LengthOfFrag= fragmentLength;
 
 HUnlock((Handle) cfrgHndl);
 ChangedResource((Handle) cfrgHndl);
 UpdateResFile(resRef);
 ReleaseResource((Handle) cfrgHndl);
 return noErr;

 }
 return theError;
}


ProcessItem
Listing 3: DSUserProcs.c
// This routine gets called for each item (in our case a Fat binary) that is dropped on the
// MoveData utility. We will process and update the ‘cfrg’ resource as appropriate. Notice // the extensive 
error checking as there are several stages where things could go wrong.

static OSErr ProcessItem(FSSpecPtr myFSSPtr)
{
 OSErr  err = noErr;
 short  refNum;
 short  resRef;
 long logEOF;
 long count;
 Handle POWER_PC_CODE;
 short  resultCode;
 short  itemHit;
 
// If the option key is held down when an application is dropped onto MoveData, it will 
// reverse the process, i.e., move the PowerPC code from a resource back into the data fork.

 if (gReverseOperation)
 {
 return(ReverseProcessItem(myFSSPtr)); 
 }
 
 err = FSpOpenDF(myFSSPtr, fsRdWrPerm, &refNum);         

 if (err == noErr) 
 {
 resRef = FSpOpenResFile(myFSSPtr,fsRdWrPerm); 
 if (resRef != -1) 
 {
 err = GetEOF(refNum,&logEOF);      // Check for PPC code
 if (logEOF == 0)
 {
 itemHit = Alert(kNoDataFork,nil);
 }
 else
 {
 if (logEOF < kMaxResourceSize)  
 { 
 POWER_PC_CODE = Get1Resource(kPowerPCCode,kPowerPCID);
 if (POWER_PC_CODE != NULL) // Check for existing resource
 {
 RemoveResource(POWER_PC_CODE);  
 UpdateResFile(resRef); 
 }
 
 POWER_PC_CODE = NewHandle(logEOF);
 
 if (POWER_PC_CODE == NULL)
 POWER_PC_CODE = TempNewHandle(logEOF,&resultCode);      
 
 if (POWER_PC_CODE != NULL) { 
 count = logEOF;
 err = FSRead(refNum,&count,*POWER_PC_CODE);
 
 AddResource(POWER_PC_CODE,
 kPowerPCCode,
 kPowerPCID,
 ”\pPPC Code”);
 WriteResource(POWER_PC_CODE);
 UpdateResFile(resRef);
 ReleaseResource(POWER_PC_CODE);
 err = SetEOF(refNum,0);  // set the data fork to 0;
 err = UpdateCFRG (resRef, kUsageIsApplication,                
 kFragmentInResource,
 kPowerPCCode,kPowerPCID);
 }
 else
 itemHit = Alert(kMemErrorID,NULL);
 }
 else
 itemHit = Alert(kTooBigID,NULL);  
  }
 }
 err = FSClose(refNum);
 }
 else
 itemHit = Alert(kDataForkError,NULL);
 
 return(err);
}

checkforSelfContained
Listing 4: Demo.c
// Checks if this is a self running document, load and handle it if necessary.

OSErr checkforSelfContained(short *vRefNumToSearch)
{

 OSErr  theError;
 ProcessSerialNumber theCurrentProcess;
 ProcessInfoRec  theInfo;
 long   fileLength;
 short  refNum = 0;
 MenuHandle theMenu;

 theInfo.processName = NULL;
 theInfo.processInfoLength = sizeof(ProcessInfoRec);
 theInfo.processAppSpec = &gApplicationProcessInfo;
 
 theCurrentProcess.highLongOfPSN = 0;
 theCurrentProcess.lowLongOfPSN = kCurrentProcess; 
 
 theError = GetProcessInformation
 (&theCurrentProcess,&theInfo);
 if (theError != noErr)
 return theError;
 
 theError = FSpOpenDF(&gApplicationProcessInfo,
 fsRdWrPerm, &refNum);

 if (theError == noErr)
  theError = GetEOF(refNum, &fileLength);

 if (fileLength != 0)
 {
 theMenu = GetMHandle(FILEMENU);
 EnableItem(theMenu,clearDataFork);
 theError = processFile(&gApplicationProcessInfo,refNum,       
 fileLength);
 
 if (!theError)
 reverseFile(refNum);
 }
 else
 {
 theError = appendTextFileToApp(refNum);
 }

 theError = FSClose(refNum);

 *vRefNumToSearch = refNum;

 return theError;
}

The best way to build the Demo program is to run the Build (Fat) Demo CW7 script. If you run the PPC project immediately after building it, the program will attempt to reverse itself, and on subsequent attempts it will fail (self-destruction). Note: You will need to edit the path in the script to get it to run on your machine.

The echoed script is here for your convenience.

Build (Fat) Demo
Listing 5:
// Simple Apple Script to coordinate the building a fat binary using the MoveData Utility.

set PATHNAME to “HD:DeskTop Folder:MacTech:”
set MOVEDATAFOLDER to PATHNAME & “MoveDataƒ”



with timeout of 60000 seconds
 tell application “CodeWarrior IDE 1.3.1”
 activate
 open {PATHNAME & “Demo68K.µ”}
 Make Project
 Close Project
 
 open {PATHNAME & “DemoPPC.µ”}
 Add Files PATHNAME & “Demo68K” To Segment 1
 Make Project
 Remove Files PATHNAME & “Demo68K”
 quit
 
 end tell
 
 tell application “Finder”
 activate
 select file “Demo (Fat)” of folder PATHNAME
 open selection using file “MoveData” 
 of folder MOVEDATAFOLDER
 end tell
 
end timeout

Caveats

One of the side effects of this approach is that the Finder information window for your application will not reflect that it is a PowerPC application. This is because the Virtual Memory Manager on Power Macs will only map your application into chunks that can be paged in an out, if the code resides in the data fork. By the time Copland rolls around, hopefully this issue will be moot, and the Finder will provide a better mechanism for determining if an application contains native code. With virtual memory turned on (and depending on the size of your PowerPC executable), you may notice faster application startup times since none of the virtual memory magic will apply to your application.

If you are using Jasik’s the Debugger, your debugging strategy is unaffected as the Debugger will still kick in once you launch your application. You could have several self-running documents all built using the same run time module (with different information in the data fork). Then the Debugger will kick in, provided that you name the document and system files appropriately.

Figure 7. Finder information for a PowerPC application.

Figure 8. Finder information for a PowerPC application processed using the MoveData utility.

What other usage does this technique invite? I started thinking about this one night while driving home, and it seemed like an interesting way of storing optimized versions of your application under one umbrella (i.e., self configuring software that ran at maximum speed on 601, 603 or 604 processors). It also gives the authors of virus protection programs another potential threat to consider, as this technique gives new meaning to the term Trojan program.

The Verdict

I hope the technique of moving program code out of the Data Fork and into a resource will prove useful in your own development projects. Drop me an e-mail message if you use this technique, or have any comments on this approach.

Credits

The author wishes to thank several people who contributed code to help make this article possible. In particular, I would like to thank Matthew Xavier Mora at Apple DTS for supplying the Pascal source for the original version of MoveData. I would also like to thank Lucien Dupont in the Newton Systems Group for offering his support and comments, and finally to Peter Lau (no relation to Raymond) for his suggestions.

 
AAPL
$98.38
Apple Inc.
+0.71
MSFT
$44.30
Microsoft Corpora
-0.21
GOOG
$590.83
Google Inc.
+1.81

MacTech Search:
Community Search:

Software Updates via MacUpdate

Bartender 1.2.20 - Organize your menu ba...
Bartender lets you organize your menu bar apps. Features: Lets you tidy your menu bar apps how you want. See your menu bar apps when you want. Hide the apps you need to run, but do not need to... Read more
TotalFinder 1.6.2 - Adds tabs, hotkeys,...
TotalFinder is a universally acclaimed navigational companion for your Mac. Enhance your Mac's Finder with features so smart and convenient, you won't believe you ever lived without them. Tab-based... Read more
Vienna 3.0.0 RC 2 :be5265e: - RSS and At...
Vienna is a freeware and Open-Source RSS/Atom newsreader with article storage and management via a SQLite database, written in Objective-C and Cocoa, for the OS X operating system. It provides... Read more
VLC Media Player 2.1.5 - Popular multime...
VLC Media Player is a highly portable multimedia player for various audio and video formats (MPEG-1, MPEG-2, MPEG-4, DivX, MP3, OGG, ...) as well as DVDs, VCDs, and various streaming protocols. It... Read more
Default Folder X 4.6.7 - Enhances Open a...
Default Folder X attaches a toolbar to the right side of the Open and Save dialogs in any OS X-native application. The toolbar gives you fast access to various folders and commands. You just click... Read more
TinkerTool 5.3 - Expanded preference set...
TinkerTool is an application that gives you access to additional preference settings Apple has built into Mac OS X. This allows to activate hidden features in the operating system and in some of the... Read more
Audio Hijack Pro 2.11.0 - Record and enh...
Audio Hijack Pro drastically changes the way you use audio on your computer, giving you the freedom to listen to audio when you want and how you want. Record and enhance any audio with Audio Hijack... Read more
Intermission 1.1.1 - Pause and rewind li...
Intermission allows you to pause and rewind live audio from any application on your Mac. Intermission will buffer up to 3 hours of audio, allowing users to skip through any assortment of audio... Read more
Autopano Giga 3.6 - Stitch multiple imag...
Autopano Giga allows you to stitch 2, 20, or 2,000 images. Version 3.0 integrates impressive new features that will definitely make you adopt Autopano Pro or Autopano Giga: Choose between 9... Read more
Airfoil 4.8.7 - Send audio from any app...
Airfoil allows you to send any audio to AirPort Express units, Apple TVs, and even other Macs and PCs, all in sync! It's your audio - everywhere. With Airfoil you can take audio from any... Read more

Latest Forum Discussions

See All

Marvel Contest of Champions Announced at...
Marvel Contest of Champions Announced at Comic-Con Posted by Jennifer Allen on July 28th, 2014 [ permalink ] Announced over the weekend at San Diego Comic-Con was the fairly exciting looking Marvel Contest of Champions. | Read more »
Teenage Mutant Ninja Turtles Review
Teenage Mutant Ninja Turtles Review By Jennifer Allen on July 28th, 2014 Our Rating: :: DULL SWIPINGUniversal App - Designed for iPhone and iPad The pizza power is weak when it comes to this Teenage Mutant Ninja Turtles game.   | Read more »
Exploration Focused Puzzle Game Beatbudd...
Exploration Focused Puzzle Game Beatbuddy Set to Make Transition from PC to iOS this September Posted by Jennifer Allen on July 28th, 2014 [ permalink ] | Read more »
PlanetHD
PlanetHD By Nadia Oxford on July 28th, 2014 Our Rating: :: SPACE MADNESSUniversal App - Designed for iPhone and iPad PlanetHD will keep players busy for a while, though its unpredictable physics are a handful to deal with.   | Read more »
This Week at 148Apps: July 21-25, 2014
Another Week of Expert App Reviews   At 148Apps, we help you sort through the great ocean of apps to find the ones we think you’ll like and the ones you’ll need. Our top picks become Editor’s Choice, our stamp of approval for apps with that little... | Read more »
Reddme for iPhone - The Reddit Client (...
Reddme for iPhone - The Reddit Client 1.0 Device: iOS iPhone Category: News Price: $.99, Version: 1.0 (iTunes) Description: Reddme for iPhone is an iOS 7-optimized Reddit client that offers a refreshing new way to experience Reddit... | Read more »
Jacob Jones and the Bigfoot Mystery : Ep...
Jacob Jones and the Bigfoot Mystery : Episode 2 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: Jacob Jones is back in Episode 2 of one of Apples 'Best of 2013' games and an App Store... | Read more »
New Trailer For Outcast Odyssey, A New K...
New Trailer For Outcast Odyssey, A New Kind of Card Battler Posted by Jennifer Allen on July 25th, 2014 [ permalink ] Out this Fall is a new kind of card battle game: Outcast Odyssey. | Read more »
Hay Day – Tip, Tricks, Strategies, and C...
Recently got into Supercell’s other huge hit, Hay Day and could do with some advice on what to do? We’ve got you covered with some helpful trips and tricks to bear in mind! Ticking Along One of the key things to keep in mind while building up that... | Read more »
Monster Head Review
Monster Head Review By Nadia Oxford on July 25th, 2014 Our Rating: :: FEEDING TIMEUniversal App - Designed for iPhone and iPad Racking up a high score with Monster Head is trickier than it first appears. The appeal wears out fairly... | Read more »

Price Scanner via MacPrices.net

13-inch 2.5GHz MacBook Pro on sale for $1099,...
Best Buy has the 13″ 2.5GHz MacBook Pro available for $1099.99 on their online store. Choose free shipping or free instant local store pickup (if available). Their price is $100 off MSRP. Price is... Read more
Roundup of Apple refurbished MacBook Pros, th...
The Apple Store has Apple Certified Refurbished 13″ and 15″ MacBook Pros available for up to $400 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free. Their prices... Read more
Record Mac Shipments In Q2/14 Confound Analys...
A Seeking Alpha Trefis commentary notes that Apple’s fiscal Q3 2014 results released July 22, beat market predictions on earnings, although revenues were slightly lower than anticipated. Apple’s Mac’... Read more
Intel To Launch Core M Silicon For Use In Not...
Digitimes’ Monica Chen and Joseph Tsai, report that Intel will launch 14nm-based Core M series processors specifically for use in fanless notebook/tablet 2-in-1 models in Q4 2014, with many models to... Read more
Apple’s 2014 Back to School promotion: $100 g...
 Apple’s 2014 Back to School promotion includes a free $100 App Store Gift Card with the purchase of any new Mac (Mac mini excluded), or a $50 Gift Card with the purchase of an iPad or iPhone,... Read more
iMacs on sale for $150 off MSRP, $250 off for...
Best Buy has iMacs on sale for up to $160 off MSRP for a limited time. Choose free home shipping or free instant local store pickup (if available). Prices are valid for online orders only, in-store... Read more
Mac minis on sale for $100 off MSRP, starting...
Best Buy has Mac minis on sale for $100 off MSRP. Choose free shipping or free instant local store pickup. Prices are for online orders only, in-store prices may vary: 2.5GHz Mac mini: $499.99 2.3GHz... Read more
Global Tablet Market Grows 11% in Q2/14 Notwi...
Worldwide tablet sales grew 11.0 percent year over year in the second quarter of 2014, with shipments reaching 49.3 million units according to preliminary data from the International Data Corporation... Read more
New iPhone 6 Models to Have Staggered Release...
Digitimes’ Cage Chao and Steve Shen report that according to unnamed sources in Apple’s upstream iPhone supply chain, the new 5.5-inch iPhone will be released several months later than the new 4.7-... Read more
New iOS App Helps People Feel Good About thei...
Mobile shoppers looking for big savings at their favorite stores can turn to the Goodshop app, a new iOS app with the latest coupons and deals at more than 5,000 online stores. In addition to being a... Read more

Jobs Board

*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
Sr. Product Leader, *Apple* Store Apps - Ap...
**Job Summary** Imagine what you could do here. At Apple , great ideas have a way of becoming great products, services, and customer experiences very quickly. Bring Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
WW Sales Program Manager, *Apple* Online St...
**Job Summary** Imagine what you could do here. At Apple , great ideas have a way of becoming great products, services, and customer experiences very quickly. Bring Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.