Initial check-in

This commit is contained in:
Nicholas Shanks 2001-10-19 19:41:13 +00:00
commit 49bbbf24fb
111 changed files with 16189 additions and 0 deletions

56
Bug List.text Normal file
View File

@ -0,0 +1,56 @@
ResKnife (Carbon & Classic):
* quit doesn't check for files to save (unverified, seems to check front window on 9.1 - don't know about others)
* files without a resource fork (inc. DF-based resource files) crash upon opening
* when saving a file, the temporary file cannot be deleted because it is open. I cannot find where I open it without closing it again.
* there's a crash on quit when there's an unsaved file open
temporary file handling is not very good. make it cooler.
should pass plug-ins a copy of the data handle, not the real thing
window header text non-existant
Revert Resource menu item not plugged in
should call memset() not BlockZero() on pre 8.5 systems (and include strings.h)
ResKnife (Carbon Only):
DataBrowser still doesn't draw the line at the top
choosing debugging menu items doesn't checkmark them
cannot drag items into/out of the data browser
ResKnife (Classic Only):
no column sorting
no GWorld support or clipRgn managment
headers don't toggle (Appearance)
no headers present (non-Appearance)
All Editors
* only have carbon support
Hex Editor:
closing winodow sometimes (rarely) causes crashes. cause unknown
Template Editor:
* some fields are not saved (elaborate)
* does not save repeating templates (I really need help with this)
* cannot handle Hxxx, P0xx, Cxxx
multi-line strings do not cause the text box to expand (anyone know how to make this work?)
PICT Editor:
Window doesn't have minimum size
Window is not resizable, has no scrollbars either
* denotes important bug (e.g. reproducable crasher, loss of data, et cetera)
I am currently working to eliminate these asterisked bugs, the others I'm not so bothered about yet.
I shall soon begin implementing an event mechanism for the editors which doesn't use CarbonEvents, allowing me to release the Classic build with some editors. (Fear not all you System 7.1-ers!)
please send bug reports (or better yet, contribute code) to resknife@nickshanks.com
One-time only bugs:
choosing save after editing a data fork caused only 2 of 14 resources to be saved.
clicking in the hex window does weird things to the selection. No selection was present, and the insertion point was not visible either. Typing subsequently deleted everything after where I typed, but no character appeared
ResKnife (Cocoa):
* Setting a type which is longer than four bytes on one resource will cause all resources below it to not be saved.
- (should require user to enter no more or less than four bytes, use formatter objects' isPartialStringValid: method)
* create new resource sheet not yet implemented
* no editors

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,178 @@
#include "ResKnife.h"
#ifndef _ResKnife_Application_
#define _ResKnife_Application_
/*!
@header Application
@discussion The Application.cpp file manages all critical workings to keep the program running, these include initalizing the environment, maintaining an event queue and parsing received events. It also manages the menubar.
*/
/***********************/
/* EVENT INITALIZATION */
/***********************/
/*!
@function InitToolbox
*/
OSStatus InitToolbox( void );
/*!
@function InitMenubar
*/
OSStatus InitMenubar( void );
/*!
@function InitAppleEvents
*/
OSStatus InitAppleEvents( void );
/*!
@function InitCarbonEvents
*/
OSStatus InitCarbonEvents( void );
/*!
@function InitGlobals
*/
OSStatus InitGlobals( void );
/*****************/
/* EVENT PARSING */
/*****************/
#if !TARGET_API_MAC_CARBON
/*!
@function ParseEvents
*/
OSStatus ParseEvents( EventRecord *event );
/*!
@function ParseDialogEvents
*/
pascal Boolean ParseDialogEvents( DialogPtr dialog, EventRecord *event, DialogItemIndex *itemHit );
/*!
@function ParseOSEvents
*/
OSStatus ParseOSEvents( EventRecord *event );
#endif
/*!
@function ParseAppleEvents
*/
pascal OSErr ParseAppleEvents( const AppleEvent *event, AppleEvent *reply, SInt32 refCon );
/******************/
/* EVENT HANDLING */
/******************/
#if !TARGET_API_MAC_CARBON
/*!
@function MouseDownEventOccoured
*/
OSStatus MouseDownEventOccoured( EventRecord *event );
/*!
@function MouseUpEventOccoured
*/
OSStatus MouseUpEventOccoured( EventRecord *event );
/*!
@function KeyDownEventOccoured
*/
OSStatus KeyDownEventOccoured( EventRecord *event );
/*!
@function KeyRepeatEventOccoured
*/
OSStatus KeyRepeatEventOccoured( EventRecord *event );
/*!
@function KeyUpEventOccoured
*/
OSStatus KeyUpEventOccoured( EventRecord *event );
/*!
@function UpdateEventOccoured
*/
OSStatus UpdateEventOccoured( EventRecord *event );
/*!
@function ActivateEventOccoured
*/
OSStatus ActivateEventOccoured( EventRecord *event );
/*!
@function IdleEvent
*/
OSStatus IdleEvent( void );
#endif
/*!
@function QuitResKnife
*/
void QuitResKnife( void );
/*****************/
/* MENU HANDLING */
/*****************/
#if TARGET_API_MAC_CARBON
/*!
@function CarbonEventUpdateMenus
*/
pascal OSStatus CarbonEventUpdateMenus( EventHandlerCallRef callRef, EventRef event, void *userData );
/*!
@function CarbonEventParseMenuSelection
*/
pascal OSStatus CarbonEventParseMenuSelection( EventHandlerCallRef callRef, EventRef event, void *userData );
/*!
@function DefaultIdleTimer
*/
pascal void DefaultIdleTimer( EventLoopTimerRef timer, void *data );
#else
/*!
@function UpdateMenus
*/
OSStatus UpdateMenus( WindowRef window );
/*!
@function ParseMenuSelection
*/
OSStatus ParseMenuSelection( UInt16 menu, UInt16 item );
#endif
/****************/
/* APPLE EVENTS */
/****************/
/*!
@function AppleEventSendSelf
*/
OSStatus AppleEventSendSelf( DescType eventClass, DescType eventID, AEDescList list );
/*!
@function GotRequiredParams
*/
Boolean GotRequiredParams( const AppleEvent *event );
/*!
@function AppleEventOpen
*/
OSStatus AppleEventOpen( const AppleEvent *event );
/*!
@function AppleEventPrint
*/
OSStatus AppleEventPrint( const AppleEvent *event );
/*********************/
/* NIBÑBASED WINDOWS */
/*********************/
/*!
@function ShowAboutBox
*/
OSStatus ShowAboutBox( void );
/*!
@function ShowPrefsWindow
*/
OSStatus ShowPrefsWindow( void );
/*!
@function PrefsTabEventHandler
*/
pascal OSStatus PrefsTabEventHandler( EventHandlerCallRef handlerRef, EventRef event, void* userData );
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,121 @@
#if defined(__MWERKS__)
#include <Resources.h>
#include <Sound.h>
#else
#include <Carbon/Carbon.h>
#endif
// enumerations
typedef enum
{
shpError = -1,
shpFinished = 0,
shpPaused = 1,
shpPlaying = 2
} SHPlayStat;
typedef enum
{
shrError = -1,
shrFinished = 0,
shrPaused = 1,
shrRecording = 2
} SHRecordStat;
// Sound Helper error codes
enum
{
kSHErrOutaChannels = 1, // No more output records are available
kSHErrBadRefNum, // Invalid reference number
kSHErrNonAsychDevice, // Input device can't handle asynchronous input
kSHErrNoRecording, // There's no recording to return
kSHErrNotRecording, // Not allowed because we're not recording
kSHErrAlreadyPaused, // Already paused
kSHErrAlreadyContinued // Already continued
};
// Contants used by the Asynchronous Sound Helper
const SInt16 kSHDefChannels = 4; // Default number of channels to preallocate
const SInt16 kSHCompleteSig = 'SH'; // Flag we use to know a "true" completion callback
const SInt32 kSHComplete = 'SHcp'; // Flag that a given channel has completed playback
const SInt16 kSHHeaderSlop = 100; // Extra bytes for the sound header when recording
const SInt16 kSHBaseNote = 60; // Middle C base note for new recordings
const SInt16 kSHSyncWaitTimeout = 60; // Ticks to sync-wait when killing the Helper
// Constants that should be in Sound.h but aren't
const SInt16 kSHNoSynth = 0; // Don't associate any synth to this channel
const SInt16 kSHNoInit = 0; // No specific initialization
const SInt8 kSHQuietNow = true; // Stop playing this sound immediately
const SInt8 kSHAsync = true; // Play asynchronously
const SInt8 kSHWait = false; // Wait for there to be enough room in the queue
// structures
typedef struct
{
SHRecordStat recordStatus; // Current record status
unsigned long totalRecordTime; // Total (maximum) record time in ms
unsigned long currentRecordTime; // Current recorded time in ms
short meterLevel; // 0..255, the current input level
} SHRecordStatusRec;
typedef struct
{
SndChannel channel; // Our sound channel
long refNum; // Our Helper ref num
Handle sound; // The sound we're playing
Fixed rate; // The rate at which a sampled sound is playing
char handleState; // The handle state to restore this handle to
Boolean inUse; // Tells whether this SHOutRec is in use
Boolean paused; // Tells whether this sound is currently paused
} SHOutRec, *SHOutPtr;
typedef struct
{
short numOutRecs; // The number of output records in outArray
SHOutRec *outArray; // Our pre-allocated output records
long nextRef; // The next available output reference number
} SHOutputVars;
typedef struct
{
long inRefNum; // Sound Input Manager's device refNum
SPB inPB; // The input parameter block
Handle inHandle; // The handle we're recording into
short headerLength; // The length of the sound's header
Boolean recording; // Tells whether we're actually recording
Boolean recordComplete; // Tells whether recording is complete
OSErr recordErr; // Error, if error terminated recording
short numChannels; // Number of channels for recording
short sampleSize; // Sample size for recording
Fixed sampleRate; // Sample rate for recording
OSType compType; // Compression type for recording
Boolean *appComplete; // Flag to caller that recording is done
Boolean paused; // Tells whether recording has been paused
} SHInputVars;
// Initialization, idle, and termination
pascal OSErr SHInitSoundHelper( Boolean *attnFlag, short numChannels );
pascal void SHIdle( void );
pascal void SHKillSoundHelper(void );
// Easy sound output
pascal OSErr SHPlayByID( short resID, long *refNum );
pascal OSErr SHPlayByHandle( Handle sound, long *refNum );
pascal OSErr SHPlayStop( long refNum );
pascal OSErr SHPlayStopAll( void );
// Advanced sound output
pascal OSErr SHPlayPause( long refNum );
pascal OSErr SHPlayContinue( long refNum );
pascal SHPlayStat SHPlayStatus( long refNum );
pascal OSErr SHGetChannel( long refNum, SndChannelPtr *channel );
// Easy sound input
pascal OSErr SHRecordStart( short maxK, OSType quality, Boolean *doneFlag );
pascal OSErr SHGetRecordedSound( Handle *theSound );
pascal OSErr SHRecordStop( void );
// Advanced sound input
pascal OSErr SHRecordPause( void );
pascal OSErr SHRecordContinue( void );
pascal OSErr SHRecordStatus( SHRecordStatusRec *recordStatus );

View File

@ -0,0 +1,634 @@
#include "DataBrowser.h"
#include "ResourceObject.h"
#include "InspectorWindow.h"
#include "Errors.h"
#include "Utility.h" // for TypeToCFString() et cetera
extern globals g;
#if TARGET_API_MAC_CARBON // CarbonLib 1.1+ or Public Beta only
/*** INITALISE DATA BROWSER ***/
OSStatus FileWindow::InitDataBrowser( void )
{
OSStatus error = noErr;
// get the db control - compatable with both CarbonLib and nib based versions
ControlID id = { kDataBrowserSignature, 0 };
GetControlByID( window, &id, &dataBrowser );
// set control ref to FileWindow
SetControlReference( dataBrowser, (long) this );
// turn off frame and focus
Boolean frame = false;
SetControlData( dataBrowser, kControlNoPart, kControlDataBrowserIncludesFrameAndFocusTag, sizeof(Boolean), &frame );
#if !USE_NIBS
// add empty columns
AddDataBrowserColumn( dataBrowser, kDBNameColumn, 0 ); // save column order into prefs file: Get/SetDataBrowserUserState()
AddDataBrowserColumn( dataBrowser, kDBTypeColumn, 1 );
AddDataBrowserColumn( dataBrowser, kDBIDColumn, 2 );
AddDataBrowserColumn( dataBrowser, kDBSizeColumn, 3 );
#endif
// add callbacks
DataBrowserCallbacks theCallbacks;
theCallbacks.version = kDataBrowserLatestCallbacks;
InitDataBrowserCallbacks( &theCallbacks );
theCallbacks.u.v1.itemDataCallback = NewDataBrowserItemDataUPP( DataBrowserItemData );
theCallbacks.u.v1.itemCompareCallback = NewDataBrowserItemCompareUPP( SortDataBrowser );
theCallbacks.u.v1.itemNotificationCallback = NewDataBrowserItemNotificationUPP( DataBrowserMessage );
theCallbacks.u.v1.addDragItemCallback = NewDataBrowserAddDragItemUPP( DataBrowserAddDragItem );
theCallbacks.u.v1.acceptDragCallback = NewDataBrowserAcceptDragUPP( DataBrowserAcceptDrag );
theCallbacks.u.v1.receiveDragCallback = NewDataBrowserReceiveDragUPP( DataBrowserReceiveDrag );
theCallbacks.u.v1.postProcessDragCallback = NewDataBrowserPostProcessDragUPP( DataBrowserPostProcessDrag );
SetDataBrowserCallbacks( dataBrowser, &theCallbacks );
// setup rest of browser, inc. adding all resources
DataBrowserItemID item;
for( UInt32 n = 1; n <= numResources; n++ )
{
item = n;
error = AddDataBrowserItems( dataBrowser, kDataBrowserNoItem, 1, &item, kDataBrowserItemNoProperty );
if( error ) DebugError( "\pError occoured adding resource to data browser." );
}
// add data fork if present
if( resourceMap->RepresentsDataFork() ) // requires data fork to be first in chain
{
item = kDataBrowserDataForkItem; // curently 0xFFFFFFFF
error = AddDataBrowserItems( dataBrowser, kDataBrowserNoItem, 1, &item, kDataBrowserItemNoProperty );
if( error ) DebugError( "\pError occoured adding data fork to data browser." );
}
SetDataBrowserSortProperty( dataBrowser, kDBTypeColumn );
SetDataBrowserTableViewRowHeight( dataBrowser, 16 +2 );
SetDataBrowserListViewDisclosureColumn( dataBrowser, kDBNameColumn, true );
// set up drag tracking
SetControlDragTrackingEnabled( dataBrowser, true );
return error;
}
/*** ADD DATA BROWSER COLUMN ***/
void AddDataBrowserColumn( ControlRef browser, DataBrowserPropertyID column, UInt16 position )
{
DataBrowserListViewColumnDesc columnDesc;
switch( column )
{
case kDataBrowserNameColumn:
columnDesc.propertyDesc.propertyID = kDataBrowserNameColumn;
columnDesc.propertyDesc.propertyType = kDataBrowserIconAndTextType;
columnDesc.propertyDesc.propertyFlags = kDataBrowserListViewDefaultColumnFlags | kDataBrowserListViewSelectionColumn;
columnDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
columnDesc.headerBtnDesc.minimumWidth = 150;
columnDesc.headerBtnDesc.maximumWidth = 250;
columnDesc.headerBtnDesc.titleOffset = 0;
columnDesc.headerBtnDesc.titleString = CFSTR("Resource Name"); // these should be resources for ease of localisation
columnDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing;
columnDesc.headerBtnDesc.btnFontStyle.font = kControlFontViewSystemFont;
columnDesc.headerBtnDesc.btnFontStyle.just = teFlushDefault;
columnDesc.headerBtnDesc.btnFontStyle.style = normal;
columnDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly;
break;
case kDataBrowserTypeColumn:
columnDesc.propertyDesc.propertyID = kDataBrowserTypeColumn;
columnDesc.propertyDesc.propertyType = kDataBrowserTextType;
columnDesc.propertyDesc.propertyFlags = kDataBrowserListViewDefaultColumnFlags;
columnDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
columnDesc.headerBtnDesc.minimumWidth = (g.systemVersion < kMacOSX)? 56:72;
columnDesc.headerBtnDesc.maximumWidth = columnDesc.headerBtnDesc.minimumWidth;
columnDesc.headerBtnDesc.titleOffset = 0;
columnDesc.headerBtnDesc.titleString = CFSTR("Type"); // these should be resources for ease of localisation
columnDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing;
columnDesc.headerBtnDesc.btnFontStyle.font = kControlFontViewSystemFont;
columnDesc.headerBtnDesc.btnFontStyle.just = teFlushRight;
columnDesc.headerBtnDesc.btnFontStyle.style = normal;
columnDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly;
break;
case kDataBrowserIDColumn:
columnDesc.propertyDesc.propertyID = kDataBrowserIDColumn;
columnDesc.propertyDesc.propertyType = kDataBrowserTextType;
columnDesc.propertyDesc.propertyFlags = kDataBrowserListViewDefaultColumnFlags;
columnDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
columnDesc.headerBtnDesc.minimumWidth = (g.systemVersion < kMacOSX)? 56:72;
columnDesc.headerBtnDesc.maximumWidth = columnDesc.headerBtnDesc.minimumWidth;
columnDesc.headerBtnDesc.titleOffset = 0;
columnDesc.headerBtnDesc.titleString = CFSTR("ID"); // these should be resources for ease of localisation
columnDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing;
columnDesc.headerBtnDesc.btnFontStyle.font = kControlFontViewSystemFont;
columnDesc.headerBtnDesc.btnFontStyle.just = teFlushRight;
columnDesc.headerBtnDesc.btnFontStyle.style = normal;
columnDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly;
break;
case kDataBrowserSizeColumn:
columnDesc.propertyDesc.propertyID = kDataBrowserSizeColumn;
columnDesc.propertyDesc.propertyType = kDataBrowserTextType;
columnDesc.propertyDesc.propertyFlags = kDataBrowserListViewDefaultColumnFlags;
columnDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
columnDesc.headerBtnDesc.minimumWidth = (g.systemVersion < kMacOSX)? 56:72;
columnDesc.headerBtnDesc.maximumWidth = columnDesc.headerBtnDesc.minimumWidth;
columnDesc.headerBtnDesc.titleOffset = 0;
columnDesc.headerBtnDesc.titleString = CFSTR("Size"); // these should be resources for ease of localisation
columnDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing;
columnDesc.headerBtnDesc.btnFontStyle.font = kControlFontViewSystemFont;
columnDesc.headerBtnDesc.btnFontStyle.just = teFlushRight;
columnDesc.headerBtnDesc.btnFontStyle.style = normal;
columnDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly;
break;
}
// create column and make respond to sorting
AddDataBrowserListViewColumn( browser, &columnDesc, position );
}
/*** HANDLE ITEM DATA I/O ***/
pascal OSStatus DataBrowserItemData( ControlRef browser, DataBrowserItemID itemID, DataBrowserPropertyID property, DataBrowserItemDataRef itemData, Boolean setValue )
{
#pragma unused( setValue )
OSStatus result = noErr;
if( setValue ) return result;
FileWindowPtr file = (FileWindowPtr) GetControlReference( browser );
ResourceObjectPtr resource = file->GetResource( itemID );
if( resource == null )
DebugError( "\pNull resource returned within DataBrowserItemData()" );
switch( property )
{
case kDataBrowserItemIsEditableProperty:
if( true ) // should item be editable? (i.e. is it a name, ID or type?)
SetDataBrowserItemDataBooleanValue( itemData, true );
break;
case kDataBrowserItemIsContainerProperty:
if( resource->Type() == kIconFamilyType )
SetDataBrowserItemDataBooleanValue( itemData, true );
break;
case kDBNameColumn:
{ // icon Ñ no resource for the icon!
IconRef theIcon = null;
#if !USE_NIBS
if( itemID != kDataBrowserDataForkItem )
{
Str255 iconString;
TypeToPString( resource->Type(), iconString );
IconFamilyHandle iconFamily = (IconFamilyHandle) Get1NamedResource( kIconFamilyType, iconString );
if( iconFamily )
{
RegisterIconRefFromIconFamily( kResKnifeCreator, resource->Type(), iconFamily, &theIcon );
ReleaseResource( (Handle) iconFamily ); // when dragging a rect this call caused other columns not to be displayed !?!
}
}
#endif
if( theIcon == null )
GetIconRef( kOnSystemDisk, kResKnifeCreator, kResourceFileType, &theIcon );
SetDataBrowserItemDataIcon( itemData, theIcon );
ReleaseIconRef( theIcon );
// resource name
CFStringRef nameCFStr;
if( itemID == kDataBrowserDataForkItem )
{
#if USE_NIBS // OS 9 version is not bundled at the present time
nameCFStr = CFBundleCopyLocalizedString( CFBundleGetMainBundle(), CFSTR("Data Fork"), null, null ); // bug: doesn't actually get localized string!
#else
nameCFStr = CFSTR("Data Fork");
#endif
SetDataBrowserItemDataRGBColor( itemData, &g.textColour );
}
else if( *resource->Name() == 0x00 )
{
#if USE_NIBS // OS 9 version is not bundled at the present time
nameCFStr = CFBundleCopyLocalizedString( CFBundleGetMainBundle(), CFSTR("Untitled Resource"), null, null ); // bug: doesn't actually get localized string!
#else
nameCFStr = CFSTR("Untitled Resource");
#endif
SetDataBrowserItemDataRGBColor( itemData, &g.textColour );
}
else nameCFStr = CFStringCreateWithPascalString( CFAllocatorGetDefault(), resource->Name(), kCFStringEncodingMacRoman );
SetDataBrowserItemDataText( itemData, nameCFStr );
#if USE_NIBS // OS 9 uses CFSTR()
CFRelease( nameCFStr );
#endif
} break;
case kDBTypeColumn:
{ // resource type
if( itemID == kDataBrowserDataForkItem )
{
SetDataBrowserItemDataText( itemData, CFSTR("-") );
}
else
{
CFStringRef typeString;
TypeToCFString( resource->Type(), &typeString );
SetDataBrowserItemDataText( itemData, typeString );
CFRelease( typeString );
}
} break;
case kDBIDColumn:
{ // resource ID
if( itemID == kDataBrowserDataForkItem )
{
SetDataBrowserItemDataText( itemData, CFSTR("-") );
}
else
{
SInt16 id = resource->ID();
Str255 idPString;
NumToString( id, (StringPtr) &idPString );
CFStringRef idString = CFStringCreateWithPascalString( CFAllocatorGetDefault(), idPString, kCFStringEncodingMacRoman );
SetDataBrowserItemDataText( itemData, idString );
CFRelease( idString );
}
} break;
case kDBSizeColumn:
{ SInt32 size = resource->Size();
UInt8 power = 0, remainder = 0;
Str255 sizePString, frac;
while( size >= 1024 && power <= 30 )
{
power += 10; // 10 == KB, 20 == MB, 30 == GB
remainder = (UInt8) ((size % 1024) / 102.4); // 102.4 gives one dp, 10.24 would give two dps, 1.024 would give three dps
size /= 1024;
}
NumToString( (long) size, (StringPtr) &sizePString );
NumToString( remainder, (StringPtr) &frac );
if( power ) // some division has occoured
{
if( sizePString[0] < 3 && remainder > 0 )
{
AppendPString( (unsigned char *) &sizePString, "\p." ); // bug: should be a comma on european systems
AppendPString( (unsigned char *) &sizePString, (unsigned char *) &frac );
}
if( power == 10 ) AppendPString( (unsigned char *) &sizePString, "\p KB" );
else if( power == 20 ) AppendPString( (unsigned char *) &sizePString, "\p MB" );
else if( power == 30 ) AppendPString( (unsigned char *) &sizePString, "\p GB" ); // everything bigger will be given in GB
}
CFStringRef sizeString = CFStringCreateWithPascalString( CFAllocatorGetDefault(), sizePString, kCFStringEncodingMacRoman );
SetDataBrowserItemDataText( itemData, sizeString );
CFRelease( sizeString );
} break;
default:
result = errDataBrowserPropertyNotSupported;
break;
}
return result;
}
/*** SORT DATA BROWSER ***/
pascal Boolean SortDataBrowser( ControlRef browser, DataBrowserItemID itemOne, DataBrowserItemID itemTwo, DataBrowserPropertyID sortProperty )
{
short result;
Str255 typeOne, typeTwo;
StringPtr nameOne, nameTwo;
FileWindowPtr file = (FileWindowPtr) GetControlReference( browser );
// send data fork to top regardless of property
if( itemOne == kDataBrowserDataForkItem ) return true;
if( itemTwo == kDataBrowserDataForkItem ) return false;
// validate data browser item IDs
if( itemOne <= kDataBrowserNoItem || itemOne > file->GetResourceCount() )
{
DebugError( "\psort item one was invalid" );
return false;
}
if( itemTwo <= kDataBrowserNoItem || itemTwo > file->GetResourceCount() )
{
DebugError( "\psort item two was invalid" );
return false;
}
// get resource corrisponding to item ID
ResourceObjectPtr resourceOne = file->GetResource( itemOne );
ResourceObjectPtr resourceTwo = file->GetResource( itemTwo );
if( resourceOne == null || resourceTwo == null )
DebugError( "\pNull resource returned within SortDataBrowser()" );
// sort resources according to property user has selected
switch( sortProperty )
{
case kDBNameColumn:
nameOne = resourceOne->Name();
nameTwo = resourceTwo->Name();
result = CompareString( nameOne, nameTwo, null );
return result < 0;
case kDBTypeColumn:
TypeToPString( resourceOne->Type(), typeOne );
TypeToPString( resourceTwo->Type(), typeTwo );
result = CompareString( typeOne, typeTwo, null );
return result < 0;
case kDBIDColumn:
return resourceOne->ID() < resourceTwo->ID();
case kDBSizeColumn:
return resourceOne->Size() < resourceTwo->Size();
case kDataBrowserItemNoProperty: // this is valid when first constructing the data browser
// DebugError( "\pkDataBrowserItemNoProperty passed to sort function" );
return false;
default:
DebugError( "\pInvalid sort property given" );
return false;
}
return false;
}
/*** DATA BROWSER MESSAGE ***/
pascal void DataBrowserMessage( ControlRef browser, DataBrowserItemID itemID, DataBrowserItemNotification message, DataBrowserItemDataRef itemData )
{
#pragma unused( itemID, itemData )
FileWindowPtr file = (FileWindowPtr) GetControlReference( browser );
switch( message )
{
case kDataBrowserItemDoubleClicked:
{ KeyMap theKeys;
Boolean shiftKeyDown = false,
optionKeyDown = false,
controlKeyDown = false;
GetKeys( theKeys );
if( theKeys[1] & (shiftKey >> shiftKeyBit) ) shiftKeyDown = true;
if( theKeys[1] & (optionKey >> shiftKeyBit) ) optionKeyDown = true;
if( theKeys[1] & (controlKey >> shiftKeyBit) ) controlKeyDown = true;
if( optionKeyDown ) file->OpenResource( itemID, kMenuCommandOpenHex );
else if( controlKeyDown ) file->OpenResource( itemID, kMenuCommandOpenTemplate );
else file->OpenResource( itemID, kMenuCommandOpenDefault );
} break;
case kDataBrowserItemSelected:
case kDataBrowserItemDeselected:
case kDataBrowserSelectionSetChanged:
// file->SetHeaderText();
if( g.inspector )
g.inspector->Update();
break;
case kDataBrowserEditStarted:
case kDataBrowserEditStopped:
case kDataBrowserItemAdded:
case kDataBrowserItemRemoved:
case kDataBrowserContainerOpened:
case kDataBrowserContainerClosing:
case kDataBrowserContainerClosed:
case kDataBrowserContainerSorting:
case kDataBrowserContainerSorted:
case kDataBrowserTargetChanged:
case kDataBrowserUserStateChanged:
break;
}
}
/*** ADD DRAG ITEM ***/
pascal Boolean DataBrowserAddDragItem( ControlRef browser, DragRef drag, DataBrowserItemID item, DragItemRef *itemRef )
{
#pragma unused( item )
// if drag already has phfs flavour, don't add another
UInt16 numFlavours;
CountDragItemFlavors( drag, *itemRef, &numFlavours );
if( numFlavours > 0 ) return true;
// add 'create file' callback
if( itemRef ) *itemRef = ItemReference( item );
FlavorFlags flags = flavorNotSaved;
DragSendDataUPP sendData = NewDragSendDataUPP( SendPromisedFile );
SetDragSendProc( drag, sendData, browser );
// setup imaginary file
PromiseHFSFlavor promisedFile;
promisedFile.fileType = kResourceFileType;
promisedFile.fileCreator = kResKnifeCreator;
promisedFile.fdFlags = null; // finder flags
promisedFile.promisedFlavor = kResourceTransferType;
// add phfs and TEXT flavours
AddDragItemFlavor( drag, *itemRef, flavorTypePromiseHFS, &promisedFile, sizeof(PromiseHFSFlavor), flags );
return true;
/* OSErr error = noErr;
DragReference theDragRef;
ItemReference theItemRef = 1;
// create the drag reference
NewDrag( &theDragRef );
if( MemError() ) return;
SetDragSendProc( theDragRef, sendProc, this );
RgnHandle dragRgn = NewRgn(),
subtractRgn = NewRgn();
// get region of dragged items, using translucent dragging where possible
Point dragOffset;
GWorldPtr imageGWorld = nil;
resData = GetResourceData( ownerWindow );
while( resData )
{
if( r.selected )
UnionRgn( r.nameIconRgn, dragRgn, dragRgn ); // add new region to rest of drag region
resData = r.next;
}
if( g.translucentDrag )
{
short resCounter = 0;
SetPt( &dragOffset, 0, kFileHeaderHeight );
resData = GetResourceData( ownerWindow );
while( !r.selected )
{
resCounter++;
resData = r.next;
}
error = CreateDragImage( resData, &imageGWorld );
if( !error )
{
// init mask region
RgnHandle maskRgn = NewRgn();
CopyRgn( r.nameIconRgn, maskRgn );
OffsetRgn( maskRgn, 0, -kFileLineHeight * resCounter );
// init rects
Rect sourceRect, destRect;
SetRect( &sourceRect, 0, 0, g.nameColumnWidth, kFileLineHeight );
SetRect( &destRect, 0, 0, g.nameColumnWidth, kFileLineHeight );
OffsetRect( &destRect, 0, kFileHeaderHeight );
// init GWorld
PixMapHandle imagePixMap = GetGWorldPixMap( imageGWorld );
DragImageFlags imageFlags = kDragStandardTranslucency | kDragRegionAndImage;
error = SetDragImage( theDragRef, imagePixMap, maskRgn, dragOffset, imageFlags );
CopyBits( &GrafPtr( imageGWorld )->portBits, &GrafPtr( ownerWindow )->portBits, &sourceRect, &destRect, srcCopy, maskRgn );
if( error ) SysBeep(0);
DisposeGWorld( imageGWorld );
DisposeRgn( maskRgn );
}
}
// subtract middles from icons
MakeGlobal( ownerWindow, NewPoint(), &globalMouse );
CopyRgn( dragRgn, subtractRgn ); // duplicate region
InsetRgn( subtractRgn, 2, 2 ); // inset it by 2 pixels
DiffRgn( dragRgn, subtractRgn, dragRgn ); // subtract subRgn from addRgn, save in nameIconRgn
OffsetRgn( dragRgn, globalMouse.h, globalMouse.v ); // change drag region to global coords
// add flavour data to drag
error = AddDragItemFlavor( theDragRef, theItemRef, flavorTypePromiseHFS, &theFile, sizeof(PromiseHFSFlavor), theFlags );
error = AddDragItemFlavor( theDragRef, theItemRef, kResType, nil, 0, theFlags );
// track the drag, then clean up
error = TrackDrag( theDragRef, theEvent, dragRgn );
if( theDragRef ) DisposeDrag( theDragRef );
if( subtractRgn ) DisposeRgn( subtractRgn );
if( dragRgn ) DisposeRgn( dragRgn );
return error == noErr; */
}
/*** ACCEPT DRAG ***/
pascal Boolean DataBrowserAcceptDrag( ControlRef browser, DragRef drag, DataBrowserItemID item )
{
#pragma unused( browser, drag, item )
/* OSStatus error = noErr;
Size size = null;
DragItemRef dragItem = 1;
UInt16 index, totalItems;
CountDragItems( theDrag, &totalItems );
for( index = 1; index <= totalItems; index++ )
{
GetDragItemReferenceNumber( theDrag, index, &dragItem );
error = GetFlavourDataSize( theDrag, dragItem, kDragFlavourTypeResource, &size );
// if( error ) return false;
if( !error ) index = totalItems; // stop when valid item is reached
}
return size >= sizeof(ResTransferDesc);
*/ return true;
}
/*** RECEIVE DRAG ***/
pascal Boolean DataBrowserReceiveDrag( ControlRef browser, DragRef drag, DataBrowserItemID item )
{
#pragma unused( browser, drag, item )
return true;
}
/*** POSTÐPROCESS DRAG ***/
pascal void DataBrowserPostProcessDrag( ControlRef browser, DragRef drag, OSStatus trackDragResult )
{
#pragma unused( browser, drag, trackDragResult )
}
/*** SEND PROMISED FILE ***/
pascal OSErr SendPromisedFile( FlavorType type, void *dragSendRefCon, ItemReference item, DragReference drag )
{
OSErr error = noErr;
ControlRef browser = (ControlRef) dragSendRefCon;
FSSpec fileSpec;
Str255 fileName;
short vRefNum;
long dirID;
if( type != flavorTypePromiseHFS ) return badDragFlavorErr;
// create file
GetIndString( fileName, kFileNameStrings, kStringNewDragFileName );
FindFolder( kOnSystemDisk, /*kTemporaryFolderType*/kDesktopFolderType, kCreateFolder, &vRefNum, &dirID );
FSMakeFSSpec( vRefNum, dirID, fileName, &fileSpec );
FSpCreateResFile( &fileSpec, kResKnifeCreator, kResourceFileType, smSystemScript );
// save resources into file
DragData clientData; // waiting for jim to add a ControlRef to DataBrowserItemUPP; bug: jim no longer works at Apple
clientData.browser = browser;
clientData.fileSpec = &fileSpec;
DataBrowserItemUPP callback = NewDataBrowserItemUPP( AddResourceToDragFile );
/* control, container, recurse, state, callback, clientData */
ForEachDataBrowserItem( browser, kDataBrowserNoItem, true, kDataBrowserItemIsSelected, callback, &clientData );
// save resources in file
/* ResourceObjectPtr resource = GetResourceData( file->window );
short refNum = FSpOpenResFile( &fileSpec, fsRdWrPerm );
UseResFile( refNum );
while( resData )
{
if( resource->Selected() )
AddResource( resource->Data(), resource->Type(), resource->ID(), resource->Name() );
resData = resource->Next();
}
CloseResFile( refNum );
UseResFile( g.appResFile );
*/
error = SetDragItemFlavorData( drag, item, type, &fileSpec, sizeof(FSSpec), 0 );
return error;
}
/*** ADD RESOURCE TO DRAG FILE ***/
pascal void AddResourceToDragFile( DataBrowserItemID item, DataBrowserItemState state, void *clientData )
{
#pragma unused( state )
// FSSpecPtr fileSpec = (FSSpecPtr) clientData;
WindowRef window = GetControlOwner( ((DragDataPtr) clientData)->browser );
FileWindowPtr file = (FileWindowPtr) GetWindowRefCon( window );
ResourceObjectPtr resource = file->GetResource( item );
// add resource to file
short oldFile = CurResFile();
short refNum = FSpOpenResFile( ((DragDataPtr) clientData)->fileSpec, fsRdWrPerm );
UseResFile( refNum );
AddResource( resource->Data(), resource->Type(), resource->ID(), resource->Name() );
if( ResError() == addResFailed )
{
DisplayError( "\pDrag Partially Failed", "\pCould not add a resource to file." );
}
else
{
SetResAttrs( resource->Data(), resource->Attributes() );
ChangedResource( resource->Data() );
// clean up & move on
DetachResource( resource->Data() );
}
CloseResFile( refNum );
UseResFile( oldFile );
}
#else
/*********************/
/* FAKE DATA BROWSER */
/*********************/
/*** CLEAR SELECTION ***/
OSStatus FileWindow::ClearSelection( void )
{
ResourceObjectPtr resource = resourceMap;
while( resource )
{
resource->Select( false );
resource = resource->Next();
}
return noErr;
}
#endif

View File

@ -0,0 +1,87 @@
#include "ResKnife.h"
#include "FileWindow.h"
#ifndef _ResKnife_DataBrowser_
#define _ResKnife_DataBrowser_
/*!
* @header DataBrowser
* @discussion Handles the databrowser control on post-CarbonLib systems, and mimics it on pre-CarbonLib machines.
*/
typedef struct
{
ControlRef browser;
FSSpecPtr fileSpec;
} DragData, *DragDataPtr;
/*!
* @enum DataBrowser Column IDs
* @discussion The data browser requires IDs for identifiying columns when adding data. These constants provide those IDs.
* @constant kDBNameColumn The name column, also include resource icon and disclosure triangle.
* @constant kDBTypeColumn The type column contains the four-byte resType of each resource.
* @constant kDBIDColumn The ID column contains 16-bit signed resource IDs
* @constant kDBSizeColumn The size column reports the size of each resource's data in bytes or multiples thereof.
*/
enum
{
kDBNameColumn = FOUR_CHAR_CODE('name'),
kDBTypeColumn = FOUR_CHAR_CODE('type'),
kDBIDColumn = FOUR_CHAR_CODE('id '),
kDBSizeColumn = FOUR_CHAR_CODE('size')
};
const DataBrowserItemID kDataBrowserDataForkItem = 0xFFFFFFFE; // bug in data browser preventts use of 0xFFFFFFFF
/*!
* @function AddDataBrowserColumn
* @discussion Adds columns to the data browser one at a time.
*/
void AddDataBrowserColumn( ControlRef browser, DataBrowserPropertyID column, UInt16 position );
/*!
* @function DataBrowserItemData
* @discussion DataBrowser callback.
*/
pascal OSStatus DataBrowserItemData( ControlRef browser, DataBrowserItemID itemID, DataBrowserPropertyID property, DataBrowserItemDataRef itemData, Boolean changeValue );
/*!
* @function SortDataBrowser
* @discussion DataBrowser callback.
*/
pascal Boolean SortDataBrowser( ControlRef browser, DataBrowserItemID itemOne, DataBrowserItemID itemTwo, DataBrowserPropertyID sortProperty );
/*!
* @function DataBrowserMessage
* @discussion DataBrowser callback.
*/
pascal void DataBrowserMessage( ControlRef browser, DataBrowserItemID itemID, DataBrowserItemNotification message, DataBrowserItemDataRef itemData );
/*!
* @function DataBrowserAddDragItem
* @discussion DataBrowser callback.
*/
pascal Boolean DataBrowserAddDragItem( ControlRef browser, DragRef drag, DataBrowserItemID item, DragItemRef *itemRef );
/*!
* @function DataBrowserAcceptDrag
* @discussion DataBrowser callback.
*/
pascal Boolean DataBrowserAcceptDrag( ControlRef browser, DragRef drag, DataBrowserItemID item );
/*!
* @function DataBrowserReceiveDrag
* @discussion DataBrowser callback.
*/
pascal Boolean DataBrowserReceiveDrag( ControlRef browser, DragRef drag, DataBrowserItemID item );
/*!
* @function DataBrowserPostProcessDrag
* @discussion DataBrowser callback.
*/
pascal void DataBrowserPostProcessDrag( ControlRef browser, DragRef drag, OSStatus trackDragResult );
/*!
* @function SendPromisedFile
* @discussion Creates the promised file and sends the FSSpec for it back.
*/
pascal OSErr SendPromisedFile( FlavorType theType, void *dragSendRefCon, ItemReference item, DragReference drag );
/*!
* @function AddResourceToDragFile
* @discussion Adds each resource to the file created by SendPromisedFile. Called once per resource.
*/
pascal void AddResourceToDragFile( DataBrowserItemID item, DataBrowserItemState state, void *clientData );
#endif

View File

@ -0,0 +1,57 @@
#include "EditorWindow.h"
#include "ResourceObject.h"
#include "Errors.h"
#include "Utility.h"
extern globals g;
/*** CREATOR ***/
EditorWindow::EditorWindow( FileWindowPtr ownerFile, ResourceObjectPtr targetResource, WindowRef inputWindow ) : PlugWindow( ownerFile )
{
OSStatus error = noErr;
// set default variables
window = inputWindow;
resource = targetResource;
// set up default window title
Str255 windowTitle, resTypeStr, resIDStr;
FSSpec spec = *ownerFile->GetFileSpec();
CopyPString( spec.name, windowTitle );
TypeToPString( resource->Type(), resTypeStr );
NumToString( resource->ID(), resIDStr );
AppendPString( windowTitle, "\p: " );
AppendPString( windowTitle, resTypeStr );
AppendPString( windowTitle, "\p " );
AppendPString( windowTitle, resIDStr );
if( *resource->Name() != 0x00 ) // resource has name
{
AppendPString( windowTitle, "\p, Ò" );
AppendPString( windowTitle, resource->Name() );
AppendPString( windowTitle, "\" );
}
// save EditorWindow class in window's refcon
SetWindowRefCon( window, (UInt32) this );
SetWindowKind( window, kEditorWindowKind );
SetWindowTitle( window, windowTitle );
}
#if !TARGET_API_MAC_CARBON
/*** CLOSE ***/
OSStatus EditorWindow::Close( void )
{
// bug: need to tell plug it is about to die.
CloseWindow( window );
delete this;
return noErr;
}
#endif
/*** RESOURCE ACCESSOR ***/
ResourceObjectPtr EditorWindow::Resource( void )
{
return resource;
}

View File

@ -0,0 +1,37 @@
#include "ResKnife.h"
#include "PlugWindow.h"
#include "ResourceObject.h"
#ifndef _ResKnife_EditorWindow_
#define _ResKnife_EditorWindow_
/*!
* @header EditorWindow
* @discussion A class specifically designed to maintain an external editor window.
*/
/*!
* @class EditorWindow
* @discussion A class specifically designed to maintain an external editor window.
*/
class EditorWindow : PlugWindow
{
private:
ResourceObjectPtr resource;
Boolean modified; // flag the editor sets when it modifies a resource (ie. it needs to be saved)
public:
/*!
* @function EditorWindow
* @discussion Constructor function.
*/
EditorWindow( FileWindowPtr ownerFile, ResourceObjectPtr targetResource, WindowRef inputWindow );
/*!
* @function Close
* @discussion Sends a close message to the plug, then closes the window.
*/
OSStatus Close( void );
ResourceObjectPtr Resource( void );
};
#endif

89
Carbon/Classes/Errors.cpp Normal file
View File

@ -0,0 +1,89 @@
#include "Errors.h"
#include "Application.h"
#include "Utility.h"
// import globals and prefs from Application.cpp
extern globals g;
extern prefs p;
/*** DISPLAY ANY ERROR ***/
OSStatus DisplayError( CFStringRef errorStr )
{
#pragma unused( errorStr )
return noErr;
}
/*** DISPLAY SIMPLE ERROR ***/
OSStatus DisplayError( ConstStr255Param errorStr )
{
return DisplayError( errorStr, "\p" );
}
/*** DISPLAY ERROR WITH EXPLANATION */
OSStatus DisplayError( UInt16 error, UInt16 explanation )
{
Str255 errorStr, explanationStr;
GetIndString( errorStr, kErrorStrings, error );
GetIndString( explanationStr, kErrorStrings, explanation );
return DisplayError( errorStr, explanationStr );
}
/*** DISPLAY ERROR WITH EXPLANATION */
OSStatus DisplayError( ConstStr255Param errorStr, ConstStr255Param explanationStr )
{
if( g.surpressErrors ) return noErr;
if( g.useAppearance )
{
SInt16 item;
AlertStdAlertParamRec params = {};
params.movable = true;
params.defaultButton = kAlertStdAlertOKButton;
params.position = kWindowDefaultPosition;
#if __profile__
ProfilerSetStatus( false );
#endif
SysBeep(0);
StandardAlert( kAlertStopAlert, errorStr, explanationStr, &params, &item );
#if __profile__
ProfilerSetStatus( true );
#endif
return item == kAlertStdAlertOKButton? noErr:paramErr;
}
else
{
ParamText( errorStr, explanationStr, "\p", "\p" );
ModalFilterUPP filter = null; // NewModalFilterUPP( ParseDialogEvents );
#if __profile__
ProfilerSetStatus( false );
#endif
SysBeep(0);
DialogItemIndex item = StopAlert( 128, filter );
#if __profile__
ProfilerSetStatus( true );
#endif
return item == kAlertStdAlertOKButton? noErr:paramErr;
}
}
/*** DISPLAY ERROR WITH EXPLANATION */
OSStatus DebugError( UInt16 error, OSStatus number )
{
Str255 errorStr;
GetIndString( errorStr, kDebugStrings, error );
return DebugError( errorStr, number );
}
/*** DISPLAY A DEBUGGING ERROR ***/
OSStatus DebugError( ConstStr255Param errorStr, OSStatus number )
{
OSStatus error = noErr;
if( g.debug )
{
Str255 message = "\pDebugging Error ID: ", numString = "\p";
NumToString( number, numString );
AppendPString( message, numString );
error = DisplayError( message, errorStr );
}
return error;
}

42
Carbon/Classes/Errors.h Normal file
View File

@ -0,0 +1,42 @@
#include "ResKnife.h"
#ifndef _ResKnife_Errors_
#define _ResKnife_Errors_
/*!
@header Errors
@discussion Contains all error display code for both ResKnife and it's plug-ins.
*/
/*!
@function DisplayError
@discussion Pass a CFStringRef and ResKnife will do noting at all. (yet :)
*/
OSStatus DisplayError( CFStringRef error );
/*!
@function DisplayError
@discussion Pass one pascal string and ResKnife will display a simple error message.
*/
OSStatus DisplayError( ConstStr255Param error );
/*!
@function DisplayError
@discussion Pass two string indecies within kErrorStrings, and they will be displayed as an error message.
*/
OSStatus DisplayError( UInt16 error, UInt16 explanation );
/*!
@function DisplayError
@discussion Pass two pascal strings and ResKnife will display a more refined error message.
*/
OSStatus DisplayError( ConstStr255Param error, ConstStr255Param explanation );
/*!
@function DebugError
@discussion Pass an index of a string with kDebugStrings and if debugging mode is on, ResKnife will display the message.
*/
OSStatus DebugError( UInt16 error, OSStatus number = noErr );
/*!
@function DebugError
@discussion Pass a pascal string and if debugging mode is on, ResKnife will display the message.
*/
OSStatus DebugError( ConstStr255Param errorStr, OSStatus number = noErr );
#endif

File diff suppressed because it is too large Load Diff

179
Carbon/Classes/FileWindow.h Normal file
View File

@ -0,0 +1,179 @@
#include "ResKnife.h"
#include "WindowObject.h"
#ifndef _ResKnife_FileWindow_
#define _ResKnife_FileWindow_
/*!
@header FileWindow
@discussion The bulk of the ResKnife code is concerned with the managment of this window. It is the essence of the program.
*/
/* Constants */
const UInt16 kDefaultHeaderHeight = 20;
const UInt16 kMinimumFileWindowWidth = 128;
const UInt16 kDefaultFileWindowWidth = 420;
const UInt16 kMinimumFileWindowHeight = 128 + kDefaultHeaderHeight;
const UInt16 kDefaultFileWindowHeight = 384 + kDefaultHeaderHeight;
const UInt16 kBevelButtonHeight = 20;
const UInt16 kFileWindowHeaderHeight = kDefaultHeaderHeight + kBevelButtonHeight;
const UInt16 kFileWindowRowHeight = 19;
const UInt16 kFileWindowTextHeight = kFileWindowRowHeight - 5;
const UInt16 kFileWindowMinimumNameColumnWidth = 150;
const UInt16 kFileWindowDefaultNameColumnWidth = 250;
const UInt16 kFileWindowTypeColumnWidth = 52;
const UInt16 kFileWindowIDColumnWidth = 52;
const UInt16 kFileWindowSizeColumnWidth = 52;
const UInt16 kFileWindowAttributesColumnWidth = 120;
const UInt16 kFileWindowSortColumnWidth = 16;
const UInt16 kFileWindowAllOtherColumnWidths = kFileWindowTypeColumnWidth + kFileWindowIDColumnWidth + kFileWindowSizeColumnWidth + kFileWindowAttributesColumnWidth +8; // excludes variable with name column
const UInt16 kFileWindowNameColumnTextOffset = 42; // start of text, actual column starts at zero
const UInt16 kFileWindowTypeColumnOffset = 0; // offset from end of name column
const UInt16 kFileWindowIDColumnOffset = kFileWindowTypeColumnOffset + kFileWindowTypeColumnWidth;
const UInt16 kFileWindowSizeColumnOffset = kFileWindowIDColumnOffset + kFileWindowIDColumnWidth;
const UInt16 kFileWindowAttributesColumnOffset = kFileWindowSizeColumnOffset + kFileWindowSizeColumnWidth;
const UInt32 kWindowPropertyDataBrowser = FOUR_CHAR_CODE('brow');
const UInt32 kHeaderSignature = FOUR_CHAR_CODE('head');
const UInt32 kLeftTextSignature = FOUR_CHAR_CODE('left');
const UInt32 kRightTextSignature = FOUR_CHAR_CODE('rght');
const UInt32 kDataBrowserSignature = FOUR_CHAR_CODE('brow');
const UInt32 kDataBrowserNameColumn = FOUR_CHAR_CODE('name');
const UInt32 kDataBrowserTypeColumn = FOUR_CHAR_CODE('type');
const UInt32 kDataBrowserIDColumn = FOUR_CHAR_CODE('id ');
const UInt32 kDataBrowserSizeColumn = FOUR_CHAR_CODE('size');
typedef enum
{
kSortName = 1,
kSortType,
kSortID,
kSortSize,
kSortAttrs
} SortOrder;
/*** FILE WINDOW CLASS ***/
class FileWindow : WindowObject
{
// file info
FSSpecPtr fileSpec; // user's copy
FSSpecPtr tempSpec; // my copy
Boolean fileExists; // existing file was opened or file has been saved at some point
Boolean fileDirty; // temp file ­ real file => save available
Boolean rfBased; // file's resource map came from it's resource fork
// resource info
UInt16 numTypes;
UInt32 numResources;
#if !TARGET_API_MAC_CARBON
UInt32 numSelected; // for fake data browser
#endif
Handle dataFork; // bug: what is this for?
ResourceObjectPtr resourceMap;
// controls
#if TARGET_API_MAC_CARBON
ControlRef dataBrowser; // header controls in WindowObject
#else // make a fake databrowser
SortOrder sortOrder; // the one which is actually selected
ControlRef sortName;
ControlRef sortType;
ControlRef sortID;
ControlRef sortSize;
ControlRef sortAttrs;
ControlRef sortDir;
SInt16 nameColumnWidth; // varies with window size, and needs to be signed
#endif
/* methods */
public:
FileWindow( FSSpecPtr spec = null );
virtual ~FileWindow( void );
// overridden inherited functions
/*!
* @function Window
* @discussion Accessor for the object&rsquo;s <tt>WindowRef</tt>.
*/
virtual WindowRef Window( void );
virtual OSStatus BoundsChanging( EventRef event );
virtual OSStatus BoundsChanged( EventRef event );
#if !TARGET_API_MAC_CARBON
virtual OSStatus Activate( Boolean active = true );
virtual OSStatus Update( RgnHandle region = null );
virtual OSStatus Click( Point mouse, EventModifiers modifiers );
// drawing
private:
virtual OSStatus UpdateScrollBars( void );
OSStatus DrawResourceIcon( ResourceObjectPtr resource, UInt16 line );
// fake data brwser
OSStatus ClearSelection( void );
#endif
// file manipulation
public:
OSStatus ReadResourceFork( void );
OSStatus ReadDataFork( OSStatus rfError );
OSStatus InitDataBrowser( void );
OSStatus SaveFile( FSSpecPtr saveSpec = null );
private:
/*!
@function ReadResourceMap
@discussion Requires the fork containing resources to be at the top of the resource chain
*/
OSStatus ReadResourceMap( void ); // fork-independent resource routines
OSStatus SaveResourceMap( void );
// carbon routines
public:
OSStatus Zoomed( EventRef event );
OSStatus SetIdealSize( EventRef event );
OSStatus DisplaySaveDialog( void );
OSStatus DisplayModelessAskSaveChangesDialog( void );
OSStatus DisplaySaveAsDialog( void );
OSStatus DisplayModelessPutFileDialog( void );
OSStatus DisplayRevertFileDialog( void );
OSStatus DisplayModelessAskDiscardChangesDialog( void );
OSStatus DisplayNewResourceDialog( void );
OSStatus DisplayNewResourceSheet( void );
// resource map processing
OSStatus CreateNewResource( ConstStr255Param name, ResType type, SInt16 resID, SInt16 attribs );
OSStatus OpenResource( DataBrowserItemID itemID, MenuCommand command );
private:
OSStatus DisposeResourceMap( void );
public:
// sound handlers
OSStatus PlaySound( DataBrowserItemID itemID );
// file accessors
FSSpecPtr GetFileSpec( void );
void SetFileSpec( FSSpecPtr spec );
Boolean IsFileDirty( void );
void SetFileDirty( Boolean dirty = true );
#if TARGET_API_MAC_CARBON
ControlRef GetDataBrowser( void );
#endif
// resource accessors
UInt32 GetResourceCount( ResType wanted = 0x00000000 );
ResourceObjectPtr GetResource( DataBrowserItemID itemID );
UInt8* GetResourceName( DataBrowserItemID itemID );
UInt32 GetResourceSize( DataBrowserItemID itemID );
ResType GetResourceType( DataBrowserItemID itemID );
SInt16 GetResourceID( DataBrowserItemID itemID );
SInt16 GetResourceAttributes( DataBrowserItemID itemID );
};
/* window event handler */
pascal void FileWindowScrollAction( ControlHandle control, SInt16 controlPart );
pascal OSStatus FileWindowEventHandler( EventHandlerCallRef callRef, EventRef event, void *userData );
pascal OSStatus FileWindowUpdateMenus( EventHandlerCallRef callRef, EventRef event, void *userData );
pascal OSStatus FileWindowParseMenuSelection( EventHandlerCallRef callRef, EventRef event, void *userData );
pascal OSStatus NewResourceEventHandler( EventHandlerCallRef callRef, EventRef event, void *userData );
#endif

860
Carbon/Classes/Files.cpp Normal file
View File

@ -0,0 +1,860 @@
#include "Files.h"
#include "Application.h"
#include "FileWindow.h"
#include "ResourceObject.h" // for saving inital resource data
#include "DataBrowser.h" // for kDataBrowserForkItem constant
#include "Utility.h"
#include "Errors.h"
extern globals g;
/* Convert an FSRef to an FSSpec:
FSGetCatalogInfo( &fsref, kFSCatInfoNone, null, null, &spec, null );
Get your application's FSSpec
FSSpec spec;
String name;
ProcessInfoRec info;
ProcessSerialNumber psn;
GetCurrentProcess( &psn );
info.processName = &name;
info.processAppSpec = &spec;
GetProcessInformation( psn, &info );
*/
/*** NAV OPEN FILE ***/
/*OSStatus NavOpenFile( void )
{
OSStatus error = noErr;
NavReplyRecord reply;
NavDialogOptions dialogOptions;
NavEventUPP eventProc = NewNavEventUPP( NavEventFilter );
NavPreviewUPP previewProc = NewNavPreviewUPP( NavPreviewFilter );
NavObjectFilterUPP filterProc = NewNavObjectFilterUPP( NavFileFilter );
// Initialize dialog options structure and set default values
NavGetDefaultDialogOptions( &dialogOptions );
dialogOptions.dialogOptionFlags = kNavNoTypePopup | kNavDontAutoTranslate | kNavDontAddTranslateItems | kNavAllowMultipleFiles | kNavAllowInvisibleFiles;
BlockMoveData( g.appName, dialogOptions.clientName, sizeof(Str255) );
// call the nav services routine
error = NavGetFile( null, &reply, &dialogOptions, eventProc, previewProc, filterProc, null, null );
DisposeNavEventUPP( eventProc );
DisposeNavPreviewUPP( previewProc );
DisposeNavObjectFilterUPP( filterProc );
if( reply.validRecord && error == noErr )
{
if( g.useAppleEvents )
error = AppleEventSendSelf( kCoreEventClass, kAEOpenDocuments, reply.selection );
#if !TARGET_API_MAC_CARBON
else
{
// open the list of item(s):
AEKeyword keyword;
DescType descType;
FSSpec fileSpec;
Size actualSize;
error = AEGetNthPtr( &(reply.selection), 1, typeFSS, &keyword, &descType, &fileSpec, sizeof(FSSpec), &actualSize );
if( !error ) // if sucessful, open & read the file
new FileWindow( &fileSpec );
*/ /* SInt32 count;
FSSpec fileSpec;
AEDesc resultDesc;
error = AECountItems( &(reply.selection), &count );
if( !error )
for( SInt32 n = 1; n <= count; n++ )
{
error = AEGetNthDesc( &(reply.selection), n, typeFSS, null, &resultDesc );
if( !error )
{
HLock( (Handle) resultDesc.dataHandle );
BlockMoveData( (void *) *resultDesc.dataHandle, &fileSpec, sizeof(FSSpec) );
new FileWindow( &fileSpec );
AEDisposeDesc( &resultDesc );
}
}
*/ /* }
#endif
// Always dispose of reply structure, resources, and descriptors
error = NavDisposeReply( &reply );
}
return error;
}
*/
#if !TARGET_API_MAC_CARBON
/*** OPEN FILE ***/
OSStatus OpenFile( short vRefNum, long dirID, ConstStr255Param fileName )
{
FSSpec fileSpec;
FSMakeFSSpec( vRefNum, dirID, fileName, &fileSpec );
new FileWindow( &fileSpec );
return noErr;
}
/*** DISPLAY STANDARD FILE OPEN DIALOG ***/
OSStatus DisplayStandardFileOpenDialog( void )
{
StandardFileReply theReply;
SFTypeList typeList = { 0x0L };
StandardGetFile( null, 0, typeList, &theReply );
if( theReply.sfGood ) new FileWindow( &theReply.sfFile );
return theReply.sfGood? noErr:userCanceledErr;
}
#endif
/*** OPEN A FILE DIALOG ***/
OSStatus DisplayOpenDialog( void )
{
OSStatus error = noErr;
NavReplyRecord reply;
NavDialogOptions dialogOptions;
NavEventUPP eventProc = NewNavEventUPP( NavEventFilter );
NavPreviewUPP previewProc = NewNavPreviewUPP( NavPreviewFilter );
NavObjectFilterUPP filterProc = NewNavObjectFilterUPP( NavFileFilter );
NavTypeListHandle typeList = null;
NavGetDefaultDialogOptions( &dialogOptions );
dialogOptions.dialogOptionFlags += kNavNoTypePopup;
GetIndString( dialogOptions.clientName, kFileNameStrings, kStringResKnifeName );
error = NavGetFile( null, &reply, &dialogOptions, eventProc, previewProc, filterProc, typeList, null);
if( reply.validRecord || !error )
{
AEKeyword keyword;
DescType descType;
FSSpec fileSpec;
Size actualSize;
error = AEGetNthPtr( &(reply.selection), 1, typeFSS, &keyword, &descType, &fileSpec, sizeof(FSSpec), &actualSize );
if( !error ) new FileWindow( &fileSpec ); // if sucessful, opens & reads the file
NavDisposeReply( &reply );
}
else error = userCanceledErr;
DisposeNavEventUPP( eventProc );
DisposeNavPreviewUPP( previewProc );
DisposeNavObjectFilterUPP( filterProc );
return error;
}
/*** DISPLAY MODELESS GET FILE DIALOG ***/
OSStatus DisplayModelessGetFileDialog( void )
{
OSStatus error;
NavEventUPP eventProc = NewNavEventUPP( ModelessGetFileHandler );
NavPreviewUPP previewProc = null;
NavObjectFilterUPP filterProc = null;
NavTypeListHandle typeList = null;
NavDialogCreationOptions options;
error = NavGetDefaultDialogCreationOptions( &options );
options.clientName = (CFStringRef) CFBundleGetValueForInfoDictionaryKey( CFBundleGetMainBundle(), kCFBundleNameKey );
NavDialogRef dialog;
error = NavCreateGetFileDialog( &options, typeList, eventProc, previewProc, filterProc, null, &dialog );
error = NavDialogRun( dialog );
if( error ) NavDialogDispose( dialog );
return error;
}
/*** SAVE FILE DIALOG ***/
OSStatus FileWindow::DisplaySaveDialog( void )
{
OSStatus error = noErr;
NavDialogOptions options;
NavEventUPP eventProc = NewNavEventUPP( NavEventFilter );
NavAskSaveChangesAction action = g.quitting? kNavSaveChangesQuittingApplication : kNavSaveChangesClosingDocument;
NavAskSaveChangesResult result;
NavGetDefaultDialogOptions( &options );
GetWindowTitle( window, options.savedFileName );
// GetIndString( options.clientName, kFileNameStrings, kStringAppName );
NavAskSaveChanges( &options, action, &result, eventProc, null );
switch( result )
{
case kNavAskSaveChangesSave:
if( fileExists ) error = SaveFile( null );
else error = DisplaySaveAsDialog();
break;
case kNavAskSaveChangesDontSave:
break;
case kNavAskSaveChangesCancel:
g.cancelQuit = true;
g.quitting = false; // bug: why can't I check for userCanceledErr instead?
error = userCanceledErr;
break;
}
DisposeNavEventUPP( eventProc );
return error;
}
/*** DISPLAY MODELESS SAVE DIALOG ***/
OSStatus FileWindow::DisplayModelessAskSaveChangesDialog( void )
{
OSStatus error;
NavEventUPP eventProc = NewNavEventUPP( ModelessAskSaveChangesHandler );
NavPreviewUPP previewProc = null;
NavObjectFilterUPP filterProc = null;
NavTypeListHandle typeList = null;
NavAskSaveChangesAction action = g.quitting? kNavSaveChangesQuittingApplication : kNavSaveChangesClosingDocument;
NavDialogCreationOptions options;
error = NavGetDefaultDialogCreationOptions( &options );
options.parentWindow = window;
options.modality = kWindowModalityWindowModal;
options.clientName = (CFStringRef) CFBundleGetValueForInfoDictionaryKey( CFBundleGetMainBundle(), kCFBundleNameKey ); // bug: are these two strings CFReleased? Should they be?
options.saveFileName = CFStringCreateWithPascalString( null, fileSpec->name, CFStringGetSystemEncoding()); // bug: see above
NavDialogRef dialog;
error = NavCreateAskSaveChangesDialog( &options, action, eventProc, this, &dialog );
error = NavDialogRun( dialog );
return error;
}
/*** SAVE AS DIALOG ***/
OSStatus FileWindow::DisplaySaveAsDialog( void )
{
OSStatus error = noErr;
NavReplyRecord reply;
NavDialogOptions dialogOptions;
NavEventUPP eventProc = NewNavEventUPP( NavEventFilter );
NavGetDefaultDialogOptions( &dialogOptions );
GetWindowTitle( window, dialogOptions.savedFileName );
GetIndString( dialogOptions.clientName, kFileNameStrings, kStringResKnifeName );
error = NavPutFile( null, &reply, &dialogOptions, eventProc, kResourceFileType, kResKnifeCreator, null );
if( reply.validRecord || !error )
{
AEKeyword keyword;
DescType descType;
FSSpec savedSpec;
Size actualSize;
// bug: does the next line only get the first selected file?
error = AEGetNthPtr( &(reply.selection), 1, typeFSS, &keyword, &descType, &savedSpec, sizeof(FSSpec), &actualSize );
if( !error )
{
if( reply.replacing ) error = FSpDelete( &savedSpec );
if( !error )
{
error = SaveFile( &savedSpec );
if ( !error )
error = NavCompleteSave( &reply, kNavTranslateInPlace );
}
else if( error == fBsyErr )
{
DisplayError( kStringUnknownError, kExplanationUnknownError ); // read error
}
}
NavDisposeReply( &reply );
}
else if( !error ) error = userCanceledErr;
DisposeNavEventUPP( eventProc );
return error;
}
/*** DISPLAY MODELESS PUT FILE DIALOG ***/
OSStatus FileWindow::DisplayModelessPutFileDialog( void )
{
OSStatus error;
NavEventUPP eventProc = NewNavEventUPP( ModelessPutFileHandler );
NavDialogCreationOptions options;
error = NavGetDefaultDialogCreationOptions( &options );
options.parentWindow = window;
options.modality = kWindowModalityWindowModal;
options.clientName = (CFStringRef) CFBundleGetValueForInfoDictionaryKey( CFBundleGetMainBundle(), kCFBundleNameKey );
options.saveFileName = CFStringCreateWithPascalString( null, fileSpec->name, CFStringGetSystemEncoding());
NavDialogRef dialog;
error = NavCreatePutFileDialog( &options, kResourceFileType, kResKnifeCreator, eventProc, this, &dialog );
error = NavDialogRun( dialog );
return error;
}
/*** DISPLAY REVERT FILE DIALOG ***/
OSStatus FileWindow::DisplayRevertFileDialog( void )
{
OSStatus error = noErr;
NavDialogOptions dialogOptions;
NavEventUPP eventProc = NewNavEventUPP( NavEventFilter );
NavAskDiscardChangesResult result;
NavGetDefaultDialogOptions( &dialogOptions );
GetWindowTitle( window, dialogOptions.savedFileName );
NavAskDiscardChanges( &dialogOptions, &result, eventProc, null );
switch( result )
{
case kNavAskDiscardChanges:
/* error = CloseFile();
if( error ) break;
error = OpenFile();
if( error ) break;
error = ReadFile();
*/ break;
case kNavAskDiscardChangesCancel:
break;
}
DisposeNavEventUPP( eventProc );
return error;
}
/*** DISPLAY MODELESS ASK DISCARD CHANGES DIALOG ***/
OSStatus FileWindow::DisplayModelessAskDiscardChangesDialog( void )
{
OSStatus error;
NavEventUPP eventProc = NewNavEventUPP( ModelessAskDiscardChangesHandler );
NavDialogCreationOptions options;
error = NavGetDefaultDialogCreationOptions( &options );
options.parentWindow = window;
options.modality = kWindowModalityWindowModal;
options.clientName = (CFStringRef) CFBundleGetValueForInfoDictionaryKey( CFBundleGetMainBundle(), kCFBundleNameKey );
options.saveFileName = CFStringCreateWithPascalString( null, fileSpec->name, CFStringGetSystemEncoding());
NavDialogRef dialog;
error = NavCreateAskDiscardChangesDialog( &options, eventProc, this, &dialog );
error = NavDialogRun( dialog );
return error;
}
/*******************************/
/* NAV SERVICES EVENT HANDLERS */
/*******************************/
#pragma mark -
/*** NAV SERVICES EVENT FILTER ***/
pascal void NavEventFilter( NavEventCallbackMessage callBackSelector, NavCBRecPtr cbRecord, NavCallBackUserData callBackUD )
{
#pragma unused( callBackUD )
switch( callBackSelector )
{
case kNavCBEvent:
switch( cbRecord->eventData.eventDataParms.event->what )
{
default:
break;
}
break;
}
}
/*** NAV SERVICES PREVIEW FILTER ***/
pascal Boolean NavPreviewFilter( NavCBRecPtr callBackParms, void *callBackUD )
{
#pragma unused( callBackParms, callBackUD )
return false;
}
/*** NAV SERVICES FILE FILTER ***/
pascal Boolean NavFileFilter( AEDescPtr theItem, void *info, void *callBackUD, NavFilterModes filterMode )
{
#pragma unused( theItem, info, callBackUD, filterMode )
/* do something useful here:
count rsources & types
give DF-based or RF-based info
maybe something else?
*/ return true;
}
#pragma mark -
/*** MODELESS GET FILE HANDLER ***/
pascal void ModelessGetFileHandler( const NavEventCallbackMessage callBackSelector, NavCBRecPtr cbRecord, NavCallBackUserData callBackUD )
{
#pragma unused( callBackUD )
OSStatus error = noErr;
switch( callBackSelector )
{
case kNavCBAccept:
// case kNavCBUserAction:
{ // open first selected file
NavReplyRecord reply;
error = NavDialogGetReply( cbRecord->context, &reply );
if( reply.validRecord )
{
AEKeyword keyword;
DescType descType;
FSSpec fileSpec;
Size actualSize;
error = AEGetNthPtr( &(reply.selection), 1, typeFSS, &keyword, &descType, &fileSpec, sizeof(FSSpec), &actualSize );
if( !error ) new FileWindow( &fileSpec ); // if sucessful, opens & reads the file
}
else SysBeep(0);
NavDisposeReply( &reply );
} break;
case kNavCBTerminate:
{ // dispose of the dialog
NavDialogDispose( cbRecord->context );
} break;
}
}
/*** MODELESS ASK SAVE CHANGES HANDLER ***/
pascal void ModelessAskSaveChangesHandler( const NavEventCallbackMessage callBackSelector, NavCBRecPtr cbRecord, NavCallBackUserData callBackUD )
{
OSStatus error = noErr;
FileWindowPtr file = (FileWindowPtr) callBackUD;
switch( callBackSelector )
{
case kNavCBUserAction:
{ // open first selected file
NavReplyRecord reply;
error = NavDialogGetReply( cbRecord->context, &reply );
if( reply.validRecord )
{
error = file->SaveFile( null );
}
else SysBeep(0);
NavDisposeReply( &reply );
} break;
case kNavCBTerminate:
{ // dispose of the dialog
NavDialogDispose( cbRecord->context );
} break;
}
}
/*** MODELESS PUT FILE HANDLER ***/
pascal void ModelessPutFileHandler( const NavEventCallbackMessage callBackSelector, NavCBRecPtr cbRecord, NavCallBackUserData callBackUD )
{
OSStatus error = noErr;
FileWindowPtr file = (FileWindowPtr) callBackUD;
switch( callBackSelector )
{
case kNavCBUserAction:
{ // open first selected file
NavReplyRecord reply;
error = NavDialogGetReply( cbRecord->context, &reply );
if( reply.validRecord )
{
;
}
else SysBeep(0);
NavDisposeReply( &reply );
} break;
case kNavCBTerminate:
{ // dispose of the dialog
NavDialogDispose( cbRecord->context );
} break;
}
}
/*** MODELESS ASK DISCARD CHANGES HANDLER ***/
pascal void ModelessAskDiscardChangesHandler( const NavEventCallbackMessage callBackSelector, NavCBRecPtr cbRecord, NavCallBackUserData callBackUD )
{
OSStatus error = noErr;
FileWindowPtr file = (FileWindowPtr) callBackUD;
switch( callBackSelector )
{
case kNavCBUserAction:
{ // open first selected file
NavReplyRecord reply;
error = NavDialogGetReply( cbRecord->context, &reply );
if( reply.validRecord )
{
;
}
else SysBeep(0);
NavDisposeReply( &reply );
} break;
case kNavCBTerminate:
{ // dispose of the dialog
NavDialogDispose( cbRecord->context );
} break;
}
}
/*********************/
/* READING & WRITING */
/*********************/
#pragma mark -
/*** READ RESOURCE FORK ***/
OSStatus FileWindow::ReadResourceFork( void )
{
// open file for reading
OSStatus error = noErr;
SInt16 oldResFile = CurResFile();
SetResLoad( false ); // don't load "preload" resources
SInt16 refNum = FSpOpenResFile( fileSpec, fsRdPerm );
SetResLoad( true );
if( !refNum ) return resFNotFound;
UseResFile( refNum );
error = ResError();
if( error ) // no resource map in resource fork, try in data fork before alerting user
DebugError( "\pResource map not present in resource fork", error );
// fork-independant resource reading routine
else error = ReadResourceMap();
rfBased = error? false:true;
// tidy up loose ends
UseResFile( oldResFile );
FSClose( refNum );
return error;
}
/*** READ DATA FORK ***/
OSStatus FileWindow::ReadDataFork( OSStatus rfError )
{
OSStatus error = rfError;
if( error ) // error occoured reading resource map from resource fork, try reading map from data fork instead
{
#if TARGET_API_MAC_CARBON
FSRef fileRef;
SInt16 refNum;
SInt16 oldResFile = CurResFile();
error = FSpMakeFSRef( fileSpec, &fileRef );
if( error )
{
DebugError( "\pFSpMakeFSRef error", error );
return error;
}
if( FSOpenResourceFile == (void *) kUnresolvedCFragSymbolAddress )
{
DisplayError( "\pCarbonLib version too old", "\pThe version of CarbonLib you have installed won't let you view files whose resources are stored in the data fork. Please update to version 1.3 GM of CarbonLib, available from http://www.apple.com/" );
error = paramErr;
return error;
}
SetResLoad( false ); // don't load "preload" resources
error = FSOpenResourceFile( &fileRef, 0, null, fsRdPerm, &refNum );
SetResLoad( true );
if( error || !refNum )
{
DisplayError( "\pThis file is corrupt", "\pSorry, but you will not be able to open it. You should replace it with a backÑup. FSOpenResourceFile()" );
return error? error:resFNotFound;
}
UseResFile( refNum );
// fork-independant resource reading routine
error = ReadResourceMap();
// tidy up loose ends
UseResFile( oldResFile );
FSClose( refNum );
#endif
return error;
}
else // no error occoured reading resource map from resource fork, read data fork as byte stream
{
// open file for reading
SInt16 refNum;
error = FSpOpenDF( fileSpec, fsRdPerm, &refNum );
if( error )
{
DisplayError( "\pData fork could not be read", "\pThis file appears to be corrupted. Although the resources could be read in correctly, the data fork could not be found. Please run Disk First Aid to correct the problem." );
return error;
}
ResourceObjectPtr current = (ResourceObjectPtr) NewPtrClear( sizeof(ResourceObject) );
if( !current )
{
DisplayError( "\pNot enough memory to read data fork", "\pPlease quit other applications and try again." );
FSClose( refNum );
return error;
}
current->number = kDataBrowserDataForkItem; // ID of fork in dataBrowser
*current->name = 0x00;
current->type = 0x00000000;
current->resID = 0;
GetEOF( refNum, &current->size );
current->attribs = 0;
current->nameIconRgn = NewRgn();
current->file = this;
current->dataFork = true;
// get new handle
current->retainCount = 1;
current->data = NewHandleClear( current->size );
if( !current->data || MemError() )
{
DisplayError( "\pNot enough memory to read data fork", "\pPlease quit other applications and try again." );
FSClose( refNum );
return memFullErr;
}
// read data fork
HLock( current->data );
error = FSRead( refNum, &current->size, *current->data );
HUnlock( current->data );
if( error )
{
DisplayError( "\pFailed to read data fork.", "\pA mysterious error occured reading the data fork. The record saying how long the file is has probably been corrupted. You should run Disk First Aid to repair the dis." );
FSClose( refNum );
return error;
}
current->next = resourceMap;
resourceMap = current;
FSClose( refNum );
return error;
}
}
/*** READ RESOURCE MAP ***/
OSStatus FileWindow::ReadResourceMap( void )
{
OSStatus error = noErr;
// set up variables & first resource record
numResources = 0;
numTypes = Count1Types();
resourceMap = (ResourceObjectPtr) NewPtrClear( sizeof(ResourceObject) );
// resourceMap = new ResourceObject( this );
ResourceObjectPtr current = resourceMap;
for( unsigned short i = 1; i <= numTypes; i++ )
{
// read in each data type
ResType type;
Get1IndType( &type, i );
UInt16 n = Count1Resources( type );
for( UInt16 j = 1; j <= n; j++ )
{
// get resource info
// SetResLoad( false );
current->data = Get1IndResource( type, j );
error = ResError();
// SetResLoad( true );
if( MemError() )
{
DisplayError( "\pNot enough memory to read all resources", "\pPlease quit other applications and try again." );
DisposePtr( (Ptr) current );
return memFullErr;
}
if( !current->Data() || error != noErr )
{
DisplayError( "\pResources are damaged, proceed with extreme caution!" );
// bug: dialog should have "continue", "stop" and "quit" buttons, stop being default
DisposePtr( (Ptr) current );
// delete current;
return error; // bug: what should I be doing here?
}
current->number = numResources + j; // ID of resource in dataBrowser
GetResInfo( current->Data(), &current->resID, &current->type, current->name );
current->size = GetResourceSizeOnDisk( current->Data() );
current->attribs = GetResAttrs( current->Data() );
current->file = this;
current->dataFork = false;
DetachResource( current->Data() ); // bug: this needs to be here so calling AddResource() when saving will work, but if ResLoad() was off above, it will kill the only link between the Handle and the resource.
if( i != numTypes || j != n ) // if this isn't the last resourceÉ
{
// Émove on to the next one
current->next = (ResourceObjectPtr) NewPtrClear( sizeof(ResourceObject) );
// current->next = new ResourceObject( this );
current = current->next;
}
}
numResources += n;
}
return error;
}
/*** SAVE FILE ***/
OSStatus FileWindow::SaveFile( FSSpecPtr saveSpec )
{
OSStatus error;
if( saveSpec == null ) // we're straight saving the file, use a temp file, then switch
{
// set up file name
Str255 countStr; // bug: this is not initalised before being used
Str255 tempFileName = "\pResKnife Temporary File ";
NumToString( ++g.tempCount, (StringPtr) countStr );
AppendPString( tempFileName, countStr );
// create temporary file spec
SInt32 dirID;
SInt16 vRefNum; // Always create the temporary file on the same volume as the file we're saving, otherwise FSpExchangeFiles() won't work
OSStatus error = FindFolder( fileSpec->vRefNum, /*kTemporaryFolderType*/ kDesktopFolderType, kCreateFolder, &vRefNum, &dirID );
if( error ) DebugError( "\pFindFolder returned error.", error );
error = FSMakeFSSpec( vRefNum, dirID, tempFileName, tempSpec );
if( error == noErr )
{
DisplayError( "\pFile already exists", "\pThe temporary file used by ResKnife to protect your data already exists, try saving again. If the problem persists, flush your temporary items folder with a utility such as Eradicator." );
return error;
}
else if( error != fnfErr && error != dirNFErr )
{
DebugError( "\pError calling FSMakeFSSpec from FileWindow::SaveFile.", error );
return error;
}
}
else // we're doing a 'save as', no need for temp file
{ // if we created one, then FSpExchange wouldn't work
tempSpec = saveSpec;
}
// save plain DF if present
ResourceObjectPtr current = resourceMap;
if( rfBased && current->RepresentsDataFork() ) // requires data fork to be first item in list
{
// create data fork
FSpCreate( tempSpec, kResKnifeCreator, kResourceFileType, smSystemScript );
// open file for writing
SInt16 refNum;
error = FSpOpenDF( tempSpec, fsWrPerm, &refNum );
if( error )
{
DisplayError( "\pData fork could not be read", "\pThis file appears to be corrupted. Although the resources could be read in correctly, the data fork could not be found. Please run Disk First Aid to correct the problem." );
return error;
}
// save byte stream
SInt8 state = HGetState( resourceMap->Data() );
HLock( current->Data() );
SInt32 size = current->Size();
SetEOF( refNum, size );
error = FSWrite( refNum, &size, (Ptr) *current->Data() );
HSetState( current->Data(), state );
FSClose( refNum );
}
else if( !rfBased && current->RepresentsDataFork() )
{
DisplayError( "\pData fork present with DF-based resource file." );
}
else if( rfBased )
{
DisplayError( "\pTried to save resource fork based file, but no data fork could be found" );
}
// save resource map in specified fork
if( rfBased )
{
SInt16 oldResFile = CurResFile();
FSpCreateResFile( tempSpec, kResKnifeCreator, kResourceFileType, smSystemScript );
SInt16 tempRef = FSpOpenResFile( tempSpec, fsWrPerm );
UseResFile( tempRef );
error = SaveResourceMap();
UseResFile( oldResFile );
CloseResFile( tempRef );
error = ResError();
if( error )
{
DebugError( "\pError calling CloseResFile.", error );
return error;
}
}
else
{
FSRef fileRef;
SInt16 refNum;
SInt16 oldResFile = CurResFile();
error = FSpMakeFSRef( tempSpec, &fileRef );
if( error )
{
DebugError( "\pFSpMakeFSRef error", error );
return error;
}
if( FSOpenResourceFile == (void *) kUnresolvedCFragSymbolAddress )
{
DisplayError( "\pCarbonLib version too old", "\pThe version of CarbonLib you have installed won't let you save resources into the data fork. Please update to version 1.3.1 of CarbonLib, available from http://www.apple.com/" );
error = paramErr;
return error;
}
/* error = FSCreateResourceFile( &fileRef, );
const FSRef * parentRef,
UniCharCount nameLength,
const UniChar * name,
FSCatalogInfoBitmap whichInfo,
const FSCatalogInfo * catalogInfo, // can be NULL
UniCharCount forkNameLength,
const UniChar * forkName, // can be NULL
FSRef * newRef, // can be NULL
FSSpec * newSpec); // can be NULL
if( error )
{
DisplayError( "\pFile could not be created", "\pThe file to save your resources into could not be created. FSCreateResourceFile()" );
return error? error:resFNotFound;
}
*/ error = FSOpenResourceFile( &fileRef, 0, null, fsRdPerm, &refNum );
if( error || !refNum )
{
DisplayError( "\pFile could not be created", "\pThe file to save your resources into could not be created. FSOpenResourceFile()" );
return error? error:resFNotFound;
}
UseResFile( refNum );
error = SaveResourceMap();
UseResFile( oldResFile );
CloseResFile( refNum );
error = ResError();
if( error )
{
DebugError( "\pError calling CloseResFile.", error );
return error;
}
}
// switch file for temp if we did a regular save
if( saveSpec == null )
{
// swap the temporary file for the real one
error = FSpExchangeFiles( tempSpec, fileSpec ); // bug: this will fail on non HFS/HFS+ file systems - therefore file will not save
if( error )
{
DebugError( "\pError calling FSpExchangeFiles.", error );
return error;
}
error = FSpDelete( tempSpec );
if( error )
{
DebugError( "\pError calling FSpDelete.", error );
}
// file is no longer dirty
fileDirty = false;
SetWindowModified( window, fileDirty );
}
return error;
}
/*** SAVE RESOURCE MAP ***/
OSStatus FileWindow::SaveResourceMap( void )
{
OSStatus error = noErr;
// save resources from memory to the temp file
ResourceObjectPtr current = resourceMap;
if( current->RepresentsDataFork() == true )
current = current->Next(); // skip data fork
while( current )
{
// save resource
AddResource( current->Data(), current->Type(), current->ID(), current->Name() );
if( ResError() == addResFailed )
{
DisplayError( "\pSaving Failed", "\pCould not add resources to file." );
current = null;
error = addResFailed;
}
else
{
SetResAttrs( current->Data(), current->Attributes() );
ChangedResource( current->Data() );
// clean up & move on
DetachResource( current->Data() );
current = current->Next();
}
}
return error;
}

62
Carbon/Classes/Files.h Normal file
View File

@ -0,0 +1,62 @@
#include "ResKnife.h"
#ifndef _ResKnife_Files_
#define _ResKnife_Files_
/*!
@header File Handling Code
@discussion All code that reads from and writes to a file resides in here. Also contains open, save and revert dialog code.
*/
/*!
@function DisplayOpenDialog
@discussion Calls the appropriate <tt>Open()</tt> function for the system we are running on.
*/
OSStatus DisplayOpenDialog( void );
/*!
@function DisplayModelessGetFileDialog
@discussion Requires CarbonLib 1.1 or OS X
*/
OSStatus DisplayModelessGetFileDialog( void );
/*!
@function OpenFile
*/
OSStatus OpenFile( short vRefNum, long dirID, ConstStr255Param fileName );
/*!
@function DisplayStandardFileOpenDialog
*/
OSStatus DisplayStandardFileOpenDialog( void );
/*!
@function ModelessGetFileHandler
@discussion Requires CarbonLib 1.1 or OS X
*/
pascal void ModelessGetFileHandler( const NavEventCallbackMessage callBackSelector, NavCBRecPtr cbRecord, NavCallBackUserData callBackUD );
/*!
@function ModelessAskSaveChangesHandler
@discussion Requires CarbonLib 1.1 or OS X
*/
pascal void ModelessAskSaveChangesHandler( const NavEventCallbackMessage callBackSelector, NavCBRecPtr cbRecord, NavCallBackUserData callBackUD );
/*!
@function ModelessPutFileHandler
@discussion Requires CarbonLib 1.1 or OS X
*/
pascal void ModelessPutFileHandler( const NavEventCallbackMessage callBackSelector, NavCBRecPtr cbRecord, NavCallBackUserData callBackUD );
/*!
@function ModelessAskDiscardChangesHandler
@discussion Requires CarbonLib 1.1 or OS X
*/
pascal void ModelessAskDiscardChangesHandler( const NavEventCallbackMessage callBackSelector, NavCBRecPtr cbRecord, NavCallBackUserData callBackUD );
/*!
@function NavEventFilter
*/
pascal void NavEventFilter( NavEventCallbackMessage callBackSelector, NavCBRecPtr cbRecord, NavCallBackUserData callBackUD );
/*!
@function NavPreviewFilter
*/
pascal Boolean NavPreviewFilter( NavCBRecPtr callBackParms, void *callBackUD );
/*!
@function NavFileFilter
*/
pascal Boolean NavFileFilter( AEDescPtr theItem, void *info, void *callBackUD, NavFilterModes filterMode );
#endif

View File

@ -0,0 +1,186 @@
#define _ResKnife_Plug_ 0
#include "HostCallbacks.h"
#include "Application.h"
#include "WindowObject.h"
#include "EditorWindow.h"
#include "PlugObject.h"
#include "Errors.h"
extern globals g;
/* window management */
Plug_WindowRef Host_RegisterWindow( Plug_PlugInRef plug, Plug_ResourceRef resource, WindowRef window )
{
if( resource )
{
EditorWindowPtr plugWindow = new EditorWindow( ((ResourceObjectPtr) resource)->File(), (ResourceObjectPtr) resource, window );
((PlugObjectPtr) plug)->SetWindowObject( (WindowObjectPtr) plugWindow );
((PlugObjectPtr) plug)->SetResourceObject( (ResourceObjectPtr) resource );
return (Plug_WindowRef) plugWindow;
}
/* else
{
PickerWindowPtr plugWindow = new PickerWindow( window );
((PlugObjectPtr) plug)->SetWindowObject( plugWindow );
((PlugObjectPtr) plug)->SetResourceObject( (ResourceObjectPtr) resource );
return (Plug_WindowRef) plugWindow;
}
*/ else return null;
}
#if !TARGET_API_MAC_CARBON
void Host_InstallClassicWindowEventHandler( Plug_WindowRef plugWindow, RoutineDescriptor *handler )
{
((PlugWindowPtr) plugWindow)->InstallClassicEventHandler( (ClassicEventHandlerProcPtr) handler );
}
#endif
WindowRef Host_GetWindowRefFromPlugWindow( Plug_WindowRef plugWindow )
{
return ((WindowObjectPtr) plugWindow)->Window();
}
Plug_WindowRef Host_GetPlugWindowFromWindowRef( WindowRef window )
{
return (Plug_WindowRef) GetWindowRefCon(window);
}
Plug_PlugInRef Host_GetPlugRef( WindowRef window )
{
#pragma unused( window )
return null;
}
Plug_ResourceRef Host_GetTargetResource( Plug_WindowRef plugWindow )
{
return (Plug_ResourceRef) ((EditorWindowPtr) plugWindow)->Resource();
}
/* accessors */
Handle Host_GetResourceData( Plug_ResourceRef resource )
{
((ResourceObjectPtr) resource)->Retain();
return ((ResourceObjectPtr) resource)->Data();
}
Handle Host_GetPartialResourceData( Plug_ResourceRef resource, UInt32 offset, UInt32 length )
{
#pragma unused( resource, offset, length )
return null;
}
void Host_ReleaseResourceData( Plug_ResourceRef resource )
{
#pragma unused( resource )
// ((ResourceObjectPtr) resource)->Release();
return;
}
void Host_ReleasePartialResourceData( Plug_ResourceRef resource, Handle data )
{
#pragma unused( resource, data )
return;
}
ResType Host_GetResourceType( Plug_ResourceRef resource )
{
return ((ResourceObjectPtr) resource)->Type();
}
SInt16 Host_GetResourceID( Plug_ResourceRef resource )
{
return ((ResourceObjectPtr) resource)->ID();
}
UInt32 Host_GetResourceSize( Plug_ResourceRef resource )
{
return ((ResourceObjectPtr) resource)->Size();
}
void Host_GetResourceName( Plug_ResourceRef resource, Str255 name )
{
#pragma unused( resource, name )
return;
}
UInt32 Host_GetWindowRefCon( Plug_WindowRef plugWindow )
{
return ((PlugWindowPtr) plugWindow)->GetRefCon();
}
void Host_SetWindowRefCon( Plug_WindowRef plugWindow, UInt32 value )
{
((PlugWindowPtr) plugWindow)->SetRefCon(value);
}
UInt32 Host_GetGlobalRefCon( Plug_PlugInRef plug )
{
return ((PlugObjectPtr) plug)->GetRefCon();
}
void Host_SetGlobalRefCon( Plug_PlugInRef plug, UInt32 value )
{
((PlugObjectPtr) plug)->SetRefCon(value);
}
Boolean Host_GetResourceDirty( Plug_ResourceRef resource )
{
return ((ResourceObjectPtr) resource)->Dirty();
}
void Host_SetResourceDirty( Plug_ResourceRef resource, Boolean dirty )
{
((ResourceObjectPtr) resource)->SetDirty( dirty );
}
/* utilities */
Handle Host_GetDefaultTemplate( ResType type )
{
short savedResFile = CurResFile();
UseResFile( g.appResFile );
Str255 name = "\pxxxx";
BlockMoveData( &type, name +1, sizeof(ResType) );
Handle tmpl = Get1NamedResource( 'TMPL', name );
OSStatus error = ResError();
UseResFile( savedResFile );
if( error ) return null;
else return tmpl;
}
void Host_AppendMenuToBar( Plug_PlugInRef plug, SInt16 resID )
{
#pragma unused( plug, resID )
return;
}
void Host_RemoveMenuFromBar( Plug_PlugInRef plug, SInt16 resID )
{
#pragma unused( plug, resID )
return;
}
void Host_UpdateMenus( Plug_ResourceRef resource )
{
OSStatus error = noErr;
#if TARGET_API_MAC_CARBON
error = CarbonEventUpdateMenus( null, null, null );
// if( error ) DebugError( "\pHost_UpdateMenus hit an error when calling CarbonEventUpdateMenus()" );
error = FileWindowUpdateMenus( null, null, ((ResourceObjectPtr) resource)->File() );
// if( error ) DebugError( "\pHost_UpdateMenus hit an error when calling FileWindowUpdateMenus()" );
#else
UpdateMenus( ((ResourceObjectPtr) resource)->File()->Window() );
#endif
}
void Host_DisplayError( ConstStr255Param errorStr, ConstStr255Param explanationStr, UInt8 severity )
{
#pragma unused( severity )
DisplayError( errorStr, explanationStr );
}
void Host_DebugError( ConstStr255Param errorStr, OSStatus number )
{
DebugError( errorStr, number );
}

View File

@ -0,0 +1,245 @@
#if !TARGET_API_MAC_OS8
#include <Carbon/Carbon.h>
#endif
#ifndef _ResKnife_HostCallbacks_
#define _ResKnife_HostCallbacks_
/*!
* @header Plug-in Import/Export
* @discussion The only file that both plug-ins and the host should include, this allows a one-to-one mapping between exported and imported functions.
*/
/*!
* @typedef Plug_PlugInRef
* @abstract A global reference to your plug-in.
* @discussion When you plug-in is first loded it is assigned a unique reference number. This allows you to maintain a global refcon into which you can save a pointer to your globals. Thus any change to preferences can be maintained across all of your open editors, even if they are editing resources in different files, and is persistant across the entire time the host remains running.
*/
typedef struct OpaquePlugInObject* Plug_PlugInRef;
/*!
* @typedef Plug_WindowRef
* @abstract A reference to one of your editor or picker windows.
* @discussion The <tt>Plug_WindowRef</tt> allows a host to track your window and send it events
*/
typedef struct OpaqueWindowObject* Plug_WindowRef;
/*!
* @typedef Plug_ResourceRef
* @abstract A reference to one particular resource.
* @discussion Allows a plug to obtain information about <i>any</i> resource, not necessarily the one it is editing. For example, a 'TEXT' editor will probably want 'styl' resource data as well.
*/
typedef struct OpaqueResourceObject* Plug_ResourceRef;
/*!
* @typedef Plug_MenuCommand
* @abstract Passed to your menu parser when the user selects something.
* @discussion Contains the four-byte menu command defined in your xmnu resources or that which you chose when creating the menu in InterfaceBuilder. Only used with the <tt>Plug_HandleMenuCommand()</tt> function.
*/
typedef UInt32 Plug_MenuCommand;
// idea taken from Starry Night (thanks Tom)
#if TARGET_API_MAC_OS8
#if _ResKnife_Plug_ // you should #define this to be 1É
#define ResCall __declspec(dllimport) // functions exported by the host
#define ResCallBack __declspec(dllexport) // functions exported by the plug-in
#else // Éthe host #defines 0
#define ResCall __declspec(dllexport)
#define ResCallBack __declspec(dllimport)
#endif
#else
#define ResCall
#define ResCallBack
#endif
/*!
* @enum EditorType
* @discussion Allows a plug-in to tell the host what it does in a consice and simple way.
*/
typedef enum
{
kPickerType = FOUR_CHAR_CODE('pick'),
kHexEditorType = FOUR_CHAR_CODE('hexa'), // returned ResTypes are ignored
kNormalEditorType = FOUR_CHAR_CODE('norm') // requires 'kind' to be set to the appropriate ResType
} EditorType;
/*!
* @enum OpenMode
* @discussion Lets the plug-in <i>influence</i> how sub-editors are chosen when the plug requests that a new editor be opened
* via <tt>Host_OpenEditor()</tt>. If it cannot be fulfilled, a lesser type of window will open.
*/
typedef enum
{
kOpenUsingEditor = 0,
kOpenUsingTemplate,
kOpenUsingHex
} OpenMode;
/*!
* @enum Plug-in WindowKinds
* @discussion ID numbers for generic plug windows.
*/
enum
{
kPlugWindowDocument = 1000, // your main window's windowkind is set to this by the host, do NOT change it.
kPlugWindowAboutBox, // windowkinds below 2000 are reserved
kPlugWindowPreferences
};
/*** IMPORTED FUNCTIONS ***/
extern "C" // functions beginning "Host_" are in ResKnife/Resurrection
{
/*!
* @function Host_RegisterWindow
* @abstract Registers plug-in windows with the host.
* @discussion Plug-ins should call this function immediatly after creating a window to swap their Mac OS <tt>WindowRef</tt>
* for a <tt>Plug_WindowRef</tt>, which allows the host to track the window, it's contents, and to send events there.
*/
ResCall Plug_WindowRef Host_RegisterWindow( Plug_PlugInRef plug, Plug_ResourceRef resource, WindowRef window );
/*!
* @function Host_InstallClassicWindowEventHandler
* @abstract Without this, non-carbon plugs will not receive events
* @discussion After regestering you window, and only if you do not have access to the Carbon routine <tt>InstallWindowEventHandler()</tt>,
* your plug should call this to receive events. Events sent are currently limited to:
*
* &bull; kEventWindowClickContentRgn
*/
ResCall void Host_InstallClassicWindowEventHandler( Plug_WindowRef plugWindow, RoutineDescriptor *handler );
/*!
* @function Host_GetWindowRefFromPlugWindow
* @abstract Allows plug-ins to obtain a Mac OS <tt>WindowRef</tt> from their <tt>Plug_WindowRef</tt>
* @discussion This call must not be made before the window has been registered using <tt>Host_RegisterWindow()</tt>
*/
ResCall WindowRef Host_GetWindowRefFromPlugWindow( Plug_WindowRef plugWindow );
/*!
* @function Host_GetPlugWindowFromWindowRef
* @abstract Allows plug-ins to obtain a <tt>Plug_WindowRef</tt> from their Mac OS <tt>WindowRef</tt>
* @discussion This call must not be made before the window has been registered using <tt>Host_RegisterWindow()</tt>
*/
ResCall Plug_WindowRef Host_GetPlugWindowFromWindowRef( WindowRef window );
/*!
* @function Host_GetPlugRef
* @discussion You will probably need to call this if the system calls one of your routines directly.
*/
ResCall Plug_PlugInRef Host_GetPlugRef( WindowRef window );
/*!
* @function Host_GetTargetResource
*/
ResCall Plug_ResourceRef Host_GetTargetResource( Plug_WindowRef plugWindow );
/*!
* @function Host_GetResourceData
* @discussion Dispose of with <tt>Host_ReleaseResourceData()</tt>
*/
ResCall Handle Host_GetResourceData( Plug_ResourceRef resource );
/*!
* @function Host_GetPartialResourceData
* @discussion Dispose of with <tt>Host_ReleasePartialResourceData()</tt>
*/
ResCall Handle Host_GetPartialResourceData( Plug_ResourceRef resource, UInt32 offset, UInt32 length );
/*!
* @function Host_ReleaseResourceData
*/
ResCall void Host_ReleaseResourceData( Plug_ResourceRef resource );
/*!
* @function Host_ReleasePartialResourceData
*/
ResCall void Host_ReleasePartialResourceData( Plug_ResourceRef resource, Handle data );
/*!
* @function Host_GetResourceType
*/
ResCall ResType Host_GetResourceType( Plug_ResourceRef resource );
/*!
* @function Host_GetResourceID
*/
ResCall SInt16 Host_GetResourceID( Plug_ResourceRef resource );
/*!
* @function Host_GetResourceSize
*/
ResCall UInt32 Host_GetResourceSize( Plug_ResourceRef resource );
/*!
* @function Host_GetResourceName
*/
ResCall void Host_GetResourceName( Plug_ResourceRef resource, Str255 name );
/* ResCall void Host_SetResourceName( Plug_ResourceRef resource, ConstStr255Param name ); */
/*!
* @function Host_GetResourceDirty
*/
ResCall Boolean Host_GetResourceDirty( Plug_ResourceRef resource );
/*!
* @function Host_SetResourceDirty
*/
ResCall void Host_SetResourceDirty( Plug_ResourceRef resource, Boolean dirty );
/* ResCall Boolean Host_GetResourceIsOnDisk( Plug_ResourceRef resource ); */ // name may change soon
/*!
* @function Host_GetWindowRefCon
*/
ResCall UInt32 Host_GetWindowRefCon( Plug_WindowRef plugWindow );
/*!
* @function Host_SetWindowRefCon
*/
ResCall void Host_SetWindowRefCon( Plug_WindowRef plugWindow, UInt32 value );
/*!
* @function Host_GetGlobalRefCon
*/
ResCall UInt32 Host_GetGlobalRefCon( Plug_PlugInRef plugRef );
/*!
* @function Host_SetGlobalRefCon
*/
ResCall void Host_SetGlobalRefCon( Plug_PlugInRef plugRef, UInt32 value );
/* ResCall OSStatus Host_OpenEditor( Plug_ResourceRef resource, ResOpenMode mode );
ResCall OSStatus Host_SaveResource( Plug_ResourceRef resource ); // VERY IMPORTANT CALL! - Make when closing window
ResCall void Host_SetCursor( Plug_PlugInRef plugRef, Cursor *cursor );
ResCall void Host_SetCursorToID( Plug_PlugInRef plugRef, SInt16 resID );
*/
/*!
* @function Host_GetDefaultTemplate
* @abstract Returns the default TMPL resource for the resource type passed in.
* @discussion Handle is <tt>NULL</tt> if no template exists. You must dispose of the handle yourself.
*/
ResCall Handle Host_GetDefaultTemplate( ResType type );
/*!
* @function Host_AppendMenuToBar
* @discussion The host will track your window, and hide the menu when you are not fromtmost.
*/
ResCall void Host_AppendMenuToBar( Plug_PlugInRef plug, SInt16 resID );
/*!
* @function Host_RemoveMenuFromBar
*/
ResCall void Host_RemoveMenuFromBar( Plug_PlugInRef plug, SInt16 resID );
/*!
* @function Host_UpdateMenus
*/
ResCall void Host_UpdateMenus( Plug_ResourceRef resource );
/*!
* @function Host_DisplayError
* @discussion Errors the user should see
*/
ResCall void Host_DisplayError( ConstStr255Param error, ConstStr255Param explanation, UInt8 severity );
/*!
* @function Host_DebugError
* @discussion Errors the user shouldn't see
*/
ResCall void Host_DebugError( ConstStr255Param error, OSStatus number );
}
/*** EXPORTED FUNCTIONS ***/
extern "C" // functions beginning "Plug_" should be in your plug-in editor
{
/* required functions - plug-in won't be loaded if all these symbols cannot be found */
/* ResCallBack OSStatus Plug_EditorType( Plug_PlugInRef plugRef, EditorType *type, ResType *kind, UInt8 *number ); // called to identify the number of different types of resources it can handle
*/
/*!
* @function Plug_InitInstance
* @abstract Allows a plug-in to initalise itself and prepare to edit the resource.
* @discussion This is a required call. You must export this for your plug-in to be loaded.
* @param plug A reference which has been assigned to this plug-in. It will not necessarily remain constant, so do not save it beyond this call returning.
* @param resource A reference to the resource whose editing session has been requested.
*/
ResCallBack OSStatus Plug_InitInstance( Plug_PlugInRef plug, Plug_ResourceRef resource );
/* ResCallBack OSStatus Plug_FlattenResource( Plug_PlugInRef plugRef, Plug_ResourceRef resource ); // update the handle provided by the host (see Host_GetResData)
ResCallBack OSStatus Plug_ResourceChanged( Plug_PlugInRef plugRef, Plug_ResourceRef resource ); // another editor has changed the resource your working on (normally responded to by calling Host_GetResData and a window update)
*/ /* optional functions - only called if they are requested & found */
/* ResCallBack OSStatus Plug_UpdateMenu( Plug_PlugInRef plugRef, Plug_WindowRef windowObject );
ResCallBack OSStatus Plug_HandleMenuCommand( Plug_PlugInRef plugRef, Plug_MenuCommand menuCmd, Boolean *handled );
ResCallBack OSStatus Plug_HandleMenuItem( Plug_PlugInRef plugRef, SInt16 menuID, SInt16 itemID, Boolean *handled ); // name change
ResCallBack OSStatus Plug_AboutBox( Plug_PlugInRef plugRef );
*/}
#endif

View File

@ -0,0 +1,265 @@
#include "InspectorWindow.h"
#include "FileWindow.h"
#include "ResourceObject.h"
#include "Utility.h"
extern globals g;
/*******************/
/* WINDOW & EVENTS */
/*******************/
/*** CONSTRUCTOR ***/
InspectorWindow::InspectorWindow( void )
{
// if inspector already exists, return
if( g.inspector )
{
SelectWindow( g.inspector->Window() );
return;
}
#if TARGET_API_MAC_CARBON
// create window
Str255 windowName;
Rect creationBounds;
SetRect( &creationBounds, 0, 0, kInspectorWindowWidth, kInspectorWindowHeight );
OffsetRect( &creationBounds, 520, 45 );
OSStatus error = CreateNewWindow( kFloatingWindowClass, kWindowStandardFloatingAttributes | kWindowStandardHandlerAttribute, &creationBounds, &window );
GetIndString( windowName, kWindowNameStrings, kStringInspectorWindowName );
SetWindowTitle( window, windowName );
SetWindowKind( window, kInspectorWindowKind );
SetThemeWindowBackground( window, kThemeBrushUtilityWindowBackgroundActive, false );
// install window event handler
EventHandlerRef ref = null;
EventHandlerUPP eventHandler = NewEventHandlerUPP( CloseInspectorWindow );
EventTypeSpec events[] = { { kEventClassWindow, kEventWindowClose } };
InstallWindowEventHandler( window, eventHandler, GetEventTypeCount(events), (EventTypeSpec *) &events, this, &ref );
// create root control
Rect bounds;
if( g.systemVersion < kMacOSX )
{
ControlRef root;
CreateRootControl( window, &root );
}
// create image well
ControlRef imageWell;
ControlButtonContentInfo content;
content.contentType = kControlNoContent;
SetRect( &bounds, 0, 0, 44, 44 );
OffsetRect( &bounds, 8, 8 );
CreateImageWellControl( window, &bounds, &content, &imageWell );
// create static text controls
Rect windowRect;
ControlRef name, type, id;
ControlFontStyleRec fontStyle;
fontStyle.flags = kControlUseFontMask + kControlUseJustMask;
fontStyle.font = kControlFontSmallSystemFont;
fontStyle.just = teJustLeft;
GetWindowPortBounds( window, &windowRect );
SetRect( &bounds, windowRect.left +60, windowRect.top +8, windowRect.right - windowRect.left -8, windowRect.top +36 );
CreateStaticTextControl( window, &bounds, CFSTR(""), &fontStyle, &name );
fontStyle.font = kControlFontSmallBoldSystemFont;
SetRect( &bounds, windowRect.left +60, windowRect.top +38, windowRect.right - windowRect.left -70, windowRect.top +52 );
CreateStaticTextControl( window, &bounds, CFSTR(""), &fontStyle, &type );
SetRect( &bounds, windowRect.right - windowRect.left -70, windowRect.top +38, windowRect.right - windowRect.left -8, windowRect.top +52 );
CreateStaticTextControl( window, &bounds, CFSTR(""), &fontStyle, &id );
// create group control
ControlRef group;
GetWindowPortBounds( window, &bounds );
InsetRect( &bounds, 8, 8 );
bounds.top += kInspectorHeaderHeight;
CreateGroupBoxControl( window, &bounds, CFSTR("Attributes"), true, &group );
// create checkboxes
ControlRef changedBox, preloadBox, protectedBox,
lockedBox, purgeableBox, sysHeapBox;
InsetRect( &bounds, 4, 4 );
bounds.top = bounds.bottom - kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("System Heap"), kControlCheckBoxUncheckedValue, true, &sysHeapBox );
bounds.top -= kControlCheckBoxHeight;
bounds.bottom -= kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("Purgeable"), kControlCheckBoxUncheckedValue, true, &purgeableBox );
bounds.top -= kControlCheckBoxHeight;
bounds.bottom -= kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("Locked"), kControlCheckBoxUncheckedValue, true, &lockedBox );
bounds.top -= kControlCheckBoxHeight;
bounds.bottom -= kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("Protected"), kControlCheckBoxUncheckedValue, true, &protectedBox );
bounds.top -= kControlCheckBoxHeight;
bounds.bottom -= kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("Preload"), kControlCheckBoxUncheckedValue, true, &preloadBox );
bounds.top -= kControlCheckBoxHeight;
bounds.bottom -= kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("Changed"), kControlCheckBoxUncheckedValue, true, &changedBox );
// embed controls
EmbedControl( changedBox, group );
EmbedControl( preloadBox, group );
EmbedControl( protectedBox, group );
EmbedControl( lockedBox, group );
EmbedControl( purgeableBox, group );
EmbedControl( sysHeapBox, group );
#else
if( g.useAppearance && g.systemVersion >= kMacOSEight )
window = GetNewCWindow( kFileWindow8, null, kFirstWindowOfClass );
else
window = GetNewCWindow( kFileWindow7, null, kFirstWindowOfClass );
#endif
// update and show window
Update();
ShowWindow( window );
g.inspector = this;
}
/*** DESTRUCTOR ***/
InspectorWindow::~InspectorWindow( void )
{
g.inspector = null;
}
/*** CLOSW WINDOW EVENT HANDLER ***/
pascal OSStatus CloseInspectorWindow( EventHandlerCallRef callRef, EventRef event, void *userData )
{
#pragma unused( callRef, event, userData )
if( g.inspector ) delete g.inspector;
return eventNotHandledErr;
}
/*** UPDATE WINDOW ***/
OSStatus InspectorWindow::Update( RgnHandle region )
{
#pragma unused( region )
#if TARGET_API_MAC_CARBON
// get target file
FileWindowPtr file = null;
WindowRef fileWindow = GetFrontWindowOfClass( kDocumentWindowClass, true );
if( !fileWindow ) return noErr; // no window is open - BUG: items in window are not cleared
OSStatus error = noErr;
Boolean validWindow = false;
while( !validWindow || error )
{
WindowKind kind = (WindowKind) GetWindowKind( fileWindow );
if( kind != kFileWindowKind )
{
fileWindow = GetNextWindowOfClass( fileWindow, kDocumentWindowClass, true );
if( !window ) error = paramErr;
}
else
{
file = (FileWindowPtr) GetWindowRefCon( fileWindow );
if( file ) validWindow = true;
else error = paramErr;
}
}
if( error ) return error;
// get selection
UInt32 itemCount;
ControlRef browser = null;
GetWindowProperty( fileWindow, kResKnifeCreator, kDataBrowserSignature, sizeof(ControlRef), null, &browser );
GetDataBrowserItemCount( browser, kDataBrowserNoItem, true, kDataBrowserItemIsSelected, &itemCount );
// get controls
ControlRef root, well, name, type, id, group;
ControlRef changedBox, preloadBox, protectedBox, lockedBox, purgeableBox, sysHeapBox;
ControlButtonContentInfo content;
GetRootControl( window, &root );
GetIndexedSubControl( root, 1, &well );
GetIndexedSubControl( root, 2, &name );
GetIndexedSubControl( root, 3, &type );
GetIndexedSubControl( root, 4, &id );
GetIndexedSubControl( root, 5, &group );
GetIndexedSubControl( group, 1, &changedBox );
GetIndexedSubControl( group, 2, &preloadBox );
GetIndexedSubControl( group, 3, &protectedBox );
GetIndexedSubControl( group, 4, &lockedBox );
GetIndexedSubControl( group, 5, &purgeableBox );
GetIndexedSubControl( group, 6, &sysHeapBox );
if( itemCount != 1 )
{
// set icon
content.contentType = kControlNoContent;
SetImageWellContentInfo( well, &content );
DrawOneControl( well ); // bug: work around for bug in ControlManager
// DisableControl( well );
// set name
StringPtr blank = (StringPtr) NewPtrClear( sizeof(Str255) );
CopyPascalStringToC( "\p", (char *) blank );
SetControlData( name, kControlLabelPart, kControlStaticTextTextTag, 1, blank );
SetControlTitle( name, "\p" );
// set type
SetControlData( type, kControlLabelPart, kControlStaticTextTextTag, 1, blank );
SetControlTitle( type, "\p" );
// set ID
SetControlData( id, kControlLabelPart, kControlStaticTextTextTag, 1, blank );
SetControlTitle( id, "\p" );
// set control values
SetControlValue( changedBox, kControlCheckBoxUncheckedValue );
SetControlValue( preloadBox, kControlCheckBoxUncheckedValue );
SetControlValue( protectedBox, kControlCheckBoxUncheckedValue );
SetControlValue( lockedBox, kControlCheckBoxUncheckedValue );
SetControlValue( purgeableBox, kControlCheckBoxUncheckedValue );
SetControlValue( sysHeapBox, kControlCheckBoxUncheckedValue );
// DisableControl( group );
}
else
{
// get selected resource
DataBrowserItemID first, last;
GetDataBrowserSelectionAnchor( browser, &first, &last ); // first must == last
ResourceObjectPtr resource = file->GetResource(first);
// set icon
content.contentType = kControlContentIconSuiteRes;
content.u.resID = kDefaultResourceIcon;
SetImageWellContentInfo( well, &content );
DrawOneControl( well ); // bug: work around for bug in ControlManager
// EnableControl( well );
// set name
StringPtr label = (StringPtr) NewPtrClear( sizeof(Str255) );
if( PStringLength( resource->Name()) == 0 ) GetIndString( label, kResourceNameStrings, kStringUntitledResource );
else CopyPascalStringToC( resource->Name(), (char *) label );
SetControlData( name, kControlLabelPart, kControlStaticTextTextTag, PStringLength(resource->Name()), label );
SetControlTitle( name, resource->Name() );
// set type
Str255 string;
TypeToPString( resource->Type(), string );
CopyPascalStringToC( string, (char *) label );
SetControlData( type, kControlLabelPart, kControlStaticTextTextTag, string[0], label );
SetControlTitle( type, string );
// set ID
NumToString( resource->ID(), string );
CopyPascalStringToC( string, (char *) label );
SetControlData( id, kControlLabelPart, kControlStaticTextTextTag, string[0], label );
SetControlTitle( id, string );
// set control values
SetControlValue( changedBox, (resource->Attributes() & resChanged)? kControlCheckBoxCheckedValue : kControlCheckBoxUncheckedValue );
SetControlValue( preloadBox, (resource->Attributes() & resPreload)? kControlCheckBoxCheckedValue : kControlCheckBoxUncheckedValue );
SetControlValue( protectedBox, (resource->Attributes() & resProtected)? kControlCheckBoxCheckedValue : kControlCheckBoxUncheckedValue );
SetControlValue( lockedBox, (resource->Attributes() & resLocked)? kControlCheckBoxCheckedValue : kControlCheckBoxUncheckedValue );
SetControlValue( purgeableBox, (resource->Attributes() & resPurgeable)? kControlCheckBoxCheckedValue : kControlCheckBoxUncheckedValue );
SetControlValue( sysHeapBox, (resource->Attributes() & resSysHeap)? kControlCheckBoxCheckedValue : kControlCheckBoxUncheckedValue );
DeactivateControl( changedBox );
// EnableControl( group );
}
return error;
#else
return noErr;
#endif
}

View File

@ -0,0 +1,26 @@
#include "ResKnife.h"
#include "WindowObject.h"
/*!
@header InspectorWindow
@discussion Manages the little inspector that accompanies a File Window.
*/
/* INSPECTOR WINDOW CLASS */
class InspectorWindow : WindowObject
{
public:
InspectorWindow( void );
~InspectorWindow( void );
virtual OSStatus Update( RgnHandle region = null ); // unused parameter
};
pascal OSStatus CloseInspectorWindow( EventHandlerCallRef callRef, EventRef event, void *userData );
// inspector window dimentions
const UInt16 kInspectorHeaderHeight = 48 + 4; // 48 for huge icon
const UInt16 kInspectorWindowWidth = 183;
const UInt16 kInspectorWindowHeight = 183;
// non-window dimentions
const UInt16 kControlCheckBoxHeight = 16;

View File

@ -0,0 +1,73 @@
#include "PickerWindow.h"
#include "FileWindow.h"
#include "Errors.h"
#include "Utility.h"
extern globals g;
/*** CREATOR ***/
PickerWindow::PickerWindow( FileWindowPtr ownerFile, ResType resType ) : PlugWindow( ownerFile )
{
OSStatus error = noErr;
#if USE_NIBS
// create a nib reference (only searches the application bundle)
IBNibRef nibRef = null;
error = CreateNibReference( CFSTR("ResKnife"), &nibRef );
if( error != noErr || nibRef == null )
{
DisplayError( "\pThe nib file reference could not be obtained." );
return;
}
// create window
error = CreateWindowFromNib( nibRef, CFSTR("Picker Window"), &window );
if( error != noErr || window == null )
{
DisplayError( "\pA picker window could not be obtained from the nib file." );
return;
}
// dispose of nib ref
DisposeNibReference( nibRef );
#elif TARGET_API_MAC_CARBON
// create window
Rect creationBounds;
SetRect( &creationBounds, 9, 45, 256 +9, 256 +45 );
error = CreateNewWindow( kDocumentWindowClass, kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute, &creationBounds, &window );
#else
if( g.useAppearance && g.systemVersion >= kMacOSEight )
{
window = GetNewCWindow( kFileWindow8, null, kFirstWindowOfClass );
themeSavvy = true;
}
else
{
window = GetNewCWindow( kFileWindow7, null, kFirstWindowOfClass );
themeSavvy = false;
}
#endif
// set up default window title
Str255 windowTitle, resTypeStr;
FSSpec spec = *ownerFile->GetFileSpec();
CopyPString( spec.name, windowTitle );
TypeToPString( resType, resTypeStr );
AppendPString( windowTitle, "\p: " );
AppendPString( windowTitle, resTypeStr );
AppendPString( windowTitle, "\p resources" );
// save PickerWindow class in window's refcon
SetWindowRefCon( window, (UInt32) this );
SetWindowKind( window, kPickerWindowKind );
SetWindowTitle( window, windowTitle );
// set window's background to default for theme
#if TARGET_API_MAC_CARBON
SetThemeWindowBackground( window, kThemeBrushDocumentWindowBackground, true );
#else
if( g.useAppearance )
SetThemeWindowBackground( window, kThemeBrushDocumentWindowBackground, false );
#endif
}

View File

@ -0,0 +1,23 @@
#include "ResKnife.h"
#include "PlugWindow.h"
#ifndef _ResKnife_PickerWindow_
#define _ResKnife_PickerWindow_
/*!
@header PickerWindow
@discussion A class specifically designed to maintain an external picker window.
*/
/*!
@class PickerWindow
@discussion A class specifically designed to maintain an external picker window.
*/
class PickerWindow : PlugWindow
{
public:
// methods
PickerWindow( FileWindowPtr ownerFile, ResType resType );
};
#endif

View File

@ -0,0 +1,95 @@
#include "PlugObject.h"
#include "Errors.h"
extern globals g;
/*** LOAD EDITOR ***/
OSStatus LoadEditor( ResourceObjectPtr resource, ConstStr63Param libName )
{
// create editor window structure and save resource to be edited into it
OSStatus error = noErr;
PlugObjectPtr plug = (PlugObjectPtr) NewPtrClear( sizeof(PlugObject) ); // bug: this function calls itself, so memory leak may exist here
if( !plug ) return memFullErr; // another bug: should check if plug already has associated PlugObject (ie it is loaded already) - globalRefCon won't work
// load editor's library into memory
CFragConnectionID connID = null;
Ptr mainAddr = null;
Str255 errMessage;
error = GetSharedLibrary( libName, kPowerPCCFragArch, kLoadCFrag, &connID, &mainAddr, errMessage );
DebugError( errMessage );
if( error )
{
if( EqualString( libName, "\pHex Editor", true, true ) )
{
DisposePtr( (Ptr) plug ); // only dispose if was created just now
DisplayError( "\pNo editors are available for this resource!", "\pI suggest you reinstall the program." );
return error;
}
else if( EqualString( libName, "\pTemplate Editor", true, true ) )
{
error = LoadEditor( resource, "\pHex Editor" );
return error;
}
else
{
error = LoadEditor( resource, "\pTemplate Editor" );
if( error )
error = LoadEditor( resource, "\pHex Editor" );
return error;
}
}
plug->SetConnectionID( connID );
// find and call InitInstance symbol
InitPlugProcPtr symAddr;
CFragSymbolClass symClass;
error = FindSymbol( connID, "\pPlug_InitInstance", (Ptr *) &symAddr, &symClass );
if( error )
{
DisposePtr( (Ptr) plug ); // only dispose if was created just now
if( g.debug ) DebugError( "\pPlug_InitInstance() could not be found." );
else DisplayError( "\pCannot load up requested editor.", "\pPlease obtain an update from the plug-in's author." );
return error;
}
error = (* symAddr)( plug, resource );
if( error )
{
DisposePtr( (Ptr) plug ); // only dispose if was created just now
DebugError( "\pPlug_InitInstance() returned an error. This is quite normal for the Template Editor, thus if no XXXX Editor exists, and no template is found, you will see this dialog, then a hex editor appear." );
}
return error;
}
/*** UNLOAD EDITOR ***/
OSStatus UnloadEditor( PlugObjectPtr plug )
{
#pragma unused( plug )
OSStatus error = noErr;
CFragConnectionID connID = plug->GetConnectionID();
// find and call DisposeEditor symbol
/* DisposePlugProcPtr symAddr;
CFragSymbolClass symClass;
error = FindSymbol( connID, "\pPlug_DisposeEditor", (Ptr *) &symAddr, &symClass );
if( error ) return error;
(* symAddr)( plug );
*/
// close connection to editor
error = CloseConnection( &connID );
plug->SetConnectionID( null );
return error;
}
/**************************/
/* CLASS ACCESSOR METHODS */
/**************************/
/*** ACCESSORS ***/
void PlugObject::SetRefCon( UInt32 value ) { refcon = value; }
UInt32 PlugObject::GetRefCon( void ) { return refcon; }
CFragConnectionID PlugObject::GetConnectionID( void ) { return connID; }
void PlugObject::SetConnectionID( CFragConnectionID newID ) { connID = newID; }
WindowObjectPtr PlugObject::GetWindowObject( void ) { return windowObj; }
void PlugObject::SetWindowObject( WindowObjectPtr newWindowObj ) { windowObj = newWindowObj; }
ResourceObjectPtr PlugObject::GetResourceObject( void ) { return resourceObj; }
void PlugObject::SetResourceObject( ResourceObjectPtr newResourceObj ) { resourceObj = newResourceObj; }

View File

@ -0,0 +1,97 @@
#include "ResKnife.h"
#include "WindowObject.h"
#include "ResourceObject.h"
#ifndef _ResKnife_PlugObject_
#define _ResKnife_PlugObject_
/*!
@header PlugObject
@discussion Keeps track of all loaded plug-ins.
*/
/*!
@class PlugObject
@abstract Contains the data required to know which plug-ins can edit what.
@discussion Created when a plug-in is loaded for the first time, and is never destoyed, this class maintains the connection between the host and a plug-in. Also tracks whether the plug is an Editor or a Picker.
*/
typedef class PlugObject
{
/*! @var connID A CFM connection ID to a plug-in. */
CFragConnectionID connID;
/*! @var windowObj The first window loaded for this plug-in. Either a PickerWindow or an EditorWindow. */
WindowObjectPtr windowObj;
/*! @var resourceObj What the first loaded window edits (if anything). */
ResourceObjectPtr resourceObj;
// EditorType editorType;
/*! @var ResType The type of resource this plug can handle. */
ResType whatIActuallyEdit;
// for the plug's use
/*! @var refcon A plug-global refcon for storing (say) it's preferences structure. */
UInt32 refcon;
public:
/*!
@function GetConnectionID
@discussion Accessor function.
*/
CFragConnectionID GetConnectionID( void );
/*!
@function SetConnectionID
@discussion Accessor function.
*/
void SetConnectionID( CFragConnectionID newID );
/*!
@function GetWindowObject
@discussion Accessor function.
*/
WindowObjectPtr GetWindowObject( void );
/*!
@function SetWindowObject
@discussion Accessor function.
*/
void SetWindowObject( WindowObjectPtr newWindowObj );
/*!
@function GetResourceObject
@discussion Accessor function.
*/
ResourceObjectPtr GetResourceObject( void );
/*!
@function SetResourceObject
@discussion Accessor function.
*/
void SetResourceObject( ResourceObjectPtr newResourceObj );
/*!
@function SetRefCon
@discussion Accessor function.
*/
void SetRefCon( UInt32 value );
/*!
@function GetRefCon
@discussion Accessor function.
*/
UInt32 GetRefCon( void );
} PlugObject, *PlugObjectPtr;
/*!
@function LoadEditor
@discussion Loads a CFrag by name, and passes it a resource to edit.
@param resource The resource to be edited.
@param libName A string containing the fragment name of the editor to be used, for example "icns Editor" or "PICT Picker".
*/
OSStatus LoadEditor( ResourceObjectPtr resource, ConstStr63Param libName );
/*!
@function UnloadEditor
@discussion Unloads the given plug.
@param plug The plug-in to be killed.
*/
OSStatus UnloadEditor( PlugObjectPtr plug );
/*!
@typedef InitPlugProcPtr
@discussion The pointer to Plug_InitInstance() that FindSymbol returns.
*/
typedef OSStatus (* InitPlugProcPtr)( PlugObjectPtr plug, ResourceObjectPtr resource );
#endif

View File

@ -0,0 +1,91 @@
#include "PlugWindow.h"
#include "Utility.h"
#include "string.h"
extern globals g;
/*********************/
/* PLUG WINDOW CLASS */
/*********************/
/*** CREATOR ***/
PlugWindow::PlugWindow( FileWindowPtr ownerFile )
{
memset( this, 0, sizeof(PlugWindow) );
file = ownerFile;
}
/*** GET FILE WINDOW ***/
FileWindowPtr PlugWindow::File( void )
{
return file;
}
#if !TARGET_API_MAC_CARBON
/*** INSTALL CLASSIC EVENT HANDLER ***/
void PlugWindow::InstallClassicEventHandler( ClassicEventHandlerProcPtr newHandler )
{
handler = newHandler;
}
/*** UPDATE WINDOW ***/
OSStatus PlugWindow::Update( RgnHandle region )
{
EventRecord event;
event.what = updateEvt;
event.message = (UInt32) window;
event.when = (UInt32) region; // note overload here
event.where = NewPoint();
event.modifiers = null;
OSStatus error = (* handler)( &event, kEventWindowUpdate, null );
return error;
}
/*** ACTIVATE WINDOW ***/
OSStatus PlugWindow::Activate( Boolean active )
{
EventRecord event;
event.what = activateEvt;
event.message = (UInt32) window;
event.when = TickCount();
event.where = NewPoint();
event.modifiers = null;
OSStatus error = (* handler)( &event, active? kEventWindowActivated:kEventWindowDeactivated, null );
return error;
}
/*** CLOSE WINDOW ***/
OSStatus PlugWindow::Close( void )
{
EventRecord event;
event.what = mouseUp;
event.message = (UInt32) window;
event.when = TickCount();
event.where = NewPoint();
event.modifiers = null;
OSStatus error = (* handler)( &event, kEventWindowClose, null );
return error;
}
/*** HANDLE CLICK IN WINDOW ***/
OSStatus PlugWindow::Click( Point mouse, EventModifiers modifiers )
{
EventRecord event;
event.what = mouseDown;
event.message = (UInt32) window;
event.when = TickCount();
event.where = mouse;
event.modifiers = modifiers;
OSStatus error = (* handler)( &event, kEventWindowClickContentRgn, null );
return error;
}
#endif
/*** ACCESSORS ***/
void PlugWindow::SetRefCon( UInt32 value ) { refcon = value; }
UInt32 PlugWindow::GetRefCon( void ) { return refcon; }

View File

@ -0,0 +1,78 @@
#include "ResKnife.h"
#include "WindowObject.h"
#ifndef _ResKnife_PlugWindow_
#define _ResKnife_PlugWindow_
/*!
* @header PlugWindow
* @discussion Declares the (very simple) PlugWindow subclass.
*/
#if !TARGET_API_MAC_CARBON
// classic event handler
typedef CALLBACK_API(OSStatus, ClassicEventHandlerProcPtr) (EventRecord *event, UInt32 eventKind, void *userData);
typedef STACK_UPP_TYPE(ClassicEventHandlerProcPtr) ClassicEventHandlerUPP;
enum { uppClassicEventHandlerProcInfo = 0x00000FF0 }; /* pascal 4_bytes Func(4_bytes, 4_bytes, 4_bytes) */
#ifdef __cplusplus
inline ClassicEventHandlerUPP NewClassicEventHandlerUPP(ClassicEventHandlerProcPtr userRoutine) { return (ClassicEventHandlerUPP)NewRoutineDescriptor((ProcPtr)(userRoutine), uppClassicEventHandlerProcInfo, GetCurrentArchitecture()); }
#else
#define NewClassicEventHandlerUPP(userRoutine) (ClassicEventHandlerUPP)NewRoutineDescriptor((ProcPtr)(userRoutine), uppClassicEventHandlerProcInfo, GetCurrentArchitecture())
#endif
#endif
/*!
* @class PlugWindow
* @abstract Base class for EditorWindow and PickerWindow.
* @discussion Declares the classic event handler &amp; a refcon, and overrides a few classic events.
*/
class PlugWindow : public WindowObject
{
protected:
/*! @var file The owning file of the window. */
FileWindowPtr file;
#if !TARGET_API_MAC_CARBON
/*! @var handler The classic event handler used for plug windows. */
ClassicEventHandlerProcPtr handler;
#endif
/*! @var refcon A refcon for the plug to use. */
UInt32 refcon;
public:
/*!
* @function PlugWindow
*/
PlugWindow( FileWindowPtr ownerFile );
/*!
* @function File
*/
FileWindowPtr File( void );
#if !TARGET_API_MAC_CARBON
/*!
* @function InstallClassicEventHandler
*/
void InstallClassicEventHandler( ClassicEventHandlerProcPtr newHandler );
/*!
* @function Close
*/
virtual OSStatus Close( void );
/*!
* @function Activate
*/
virtual OSStatus Activate( Boolean active = true );
/*!
* @function Update
*/
virtual OSStatus Update( RgnHandle region = null );
/*!
* @function Click
*/
virtual OSStatus Click( Point mouse, EventModifiers modifiers );
#endif
void SetRefCon( UInt32 value );
UInt32 GetRefCon( void );
};
#endif

View File

@ -0,0 +1,100 @@
#include "ResourceObject.h"
#include "Errors.h"
#include "string.h"
/*** CREATOR ***/
ResourceObject::ResourceObject( FileWindowPtr owner )
{
// set contents to zero
memset( this, 0, sizeof(ResourceObject) );
file = owner;
nameIconRgn = NewRgn();
}
/*** DESTRUCTOR ***/
ResourceObject::~ResourceObject( void )
{
if( nameIconRgn ) DisposeRgn( nameIconRgn );
if( data ) DisposeHandle( data );
}
/*** RETAIN ***/
OSStatus ResourceObject::Retain( void )
{
OSStatus error = noErr;
/* if( retainCount == 0 )
{
if( dataFork )
{
// open file for reading
SInt16 refNum;
error = FSpOpenDF( file->GetFileSpec(), fsRdPerm, &refNum );
if( error )
{
DisplayError( "\pData fork could not be read", "\pThis file appears to be corrupted. Although the resources could be read in correctly, the data fork could not be found. Please run Disk First Aid to correct the problem." );
return error;
}
// get new handle
data = NewHandleClear( size );
if( !data || MemError() )
{
DisplayError( "\pNot enough memory to read data fork", "\pPlease quit other applications and try again." );
FSClose( refNum );
return memFullErr;
}
// read data fork
HLock( data );
error = FSRead( refNum, (long *) &size, *data );
HUnlock( data );
FSClose( refNum );
}
else
{
LoadResource( data );
}
}
*/ retainCount++;
return error;
}
/*** RELEASE ***/
void ResourceObject::Release( void )
{
if( retainCount > 0 )
{
/* if( retainCount == 1 )
DisposeHandle( data );
*/ retainCount--;
}
}
/*** SET RESOURCE DIRTY ***/
void ResourceObject::SetDirty( Boolean value )
{
dirty = value;
file->SetFileDirty( value );
// being here indicates the resource size parameter also needs updating
size = GetHandleSize( data );
// bug: should now tell all open copies of this resource to update themselves
}
/*** RES INFO RECORD ACCESSORS ***/
FileWindowPtr ResourceObject::File( void ) { return file; }
ResourceObjectPtr ResourceObject::Next( void ) { return next; }
Boolean ResourceObject::Dirty( void ) { return dirty; }
void ResourceObject::Select( Boolean select ) { selected = select; }
Boolean ResourceObject::Selected( void ) { return selected; }
DataBrowserItemID ResourceObject::Number( void ) { return number; }
Boolean ResourceObject::RepresentsDataFork( void ) { return dataFork; }
Handle ResourceObject::Data( void ) { return data; }
UInt8* ResourceObject::Name( void ) { return name; }
UInt32 ResourceObject::Size( void ) { return size; }
ResType ResourceObject::Type( void ) { return type; }
SInt16 ResourceObject::ID( void ) { return resID; }
SInt16 ResourceObject::Attributes( void ) { return attribs; }

View File

@ -0,0 +1,159 @@
#include "ResKnife.h"
#include "FileWindow.h" // for friends
#ifndef _ResKnife_ResourceObject_
#define _ResKnife_ResourceObject_
/*!
@header ResourceObject
@discussion Contains all required information for a resource, including it's parent file and whether or not it has been edited since it was last saved (if ever).
*/
/*!
@class ResourceObject
@abstract Opaque
@discussion Mainly consisting of regular controls such as scroll bars and headers, this doesn't do much by it's self.
*/
class ResourceObject
{
/*! @var file The parent file into which this resource is to be saved. */
FileWindowPtr file;
/*! @var next the next resource. */
ResourceObjectPtr next;
// status of resource
// Boolean neverSaved; // resource has never been saved -- cleared on SaveFile()
/*! @var dirty Resource has been modified since the file was last saved if this flag is true. Cleared when SaveFile() is called. */
UInt16 retainCount; // counts the number of times this resource has been loaded minus the number it's been released
Boolean dirty;
// Boolean update; // resource is not synched with temporary file -- cleared on UpdateFile()
Boolean dataFork; // resource represents data fork, only true in files whose resource map is in the resource fork
/*! @var number Item number in the data browser. Deleted resources vacate their number, and it is not replaced if a new resource is created. New resources are appended to the end of the chain, and will always have the highest numbers. */
DataBrowserItemID number;
// classic display parameters
/*! @var nameIconRgn */
RgnHandle nameIconRgn;
/*! @var selected */
Boolean selected;
// resource
/*! @var type */
ResType type;
/*! @var size */
SInt32 size;
/*! @var resID */
SInt16 resID;
/*! @var attribs */
SInt16 attribs;
/*! @var data The actual resource byte stream. */
Handle data;
/*! @var name */
Str255 name;
/* methods */
public:
/*!
@function ResourceObject
@discussion Creator function.
*/
ResourceObject( FileWindowPtr owner = null );
/*!
@function ~ResourceObject
@discussion Destructor function.
*/
~ResourceObject( void );
/*!
@function Retain
@discussion Accessor function.
*/
OSStatus Retain( void );
/*!
@function Release
@discussion Accessor function.
*/
void Release( void );
/*!
@function File
@discussion Accessor function.
*/
FileWindowPtr File( void );
/*!
@function Next
@discussion Accessor function.
*/
ResourceObjectPtr Next( void );
/*!
@function SetDirty
@discussion Accessor function.
*/
void SetDirty( Boolean value );
/*!
@function Dirty
@discussion Accessor function.
*/
Boolean Dirty( void );
/*!
@function Select
@discussion Accessor function.
@param select Pass true to select, false to deselect this resource in the file window.
*/
void Select( Boolean select );
/*!
@function Selected
@discussion Accessor function.
*/
Boolean Selected( void );
/*!
@function Number
@discussion Accessor function.
*/
DataBrowserItemID Number( void );
/*!
@function RepresentsDataFork
@discussion Accessor function.
*/
Boolean RepresentsDataFork( void );
/*!
@function Data
@discussion Accessor function. Warning: This functions returns the ACTUAL data handle - do not dispose of it.
*/
Handle Data( void );
/*!
@function Name
@discussion Accessor function.
*/
UInt8* Name( void );
/*!
@function Size
@discussion Accessor function.
*/
UInt32 Size( void );
/*!
@function Type
@discussion Accessor function.
*/
ResType Type( void );
/*!
@function ID
@discussion Accessor function.
*/
SInt16 ID( void );
/*!
@function Attributes
@discussion Accessor function.
*/
SInt16 Attributes( void );
friend OSStatus FileWindow::ReadResourceMap( void );
friend OSStatus FileWindow::ReadDataFork( OSStatus RFError );
friend OSStatus FileWindow::InitDataBrowser( void );
#if !TARGET_API_MAC_CARBON
friend OSStatus FileWindow::Click( Point mouse, EventModifiers modifiers );
friend OSStatus FileWindow::DrawResourceIcon( ResourceObjectPtr resource, UInt16 line );
#endif
friend OSStatus FileWindow::CreateNewResource( ConstStr255Param name, ResType type, SInt16 resID, SInt16 attribs );
friend OSStatus FileWindow::DisposeResourceMap( void );
};
#endif

220
Carbon/Classes/Utility.cpp Normal file
View File

@ -0,0 +1,220 @@
#include "Utility.h"
extern globals g;
/**********************/
/* QUICKDRAW ROUTINES */
/**********************/
/*** SET COLOUR ***/
void SetColour( RGBColor *colour, UInt16 red, UInt16 green, UInt16 blue )
{
colour->red = red;
colour->green = green;
colour->blue = blue;
}
/* investigate the call ShieldCursor() - it hides the mouse when it enters a certain rect */
/*******************/
/* STRING ROUTINES */
/*******************/
/*** C STRING LENGTH ***/
unsigned long CStringLength( char *string )
{
unsigned long length;
Boolean end = false;
for( length = 0; end == false; length++ )
if( *(string + length) == 0x00 ) end = true;
return length;
}
/*** PASCAL STRING LENGTH ***/
unsigned char PStringLength( unsigned char *string )
{
return *string;
}
/*** TYPE TO C STRING ***/
void TypeToCString( const OSType type, char *string )
{
BlockMoveData( &type, &string[0], sizeof(OSType) );
string[sizeof(OSType)] = 0x00;
}
/*** TYPE TO PASCAL STRING ***/
void TypeToPString( const OSType type, Str255 string )
{
string[0] = sizeof(OSType);
BlockMoveData( &type, &string[1], sizeof(OSType) );
}
/*** TYPE TO CORE FOUNDATION STRING ***/
void TypeToCFString( const OSType type, CFStringRef *string )
{
char cString[5];
TypeToCString( type, (char *) &cString );
*string = CFStringCreateWithCString( CFAllocatorGetDefault(), (char *) &cString, kCFStringEncodingMacRoman );
}
/*** COPY C STRING ***/
void CopyCString( const UInt8 *source, UInt8 *dest )
{
//#pragma warning off
while( *dest++ = *source++ );
//#pragma warning reset
}
/*** COPY PASCAL STRING ***/
void CopyPString( const UInt8 *source, UInt8 *dest )
{
UInt8 length = *source, count;
for( count = 0; count <= length; count++ )
*dest++ = *source++;
}
/*** EQUAL C STRINGS ***/
Boolean EqualCStrings( UInt8 *source, UInt8 *dest )
{
while( *source != 0x00 )
if( *source++ != *dest++ ) return false;
return true;
}
/*** EQUAL PASCAL STRINGS ***/
Boolean EqualPStrings( UInt8 *source, UInt8 *dest )
{
UInt8 length = *source, count;
for( count = 0; count <= length; count++ )
if( *source++ != *dest++ ) return false;
return true;
}
/*** APPEND ONE PASCAL STRING ONTO ANOTHER ***/
void AppendPString( Str255 original, ConstStr255Param added )
{
short numberBytes = added[0]; // length of string to be added
short totalLength = added[0] + original[0];
if( totalLength > 255 ) // too long, adjust number of bytes to add
{
totalLength = 255;
numberBytes = totalLength - original[0];
}
BlockMoveData( &added[1], &original[totalLength-numberBytes + 1], numberBytes );
original[0] = totalLength; // new length of original string
while( ++totalLength <= 255 )
original[totalLength] = 0x00; // set rest of string to zero
}
/*****************/
/* MENU ROUTINES */
/*****************/
/*** MENU ITEM ENABLE ***/
void MenuItemEnable( MenuRef menu, MenuItemIndex item, Boolean enable )
{
#if !TARGET_API_MAC_CARBON
if( g.systemVersion >= kMacOSEightPointFive )
{
#endif
if( enable ) EnableMenuItem( menu, item );
else DisableMenuItem( menu, item );
#if !TARGET_API_MAC_CARBON
}
else
{
if( enable ) EnableItem( menu, item );
else DisableItem( menu, item );
}
#endif
}
/*** ENABLE MENU COMMAND ***/
void EnableCommand( MenuRef menu, MenuCommand command, Boolean enable )
{
if( enable ) EnableMenuCommand( menu, command );
else DisableMenuCommand( menu, command );
}
/******************/
/* FILE UTILITIES */
/******************/
/* MakeRelativeAliasFile creates a new alias file located at
aliasDest referring to the targetFile. relative path
information is stored in the new file. */
/* MAKE RELATIVE ALIAS FILE */
OSErr MakeRelativeAliasFile(FSSpec *targetFile, FSSpec *aliasDest)
{
OSErr error;
FInfo fndrInfo;
AliasHandle theAlias = null;
Boolean fileCreated = false;
SInt16 rsrc = -1;
// set up our the alias' file information
error = FSpGetFInfo( targetFile, &fndrInfo );
if( error != noErr ) goto bail;
if( fndrInfo.fdType == 'APPL')
fndrInfo.fdType = kApplicationAliasType;
fndrInfo.fdFlags = kIsAlias; // implicitly clear the inited bit
// create the new file
FSpCreateResFile( aliasDest, 'TEMP', 'TEMP', smSystemScript );
if( (error = ResError() ) != noErr) goto bail;
fileCreated = true;
// set the file information or the new file
error = FSpSetFInfo( aliasDest, &fndrInfo );
if( error != noErr ) goto bail;
// create the alias record, relative to the new alias file
error = NewAlias( aliasDest, targetFile, &theAlias );
if( error != noErr ) goto bail;
// save the resource
rsrc = FSpOpenResFile( aliasDest, fsRdWrPerm );
if( rsrc == -1)
{
error = ResError();
goto bail;
}
UseResFile( rsrc );
AddResource( (Handle) theAlias, rAliasType, 0, aliasDest->name );
error = ResError();
if( error != noErr) goto bail;
theAlias = null;
CloseResFile( rsrc );
rsrc = -1;
error = ResError();
if( error != noErr) goto bail;
// done
return noErr;
bail:
if( rsrc != -1 ) CloseResFile( rsrc );
if( fileCreated ) FSpDelete( aliasDest );
if( theAlias != null ) DisposeHandle( (Handle) theAlias );
return error;
}
/**********************/
/* INTERNET UTILITIES */
/**********************/
/*** LAUNCH WEB BROWSER ***/
OSStatus LaunchURL( char *url )
{
OSStatus error = noErr;
ICInstance instance;
error = ICStart( &instance, kResKnifeCreator );
if( error != noErr ) return error;
SInt32 start = 0, length = CStringLength( url );
error = ICLaunchURL( instance, null, url, length, &start, &length );
ICStop( instance );
return error;
}

73
Carbon/Classes/Utility.h Normal file
View File

@ -0,0 +1,73 @@
#include "ResKnife.h"
#ifndef _ResKnife_Utility_
#define _ResKnife_Utility_
/*!
@header Utility Routines
@discussion Supplies the application with generic oft-used functions such as string conversion and menu enabling.
*/
/*!
@function SetColour
*/
void SetColour( RGBColor *colour, UInt16 red, UInt16 green, UInt16 blue );
/*!
@function CStringLength
*/
unsigned long CStringLength( char *string );
/*!
@function PStringLength
*/
unsigned char PStringLength( unsigned char *string );
/*!
@function TypeToCString
*/
void TypeToCString( const OSType type, char *string );
/*!
@function TypeToPString
*/
void TypeToPString( const OSType type, Str255 string );
/*!
@function TypeToCFString
*/
void TypeToCFString( const OSType type, CFStringRef *string );
/*!
@function CopyCString
*/
void CopyCString( const UInt8 *source, UInt8 *dest );
/*!
@function CopyPString
*/
void CopyPString( const UInt8 *source, UInt8 *dest );
/*!
@function EqualCStrings
*/
Boolean EqualCStrings( UInt8 *source, UInt8 *dest );
/*!
@function EqualPStrings
*/
Boolean EqualPStrings( UInt8 *source, UInt8 *dest );
/*!
@function AppendPString
*/
void AppendPString( Str255 original, ConstStr255Param added );
/*!
@function MenuItemEnable
*/
void MenuItemEnable( MenuRef menu, MenuItemIndex item, Boolean enable );
/*!
@function EnableCommand
*/
void EnableCommand( MenuRef menu, MenuCommand command, Boolean enable );
/*!
@function MakeRelativeAliasFile
*/
OSErr MakeRelativeAliasFile(FSSpec *targetFile, FSSpec *aliasDest);
/*!
@function LaunchURL
@param url A C string containing the address to which you want the user to go. You must include 'http://' if necessary, and all addresses to a directory should have a trailing slash.
*/
OSStatus LaunchURL( char *url );
#endif

View File

@ -0,0 +1,75 @@
#include "WindowObject.h"
/*** CONSTRUCTOR ***/
WindowObject::WindowObject( void )
{
memset( this, 0, sizeof(WindowObject) );
}
/*** DESTRUCTOR ***/
WindowObject::~WindowObject( void )
{
if( window )
{
HideWindow( window );
DisposeWindow( window );
}
}
/*** WINDOW ACCESSOR ***/
WindowRef WindowObject::Window( void )
{
return window;
}
/*** WINDOW BOUNDS ARE CHANGING ***/
OSStatus WindowObject::BoundsChanging( EventRef event )
{
#pragma unused( event )
return eventNotHandledErr;
}
/*** WINDOW BOUNDS HAVE CHANGED ***/
OSStatus WindowObject::BoundsChanged( EventRef event )
{
#pragma unused( event )
return eventNotHandledErr;
}
#if !TARGET_API_MAC_CARBON
/*** CLOSE ***/
OSStatus WindowObject::Close( void )
{
delete this;
return noErr;
}
/*** ACTIVATE ***/
OSStatus WindowObject::Activate( Boolean active )
{
#pragma unused( active )
return eventNotHandledErr;
}
/*** UPDATE ***/
OSStatus WindowObject::Update( RgnHandle region )
{
#pragma unused( region )
return eventNotHandledErr;
}
/*** UPDATE SCROLL BARS ***/
OSStatus WindowObject::UpdateScrollBars( void )
{
return eventNotHandledErr;
}
/*** MOUSE CLICK ***/
OSStatus WindowObject::Click( Point mouse, EventModifiers modifiers )
{
#pragma unused( mouse, modifiers )
return eventNotHandledErr;
}
#endif

View File

@ -0,0 +1,86 @@
#include "ResKnife.h"
#ifndef _ResKnife_WindowObject_
#define _ResKnife_WindowObject_
/*!
* @header WindowObject
* @discussion The base class for all windows in the program. Also declares the (very simple) PlugWindow subclass.
*/
/*!
* @class WindowObject
* @abstract Base class for all windows in the program.
* @discussion Mainly consisting of regular controls such as scroll bars and headers, this doesn't do much by it's self.
*/
class WindowObject
{
// data
protected:
/*! @var window Stores the Mac OS <tt>WindowRef</tt> pertaining to this window. */
WindowRef window;
/*! @var header Header control (the grey bar at the top of most windows). */
ControlRef header;
/*! @var leftText Left hand side static text control (in the header). */
ControlRef left;
/*! @var rightText Right hand side static text control (in the header). */
ControlRef right;
#if !TARGET_API_MAC_CARBON
/*! @var horizScroll Horizontal scrollbar at the bottom of most windows */
ControlRef horizScroll;
/*! @var vertScroll Vetical scrollbar down the right side of most windows */
ControlRef vertScroll;
/*! @var themeSavvy True if this window is using an Appearance Manager WDEF. (Also used to determine if Appearance controls should be drawn if this window.) */
Boolean themeSavvy;
#endif
public:
// methods
/*!
* @function WindowObject
* @discussion Constructor function.
*/
WindowObject( void );
/*!
* @function WindowObject
* @discussion Desturctor function.
*/
virtual ~WindowObject( void );
/*!
* @function Window
* @discussion Accessor for the object&rsquo;s <tt>WindowRef</tt>.
*/
virtual WindowRef Window( void );
/*!
* @function BoundsChanging
*/
virtual OSStatus BoundsChanging( EventRef event );
/*!
* @function BoundsChanged
*/
virtual OSStatus BoundsChanged( EventRef event );
#if !TARGET_API_MAC_CARBON
/*!
* @function Close
*/
virtual OSStatus Close( void );
/*!
* @function Activate
*/
virtual OSStatus Activate( Boolean active = true );
/*!
* @function Update
*/
virtual OSStatus Update( RgnHandle region = null );
/*!
* @function UpdateScrollBars
*/
virtual OSStatus UpdateScrollBars( void );
/*!
* @function Click
*/
virtual OSStatus Click( Point mouse, EventModifiers modifiers );
#endif
};
#endif

16
Carbon/Generic.h Normal file
View File

@ -0,0 +1,16 @@
// abbreviations
#define null NULL
#define qdb qd.screenBits.bounds
// Easier API call names
#define GetWindowRefCon( window ) (long) GetWRefCon( window )
#define SetWindowRefCon( window, refcon ) SetWRefCon( window, refcon )
#define GetWindowTitle( window, string ) GetWTitle( window, string )
#define SetWindowTitle( window, name ) SetWTitle( window, name )
#define InvalidateRect( bounds ) InvalRect( bounds )
#define InvalidateWindowRect( window, bounds ) (OSStatus) InvalWindowRect( window, bounds )
#define RectToRegion( region, rect ) RectRgn( region, rect )
#define NewPoint() (Point) { 0, 0 }
#define SetPoint( point, x, y ) SetPt( point, x, y )
#define HilightColour( colour ) HiliteColor( colour )
#define GetPortHilightColour( window, colour ) GetPortHiliteColor( window, colour )

310
Carbon/ResKnife.h Normal file
View File

@ -0,0 +1,310 @@
/*
With thanks to: For:
Jim Luther MoreFiles
Bryan K. Ressler & Bradley D. Mohr Asynchronous SoundHelper
John Montbriand & Pete Gontier FinderDragPro
*/
// interesting function I found: CFBundleOpenBundleResourceMap()
#if defined(__MWERKS__) // compiling with CodeWarrior
#if __profile__
#include <Profiler.h>
#endif
#else // compiling with ProjectBuilder, use frameworks
#define NO_DATA_BROWSER_TWEAKS 0
#define USE_OLD_DATA_BROWSER_STRUCTS 0
#include <Carbon/Carbon.h>
#endif
#ifndef _ResKnife_
#define _ResKnife_
/*!
* @header ResKnife Global Header
* Imported by all ResKnife's C++ source files, this defines various structures and constants which have an application-wide domain.
*/
// compile options
#if TARGET_API_MAC_CARBON
#define USE_NIBS 0 // toggle this
#else
#define USE_NIBS 0 // leave this set to zero
#endif
// include my generic API abbreviations
#include "Generic.h"
/*** STRUCTURES ***/
// type definitions
typedef class ResourceObject ResourceObject, *ResourceObjectPtr;
typedef class PlugObject PlugObject, *PlugObjectPtr;
typedef class WindowObject WindowObject, *WindowObjectPtr;
typedef class FileWindow FileWindow, *FileWindowPtr;
typedef class PlugWindow PlugWindow, *PlugWindowPtr;
typedef class PickerWindow PickerWindow, *PickerWindowPtr;
typedef class EditorWindow EditorWindow, *EditorWindowPtr;
typedef class InspectorWindow InspectorWindow, *InspectorWindowPtr;
/* Global Variables */
struct globals
{
// application
Str255 appName;
Str255 prefsName;
Boolean quitting;
Boolean cancelQuit;
Boolean frontApp;
Boolean asyncSound; // async sound initalised
Boolean callSH; // call sound idle
short appResFile;
Handle emergencyMemory;
EventLoopTimerRef idleTimer; // for SHIdle()
// system info
SInt32 systemVersion;
SInt32 carbonVersion;
Boolean dragAvailable;
Boolean translucentDrag;
Boolean navAvailable;
Boolean appearanceAvailable;
Boolean windowMgrAvailable;
Boolean extendedWindowAttr;
// files
UInt16 tempCount; // number of temporary files opened, so names don't clash
// dialogs
DialogPtr prefsDialog;
Boolean protectPrefs; // if newer version of prefs file exists, will not overwrite
InspectorWindowPtr inspector;
// colours
RGBColor white; // 0xFFFF, 65535
RGBColor bgColour; // 0xEEEE, 61166
RGBColor sortColour; // 0xDDDD, 56797
RGBColor bevelColour; // 0xAAAA, 43690
RGBColor textColour; // 0x7777, 30583
RGBColor frameColour; // 0x5555, 21845
RGBColor black; // 0x0000, 0
// debugging
Boolean debug;
Boolean surpressErrors;
Boolean useAppleEvents;
Boolean useAppearance;
Boolean useNavServices;
Boolean useSheets; // OS X only
};
/*!
* @struct prefs
* @abstract Appplication-wide user preferences
* @discussion Stores all user preferences in memory to avoid needless disk access. This structure is simply written straight to disk when the preferences are saved.
* @field version Identifies which version of ResKnife saved the prefs file (allowing future versions to parse the data contained).
*/
struct prefs
{
UInt32 version; // == kResKnifeCurrentVersion, when saved to disk allows older prefs to be read in
Boolean quitIfNoWindowsAreOpen; // silly name! - perhaps grandmaMode ?
Boolean autoSave;
UInt32 autoSaveInterval; // should be in units of time
Boolean warnOnDelete; // "Are you sure?" dialog, © Microsoft 1992-2000
};
/*** CONSTANTS ***/
// Mac OS versions
const SInt32 kMacOS71 = 0x00000710;
const SInt32 kMacOS755 = 0x00000755;
const SInt32 kMacOS8 = 0x00000800;
const SInt32 kMacOS85 = 0x00000850;
const SInt32 kMacOS86 = 0x00000860;
const SInt32 kMacOS9 = 0x00000900;
const SInt32 kMacOS904 = 0x00000904;
const SInt32 kMacOS91 = 0x00000910;
const SInt32 kMacOS921 = 0x00000921;
const SInt32 kMacOS10 = 0x00001000;
const SInt32 kMacOS101 = 0x00001010;
const SInt32 kMacOSX = kMacOS10;
// CarbonLib versions
const SInt32 kCarbonLib104 = 0x00000104;
const SInt32 kCarbonLib11 = 0x00000110;
const SInt32 kCarbonLib12 = 0x00000120;
const SInt32 kCarbonLib125 = 0x00000125;
const SInt32 kCarbonLib131 = 0x00000131;
const SInt32 kCarbonLib14 = 0x00000140;
const SInt32 kCarbonLib145 = 0x00000145;
// ResKnife version & file types
const UInt32 kCurrentVersion = 0x00040001;
const UInt32 kResKnifeCreator = FOUR_CHAR_CODE('ResK');
const UInt32 kResourceFileType = FOUR_CHAR_CODE('rsrc');
const UInt32 kResourceTransferType = FOUR_CHAR_CODE('rsrc'); // for copy/paste and drags
// memory
const UInt16 kMinimumFreeMemory = 20 * 1024; // if we have over 20 KB we're alright
const UInt16 kEmergencyMemory = 40 * 1024; // 40 KB are put aside for emergencies
// window kinds
enum WindowKind
{
kFileWindowKind = 1,
kPickerWindowKind,
kEditorWindowKind,
kInspectorWindowKind
};
// control sizes
const UInt16 kScrollBarWidth = 16;
/* RESOURCES */
/*!
* @enum Menu Resources
* @discussion Contains all resource IDs for menu items and all ascociated item numbers.
*/
enum // menus
{
kClassicMenuBar = 128,
kAppleMenu = 128,
kAppleMenuAboutItem = 1,
kFileMenu = 129,
kFileMenuNewFileItem = 1,
kFileMenuOpenFileItem,
kFileMenuCloseWindowItem,
kFileMenuQuitItem = 12,
kEditMenu = 130,
kEditMenuClearItem = 7,
kEditMenuPreferencesItem = 13,
kResourceMenu = 131,
kResourceMenuNewResource = 1,
kWindowMenu = 132,
kDebugMenu = 200,
kDebugMenuDebugItem = 1,
kDebugMenuSurpressErrorsItem = 3,
kDebugMenuAppleEventsItem,
kDebugMenuAppearanceItem,
kDebugMenuNavServicesItem,
kDebugMenuSheetsItem
};
enum // application menu
{
kMenuCommandAbout = FOUR_CHAR_CODE('abou')
};
enum // file menu
{
kMenuCommandNewFile = FOUR_CHAR_CODE('new '),
kMenuCommandOpenFile = FOUR_CHAR_CODE('open'),
kMenuCommandCloseWindow = FOUR_CHAR_CODE('clos'),
kMenuCommandCloseFile = FOUR_CHAR_CODE('clsf'),
kMenuCommandSaveFile = FOUR_CHAR_CODE('save'),
kMenuCommandSaveFileAs = FOUR_CHAR_CODE('svas'),
kMenuCommandRevertFile = FOUR_CHAR_CODE('rvtf'),
kMenuCommandPageSetup = FOUR_CHAR_CODE('setu'),
kMenuCommandPrint = FOUR_CHAR_CODE('prin')
};
enum // edit menu
{
kMenuCommandFind = FOUR_CHAR_CODE('find'),
kMenuCommandFindAgain = FOUR_CHAR_CODE('agin')
};
enum // resource menu
{
kMenuCommandNewResource = FOUR_CHAR_CODE('newr'),
kMenuCommandOpenHex = FOUR_CHAR_CODE('hex '),
kMenuCommandOpenDefault = FOUR_CHAR_CODE('edit'),
kMenuCommandOpenTemplate = FOUR_CHAR_CODE('tmpl'),
kMenuCommandOpenSpecific = FOUR_CHAR_CODE('tmp '),
kMenuCommandRevertResource = FOUR_CHAR_CODE('rvtr'),
kMenuCommandPlaySound = FOUR_CHAR_CODE('play')
};
enum // debug menu
{
kMenuCommandDebug = FOUR_CHAR_CODE('dbug'),
kMenuCommandSurpressErrors = FOUR_CHAR_CODE('surp'),
kMenuCommandAppleEvents = FOUR_CHAR_CODE('appl'),
kMenuCommandAppearance = FOUR_CHAR_CODE('appr'),
kMenuCommandNavServices = FOUR_CHAR_CODE('nav '),
kMenuCommandSheets = FOUR_CHAR_CODE('shet')
};
enum // windows
{
kFileWindow7 = 128,
kFileWindow8 = 129
};
enum // dialogs
{
kErrorDialog = 128,
kNewResourceDialog = 129
};
enum // controls
{
kSystem7ScrollBarControl = 128,
kAppearanceScrollBarControl = 129,
kNormalHeaderControl = 130,
kFileHeaderControl = 131,
kEditTextControl = 132
};
enum // icons
{
kSortUpIcon = 921,
kSortDownIcon = 922,
kDefaultResourceIcon = 1000
};
enum // strings
{
kErrorStrings = 128,
kStringUnknownError = 1,
kExplanationUnknownError,
kStringOSNotGoodEnough,
kExplanationOSNotGoodEnough,
kStringMinimumCarbonLib,
kExplanationMinimumCarbonLib,
kStringRecommendedCarbonLib,
kExplanationRecommendedCarbonLib,
kDebugStrings = 129,
kStringRFNotFound = 1,
kExplanationRFNotFound,
kStringDFNotFound,
kExplanationDFNotFound,
kFileNameStrings = 130,
kStringResKnifeName = 1,
kStringPrefsFileName,
kStringNewDragFileName,
kWindowNameStrings = 131,
kStringNewFile = 1,
kStringPrefsWindowName,
kStringInspectorWindowName,
kStringNewResourceDialogName,
kResourceNameStrings = 132,
kStringDataFork = 1,
kStringUntitledResource,
kStringCustomIcon
};
#endif

BIN
Carbon/ResKnife.lib Executable file

Binary file not shown.

View File

@ -0,0 +1 @@
#include "MacTypes.r" /*** CARBON RESOURCES ***/ data 'carb' ( 0 ) { $"00000000" }; data 'plst' ( 0 ) { "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<!DOCTYPE plist SYSTEM \"file://localhost/System/Library/DTDs/PropertyList.dtd\">\n" "<plist version=\"0.9\">\n" "<dict>\n" " <key>CFBundleDevelopmentRegion</key>\n" " <string>English</string>\n" " <key>CFBundleDocumentTypes</key>\n" " <array>\n" " <dict>\n" " <key>CFBundleTypeExtensions</key>\n" " <array>\n" " <string>rsrc</string>\n" " </array>\n" " <key>CFBundleTypeIconFile</key>\n" " <string>129</string>\n" " <key>CFBundleTypeName</key>\n" " <string>Resource file</string>\n" " <key>CFBundleTypeOSTypes</key>\n" " <array>\n" " <string>rsrc</string>\n" " <string>RSRC</string>\n" " </array>\n" " <key>CFBundleTypeRole</key>\n" " <string>Editor</string>\n" " </dict>\n" " <dict>\n" " <key>CFBundleTypeExtensions</key>\n" " <array>\n" " <string>icns</string>\n" " </array>\n" " <key>CFBundleTypeIconFile</key>\n" " <string>129</string>\n" " <key>CFBundleTypeName</key>\n" " <string>Icon file</string>\n" " <key>CFBundleTypeOSTypes</key>\n" " <array>\n" " <string>icns</string>\n" " </array>\n" " <key>CFBundleTypeRole</key>\n" " <string>Editor</string>\n" " </dict>\n" " </array>\n" " <key>CFBundleExecutable</key>\n" " <string>ResKnife (Carbon)</string>\n" " <key>CFBundleGetInfoString</key>\n" " <string>A resource editor for Mac OS X</string>\n" " <key>CFBundleIconFile</key>\n" " <string>128</string>\n" " <key>CFBundleIdentifier</key>\n" " <string>com.nickshanks.resknife</string>\n" " <key>CFBundleInfoDictionaryVersion</key>\n" " <string>6.0</string>\n" " <key>CFBundleName</key>\n" " <string>ResKnife</string>\n" " <key>CFBundlePackageType</key>\n" " <string>APPL</string>\n" " <key>CFBundleShortVersionString</key>\n" " <string>Development version 0.4d1</string>\n" " <key>CFBundleSignature</key>\n" " <string>ResK</string>\n" " <key>CFBundleVersion</key>\n" " <string>0.4d1</string>\n" " <key>CSResourcesFileMapped</key>\n" " <true/>\n" "</dict>\n" "</plist>" };

295
Carbon/Resources/ResKnife.nib/classes.nib generated Normal file
View File

@ -0,0 +1,295 @@
{
IBClasses = (
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
{CLASS = IBCarbonBevelButton; LANGUAGE = ObjC; SUPERCLASS = IBCarbonControl; },
{CLASS = IBCarbonButton; LANGUAGE = ObjC; SUPERCLASS = IBCarbonControl; },
{
CLASS = IBCarbonChasingArrows;
LANGUAGE = ObjC;
OUTLETS = {
carbonBounds = id;
command = id;
controlHandle = id;
controlID = id;
controlMaximum = id;
controlMinimum = id;
controlName = id;
controlSignature = id;
controlSize = id;
controlTitle = id;
controlValue = id;
enabled = id;
hidden = id;
isEnabled = id;
isHidden = id;
objectNameForInspectorTitle = id;
targetFrameworkName = id;
targetFrameworkSupportsConnections = id;
titleRect = id;
};
SUPERCLASS = IBCarbonControl;
},
{CLASS = IBCarbonCheckBox; LANGUAGE = ObjC; SUPERCLASS = IBCarbonControl; },
{
CLASS = IBCarbonClockDate;
LANGUAGE = ObjC;
OUTLETS = {
carbonBounds = id;
clockType = id;
command = id;
controlHandle = id;
controlID = id;
controlMaximum = id;
controlMinimum = id;
controlName = id;
controlSignature = id;
controlSize = id;
controlTitle = id;
controlValue = id;
enabled = id;
hidden = id;
isEditable = id;
isEnabled = id;
isHidden = id;
isLive = id;
objectNameForInspectorTitle = id;
targetFrameworkName = id;
targetFrameworkSupportsConnections = id;
titleRect = id;
};
SUPERCLASS = IBCarbonControl;
},
{
CLASS = IBCarbonControl;
LANGUAGE = ObjC;
OUTLETS = {
carbonBounds = id;
command = id;
controlHandle = id;
controlID = id;
controlMaximum = id;
controlMinimum = id;
controlName = id;
controlSignature = id;
controlSize = id;
controlTitle = id;
controlValue = id;
enabled = id;
hidden = id;
isEnabled = id;
isHidden = id;
objectNameForInspectorTitle = id;
targetFrameworkName = id;
targetFrameworkSupportsConnections = id;
titleRect = id;
};
SUPERCLASS = NSObject;
},
{
CLASS = IBCarbonDBListView;
LANGUAGE = ObjC;
SUPERCLASS = IBCarbonDataBrowser;
},
{CLASS = IBCarbonDataBrowser; LANGUAGE = ObjC; SUPERCLASS = IBCarbonControl; },
{CLASS = IBCarbonEditText; LANGUAGE = ObjC; SUPERCLASS = IBCarbonControl; },
{
CLASS = IBCarbonGroupBox;
LANGUAGE = ObjC;
OUTLETS = {
autoToggle = id;
carbonBounds = id;
command = id;
contentRect = id;
controlHandle = id;
controlID = id;
controlMaximum = id;
controlMinimum = id;
controlName = id;
controlSignature = id;
controlSize = id;
controlTitle = id;
controlValue = id;
enabled = id;
groupBoxTitleType = id;
groupBoxType = id;
hasVariableWidth = id;
hidden = id;
isAutoToggle = id;
isEnabled = id;
isHidden = id;
isPrimary = id;
objectNameForInspectorTitle = id;
primary = id;
selectedItem = id;
supportsInsideOutSelection = id;
targetFrameworkName = id;
targetFrameworkSupportsConnections = id;
titleJustification = id;
titleRect = id;
variableWidth = id;
};
SUPERCLASS = IBCarbonControl;
},
{
CLASS = IBCarbonIcon;
LANGUAGE = ObjC;
OUTLETS = {
carbonBounds = id;
command = id;
contentResID = id;
contentType = id;
controlHandle = id;
controlID = id;
controlMaximum = id;
controlMinimum = id;
controlName = id;
controlSignature = id;
controlSize = id;
controlTitle = id;
controlValue = id;
dontTrack = id;
enabled = id;
hidden = id;
isEnabled = id;
isHidden = id;
objectNameForInspectorTitle = id;
targetFrameworkName = id;
targetFrameworkSupportsConnections = id;
titleRect = id;
};
SUPERCLASS = IBCarbonControl;
},
{CLASS = IBCarbonImageWell; LANGUAGE = ObjC; SUPERCLASS = IBCarbonControl; },
{
CLASS = IBCarbonLittleArrows;
LANGUAGE = ObjC;
OUTLETS = {
carbonBounds = id;
command = id;
controlHandle = id;
controlID = id;
controlMaximum = id;
controlMinimum = id;
controlName = id;
controlSignature = id;
controlSize = id;
controlTitle = id;
controlValue = id;
enabled = id;
hidden = id;
increment = id;
initialValue = id;
isEnabled = id;
isHidden = id;
maximumValue = id;
minimumValue = id;
objectNameForInspectorTitle = id;
targetFrameworkName = id;
targetFrameworkSupportsConnections = id;
titleRect = id;
};
SUPERCLASS = IBCarbonControl;
},
{CLASS = IBCarbonMenu; LANGUAGE = ObjC; SUPERCLASS = NSMenu; },
{CLASS = IBCarbonMenuItem; LANGUAGE = ObjC; SUPERCLASS = NSMenuItem; },
{CLASS = IBCarbonPopupButton; LANGUAGE = ObjC; SUPERCLASS = IBCarbonControl; },
{CLASS = IBCarbonRadioGroup; LANGUAGE = ObjC; SUPERCLASS = IBCarbonControl; },
{CLASS = IBCarbonRelevanceBar; LANGUAGE = ObjC; SUPERCLASS = IBCarbonControl; },
{CLASS = IBCarbonRootControl; LANGUAGE = ObjC; SUPERCLASS = IBCarbonControl; },
{CLASS = IBCarbonRoundButton; LANGUAGE = ObjC; SUPERCLASS = IBCarbonControl; },
{CLASS = IBCarbonScrollBar; LANGUAGE = ObjC; SUPERCLASS = IBCarbonControl; },
{
CLASS = IBCarbonSeparator;
LANGUAGE = ObjC;
OUTLETS = {
carbonBounds = id;
command = id;
controlHandle = id;
controlID = id;
controlMaximum = id;
controlMinimum = id;
controlName = id;
controlSignature = id;
controlSize = id;
controlTitle = id;
controlValue = id;
enabled = id;
hidden = id;
isEnabled = id;
isHidden = id;
objectNameForInspectorTitle = id;
targetFrameworkName = id;
targetFrameworkSupportsConnections = id;
titleRect = id;
};
SUPERCLASS = IBCarbonControl;
},
{
CLASS = IBCarbonSlider;
LANGUAGE = ObjC;
OUTLETS = {
carbonBounds = id;
command = id;
controlHandle = id;
controlID = id;
controlMaximum = id;
controlMinimum = id;
controlName = id;
controlSignature = id;
controlSize = id;
controlTitle = id;
controlValue = id;
enabled = id;
hidden = id;
initialValue = id;
isEnabled = id;
isHidden = id;
isLive = id;
maximumValue = id;
minimumValue = id;
numTickMarks = id;
objectNameForInspectorTitle = id;
orientation = id;
targetFrameworkName = id;
targetFrameworkSupportsConnections = id;
titleRect = id;
};
SUPERCLASS = IBCarbonControl;
},
{CLASS = IBCarbonStaticText; LANGUAGE = ObjC; SUPERCLASS = IBCarbonControl; },
{CLASS = IBCarbonTab; LANGUAGE = ObjC; SUPERCLASS = IBCarbonControl; },
{
CLASS = IBCarbonTriangle;
LANGUAGE = ObjC;
OUTLETS = {
autoToggle = id;
carbonBounds = id;
collapsed = id;
command = id;
controlHandle = id;
controlID = id;
controlMaximum = id;
controlMinimum = id;
controlName = id;
controlSignature = id;
controlSize = id;
controlTitle = id;
controlValue = id;
drawTitle = id;
enabled = id;
hidden = id;
isCollapsed = id;
isEnabled = id;
isHidden = id;
objectNameForInspectorTitle = id;
orientation = id;
targetFrameworkName = id;
targetFrameworkSupportsConnections = id;
titleRect = id;
};
SUPERCLASS = IBCarbonControl;
},
{CLASS = IBCarbonUserPane; LANGUAGE = ObjC; SUPERCLASS = IBCarbonControl; }
);
IBVersion = 1;
}

50
Carbon/Resources/ResKnife.nib/info.nib generated Normal file
View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="0.9">
<dict>
<key>IBDocumentLocation</key>
<string>70 160 588 603 0 73 1152 775 </string>
<key>IBMainMenuLocation</key>
<string>157 692 404 44 0 72 1024 674 </string>
<key>IBUserGuides</key>
<dict>
<key>About Box</key>
<dict>
<key>guideLocations</key>
<array/>
<key>guidesLocked</key>
<string>NO</string>
</dict>
<key>File Window</key>
<dict>
<key>guideLocations</key>
<array/>
<key>guidesLocked</key>
<string>NO</string>
</dict>
<key>Inspector</key>
<dict>
<key>guideLocations</key>
<array/>
<key>guidesLocked</key>
<string>NO</string>
</dict>
<key>New Resource</key>
<dict>
<key>guideLocations</key>
<array/>
<key>guidesLocked</key>
<string>NO</string>
</dict>
<key>Preferences</key>
<dict>
<key>guideLocations</key>
<array/>
<key>guidesLocked</key>
<string>NO</string>
</dict>
</dict>
<key>targetFramework</key>
<string>IBCarbonFramework</string>
</dict>
</plist>

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

35
Carbon/Transfer.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef _ResKnife_Transfer_
#define _ResKnife_Transfer_
/*!
@header Transfer
@discussion Declares the structure used for intra- and inter-application data transfer. All modern resource editors support this structure, and ResKnife handles both copy & paste and drag & drop transfer methods.
*/
/*!
@class ResTransferDesc
@discussion Useful for interaplication data transfer.
*/
typedef class
{
/*! @var version Should be kResTransferDescCurrentVersion. */
UInt16 version;
/*! @var resType Type of resource being copied/dragged. */
ResType resType;
/*! @var resID ID of resource being copied/dragged. */
SInt16 resID;
/*! @var resFlags Flags (attributes) of this resource. */
UInt16 resFlags;
/*! @var resName Name of this resource. */
Str255 resName;
/*! @var hostApp Creator of application that this copy/drag started from. */
OSType hostApp;
/*! @var hostData Data for private use by host. */
UInt32 hostData[4];
/*! @var dataSize Size of resource data. */
UInt32 dataSize;
/*! @var data Variably-sized array with resource data. */
UInt8 data[kVariableLengthArray]; // bug: zero-length resources do weird shit
} ResTransferDesc, *ResTransferPtr;
#endif

View File

@ -0,0 +1,14 @@
#import <Cocoa/Cocoa.h>
@interface ApplicationDelegate : NSObject
{
}
- (IBAction)showInfo:(id)sender;
- (IBAction)showPrefs:(id)sender;
- (IBAction)showCreateResourceSheet:(id)sender;
- (IBAction)openResource:(id)sender;
- (IBAction)playSound:(id)sender;
- (void)initUserDefaults;
@end

View File

@ -0,0 +1,91 @@
#import "ApplicationDelegate.h"
#import "InfoWindowController.h"
#import "PrefsWindowController.h"
#import "ResourceDataSource.h"
#import "CreateResourceSheetController.h"
@implementation ApplicationDelegate
- (id)init
{
self = [super init];
[NSApp registerServicesMenuSendTypes:[NSArray arrayWithObject:@"NSString"] returnTypes:[NSArray arrayWithObject:@"NSString"]];
return self;
}
- (void)awakeFromNib
{
// Part of my EvilPlanª to find out how many people use ResKnife and how often!
int launchCount = [[NSUserDefaults standardUserDefaults] integerForKey:@"LaunchCount"];
[[NSUserDefaults standardUserDefaults] setInteger:launchCount + 1 forKey:@"LaunchCount"];
[self initUserDefaults];
}
- (IBAction)showInfo:(id)sender
{
[[InfoWindowController sharedInfoWindowController] showWindow:sender];
}
- (IBAction)showPrefs:(id)sender
{
[[PrefsWindowController sharedPrefsWindowController] showWindow:sender];
}
- (IBAction)showCreateResourceSheet:(id)sender
{
// bug: requires ALL main window's delegates to have 'dataSource' declared,
// would be better to use a resourceDocument variable which could point to self for document windows.
return [[[[[NSApp mainWindow] delegate] dataSource] createResourceSheetController] showCreateResourceSheet:sender];
}
- (IBAction)openResource:(id)sender
{
// [NSBundle loadNibNamed:@"HexWindow" owner:self];
//- (NSString *)pathForAuxiliaryExecutable:(NSString *)executableName;
// [[NSBundle bundleWithIdentifier:@"com.nickshanks.resknife.hexadecimal"] load];
[[NSBundle bundleWithPath:[[[NSBundle mainBundle] builtInPlugInsPath] stringByAppendingPathComponent:@"HexEditor.plugin"]] load];
}
- (IBAction)playSound:(id)sender
{
}
- (void)initUserDefaults
{
// This should probably be added to NSUserDefaults as a category,
// since its universally useful. It loads a defaults.plist file
// from the app wrapper, and then sets the defaults if they don't
// already exist.
NSUserDefaults *defaults;
NSDictionary *defaultsPlist;
NSEnumerator *overDefaults;
id eachDefault;
// this isn't required, but saves us a few method calls
defaults = [NSUserDefaults standardUserDefaults];
// load the defaults.plist from the app wrapper. This makes it
// easy to add new defaults just using a text editor instead of
// hard-coding them into the application
defaultsPlist = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"defaults" ofType:@"plist"]];
// enumerate over all the keys in the dictionary
overDefaults = [[defaultsPlist allKeys] objectEnumerator];
while( eachDefault = [overDefaults nextObject] )
{
// for each key in the dictionary
// check if there is a value already registered for it
// and if there isn't, then register the value that was in the file
if( ![defaults stringForKey:eachDefault] )
{
[defaults setObject:[defaultsPlist objectForKey:eachDefault] forKey:eachDefault];
}
}
// force the defaults to save to the disk
[defaults synchronize];
}
@end

View File

@ -0,0 +1,13 @@
#import <Foundation/Foundation.h>
@interface AttributesFormatter : NSFormatter
{
}
- (NSString *)stringForObjectValue:(id)obj;
- (NSAttributedString *)attributedStringForObjectValue:(id)obj withDefaultAttributes:(NSDictionary *)attrs;
- (NSString *)editingStringForObjectValue:(id)obj;
- (BOOL)getObjectValue:(id *)obj forString:(NSString *)string errorDescription:(NSString **)error;
- (BOOL)isPartialStringValid:(NSString *)partialString newEditingString:(NSString **)newString errorDescription:(NSString **)error;
@end

View File

@ -0,0 +1,65 @@
#import "AttributesFormatter.h"
#import <Carbon/Carbon.h>
@implementation AttributesFormatter
- (NSString *)stringForObjectValue:(id)obj
{
BOOL addComma = NO;
short attributes = [obj shortValue];
NSMutableString *string = [NSMutableString string];
if( attributes & resPreload )
{
if( addComma ) [string appendString:@", "];
[string appendString:@"Preload"];
addComma = YES;
}
if( attributes & resProtected )
{
if( addComma ) [string appendString:@", "];
[string appendString:@"Protected"];
addComma = YES;
}
if( attributes & resLocked )
{
if( addComma ) [string appendString:@", "];
[string appendString:@"Locked"];
addComma = YES;
}
if( attributes & resPurgeable )
{
if( addComma ) [string appendString:@", "];
[string appendString:@"Purgeable"];
addComma = YES;
}
if( attributes & resSysHeap )
{
if( addComma ) [string appendString:@", "];
[string appendString:@"SysHeap"];
addComma = YES;
}
return string;
}
- (NSAttributedString *)attributedStringForObjectValue:(id)obj withDefaultAttributes:(NSDictionary *)attrs
{
NSString *string = [self stringForObjectValue:obj];
return [[NSAttributedString alloc] initWithString:string attributes:attrs];
}
- (NSString *)editingStringForObjectValue:(id)obj
{
return nil;
}
- (BOOL)getObjectValue:(id *)obj forString:(NSString *)string errorDescription:(NSString **)error
{
return NO;
}
- (BOOL)isPartialStringValid:(NSString *)partialString newEditingString:(NSString **)newString errorDescription:(NSString **)error
{
return NO;
}
@end

View File

@ -0,0 +1,21 @@
#import <Cocoa/Cocoa.h>
#import "ResourceDataSource.h"
@interface CreateResourceSheetController : NSWindowController
{
IBOutlet ResourceDataSource *dataSource;
IBOutlet NSMatrix *attributesMatrix;
IBOutlet NSButton *cancelButton;
IBOutlet NSButton *createButton;
IBOutlet NSTextField *nameView;
IBOutlet NSTextField *resIDView;
IBOutlet NSTextField *typeView;
IBOutlet NSPopUpButton *typePopup;
IBOutlet NSWindow *parent;
}
- (IBAction)showCreateResourceSheet:(id)sender;
- (IBAction)hideCreateResourceSheet:(id)sender;
- (IBAction)typePopupSelection:(id)sender;
@end

View File

@ -0,0 +1,32 @@
#import "CreateResourceSheetController.h"
#import <Carbon/Carbon.h>
@implementation CreateResourceSheetController
- (IBAction)showCreateResourceSheet:(id)sender
{
[NSApp beginSheet:[self window] modalForWindow:parent modalDelegate:self didEndSelector:NULL contextInfo:nil];
}
- (IBAction)hideCreateResourceSheet:(id)sender
{
if( sender == createButton )
{
unsigned short attributes = 0;
attributes ^= [[attributesMatrix cellAtRow:0 column:0] intValue]? resPreload:0;
attributes ^= [[attributesMatrix cellAtRow:1 column:0] intValue]? resPurgeable:0;
attributes ^= [[attributesMatrix cellAtRow:2 column:0] intValue]? resLocked:0;
attributes ^= [[attributesMatrix cellAtRow:0 column:1] intValue]? resSysHeap:0;
attributes ^= [[attributesMatrix cellAtRow:1 column:1] intValue]? resProtected:0;
[dataSource addResource:[Resource resourceOfType:[typeView stringValue] andID:[NSNumber numberWithShort:(short) [resIDView intValue]] withName:[nameView stringValue] andAttributes:[NSNumber numberWithUnsignedShort:attributes]]];
}
[[self window] orderOut:nil];
[NSApp endSheet:[self window]];
}
- (IBAction)typePopupSelection:(id)sender
{
}
@end

View File

@ -0,0 +1,6 @@
#import <Cocoa/Cocoa.h>
@interface InfoWindow : NSPanel
{
}
@end

View File

@ -0,0 +1,15 @@
#import "InfoWindow.h"
@implementation InfoWindow
- (BOOL)canBecomeKeyWindow
{
return NO;
}
- (BOOL)canBecomeMainWindow
{
return NO;
}
@end

View File

@ -0,0 +1,34 @@
#import <Cocoa/Cocoa.h>
@class ResourceDocument, Resource;
enum Attributes
{
changedBox = 0,
preloadBox,
protectedBox,
lockedBox,
purgableBox,
systemHeapBox
};
@interface InfoWindowController : NSWindowController
{
IBOutlet NSMatrix *attributesMatrix;
IBOutlet NSImageView *iconView;
IBOutlet NSTextField *nameView;
IBOutlet NSTextField *resIDView;
IBOutlet NSTextField *typeView;
@private
ResourceDocument *currentDocument;
Resource *selectedResource;
}
- (void)updateInfoWindow;
- (void)setMainWindow:(NSWindow *)mainWindow;
- (IBAction)attributesChanged:(id)sender;
+ (id)sharedInfoWindowController;
@end

View File

@ -0,0 +1,102 @@
#import "InfoWindowController.h"
#import <Carbon/Carbon.h> // Actually I only need CarbonCore.framework, but <Carbon/CarbonCore.h> and <CarbonCore/CarbonCore.h> don't work, so I don't know what else to do
#import "ResourceDocument.h"
#import "Resource.h"
@implementation InfoWindowController
- (id)init
{
self = [self initWithWindowNibName:@"InfoWindow"];
if( self ) [self setWindowFrameAutosaveName:@"Resource Info"];
return self;
}
- (void)windowDidLoad
{
[super windowDidLoad];
[self setMainWindow:[NSApp mainWindow]];
[self updateInfoWindow];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mainWindowChanged:) name:NSWindowDidBecomeMainNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(selectedResourceChanged:) name:NSOutlineViewSelectionDidChangeNotification object:nil];
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
- (void)updateInfoWindow
{
if( selectedResource )
{
[nameView setStringValue:[selectedResource name]];
[typeView setStringValue:[selectedResource type]];
[resIDView setStringValue:[[selectedResource resID] stringValue]];
[[attributesMatrix cellAtRow:changedBox column:0] setState:[[selectedResource attributes] shortValue] & resChanged];
[[attributesMatrix cellAtRow:preloadBox column:0] setState:[[selectedResource attributes] shortValue] & resPreload];
[[attributesMatrix cellAtRow:protectedBox column:0] setState:[[selectedResource attributes] shortValue] & resProtected];
[[attributesMatrix cellAtRow:lockedBox column:0] setState:[[selectedResource attributes] shortValue] & resLocked];
[[attributesMatrix cellAtRow:purgableBox column:0] setState:[[selectedResource attributes] shortValue] & resPurgeable];
[[attributesMatrix cellAtRow:systemHeapBox column:0] setState:[[selectedResource attributes] shortValue] & resSysHeap];
}
else
{
[nameView setStringValue:@""];
[typeView setStringValue:@""];
[resIDView setStringValue:@""];
[[attributesMatrix cellAtRow:changedBox column:0] setState:NSOffState];
[[attributesMatrix cellAtRow:preloadBox column:0] setState:NSOffState];
[[attributesMatrix cellAtRow:protectedBox column:0] setState:NSOffState];
[[attributesMatrix cellAtRow:lockedBox column:0] setState:NSOffState];
[[attributesMatrix cellAtRow:purgableBox column:0] setState:NSOffState];
[[attributesMatrix cellAtRow:systemHeapBox column:0] setState:NSOffState];
}
}
- (void)setMainWindow:(NSWindow *)mainWindow
{
NSWindowController *controller = [mainWindow windowController];
if( [[controller document] isKindOfClass:[ResourceDocument class]] )
currentDocument = [controller document];
else currentDocument = nil;
selectedResource = [[currentDocument outlineView] itemAtRow:[[currentDocument outlineView] selectedRow]];
[self updateInfoWindow];
}
- (void)mainWindowChanged:(NSNotification *)notification
{
[self setMainWindow:[notification object]];
}
- (void)selectedResourceChanged:(NSNotification *)notification
{
selectedResource = [[notification object] itemAtRow:[[notification object] selectedRow]];
[self updateInfoWindow];
}
- (IBAction)attributesChanged:(id)sender
{
short attr = 0x0001 << [sender selectedRow]+1;
short number = ([[selectedResource attributes] shortValue] ^ attr);
[selectedResource setAttributes:[NSNumber numberWithShort:number]];
[self updateInfoWindow];
}
+ (id)sharedInfoWindowController
{
static InfoWindowController *sharedInfoWindowController = nil;
if( !sharedInfoWindowController )
{
sharedInfoWindowController = [[InfoWindowController allocWithZone:[self zone]] init];
}
return sharedInfoWindowController;
}
@end

View File

@ -0,0 +1,13 @@
#import <Foundation/Foundation.h>
@interface NameFormatter : NSFormatter
{
}
- (NSString *)stringForObjectValue:(id)obj;
- (NSAttributedString *)attributedStringForObjectValue:(id)obj withDefaultAttributes:(NSDictionary *)attrs;
- (NSString *)editingStringForObjectValue:(id)obj;
- (BOOL)getObjectValue:(id *)obj forString:(NSString *)string errorDescription:(NSString **)error;
- (BOOL)isPartialStringValid:(NSString *)partialString newEditingString:(NSString **)newString errorDescription:(NSString **)error;
@end

View File

@ -0,0 +1,41 @@
#import "NameFormatter.h"
#import <AppKit/NSColor.h>
@implementation NameFormatter
- (NSString *)stringForObjectValue:(id)obj
{
if( ![obj isKindOfClass:[NSString class]] ) return nil;
if( [obj isEqualToString:@""] )
{
if( NO ) return NSLocalizedString( @"Custom Icon", nil );
else return NSLocalizedString( @"Untitled Resource", nil );
}
else return obj;
}
- (NSAttributedString *)attributedStringForObjectValue:(id)obj withDefaultAttributes:(NSDictionary *)attrs
{
NSString *string = [self stringForObjectValue:obj];
if( [obj isEqualToString:@""] )
return [[NSAttributedString alloc] initWithString:string attributes:[NSDictionary dictionaryWithObject:[NSColor grayColor] forKey:@"NSColor"]];
else return [[NSAttributedString alloc] initWithString:string attributes:attrs];
}
- (NSString *)editingStringForObjectValue:(id)obj
{
return obj;
}
- (BOOL)getObjectValue:(id *)obj forString:(NSString *)string errorDescription:(NSString **)error
{
*obj = string;
return YES;
}
- (BOOL)isPartialStringValid:(NSString *)partialString newEditingString:(NSString **)newString errorDescription:(NSString **)error
{
return YES;
}
@end

View File

@ -0,0 +1,13 @@
#import <Cocoa/Cocoa.h>
#import "NameFormatter.h"
#import "SizeFormatter.h"
#import "AttributesFormatter.h"
@interface OutlineViewDelegate : NSObject
{
IBOutlet NSWindow *window;
IBOutlet NameFormatter *nameFormatter;
IBOutlet SizeFormatter *sizeFormatter;
IBOutlet AttributesFormatter *attributesFormatter;
}
@end

View File

@ -0,0 +1,20 @@
#import "OutlineViewDelegate.h"
@implementation OutlineViewDelegate
- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
NSTableColumn *nameColumn = [outlineView tableColumnWithIdentifier:@"name"];
NSTableColumn *sizeColumn = [outlineView tableColumnWithIdentifier:@"size"];
NSTableColumn *attributesColumn = [outlineView tableColumnWithIdentifier:@"attributes"];
if( [tableColumn isEqual:nameColumn] ) [cell setFormatter:nameFormatter];
else if( [tableColumn isEqual:sizeColumn] ) [cell setFormatter:sizeFormatter];
else if( [tableColumn isEqual:attributesColumn] ) [cell setFormatter:attributesFormatter];
}
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
return YES;
}
@end

View File

@ -0,0 +1,22 @@
#import <Cocoa/Cocoa.h>
enum DataProtection
{
preserveBackupsBox = 0,
autosaveBox,
deleteResourceWarningBox
};
@interface PrefsWindowController : NSWindowController
{
IBOutlet NSTextField *autosaveIntervalField;
IBOutlet NSMatrix *dataProtectionMatrix;
}
- (IBAction)acceptPrefs:(id)sender;
- (IBAction)cancelPrefs:(id)sender;
- (IBAction)resetToDefault:(id)sender;
+ (id)sharedPrefsWindowController;
@end

View File

@ -0,0 +1,93 @@
#import "PrefsWindowController.h"
@implementation PrefsWindowController
- (id)init
{
self = [self initWithWindowNibName:@"PrefsWindow"];
if( self ) [self setWindowFrameAutosaveName:@"ResKnife Preferences"];
return self;
}
- (void)awakeFromNib
{
// load preferencesÉ
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
BOOL preserveBackups = [defaults boolForKey:@"PreserveBackups"];
BOOL autosave = [defaults boolForKey:@"Autosave"];
int autosaveInterval = [defaults integerForKey:@"AutosaveInterval"];
BOOL deleteResourceWarning = [defaults boolForKey:@"DeleteResourceWarning"];
// Éand set widgets accordingly
[[dataProtectionMatrix cellAtRow:preserveBackupsBox column:0] setState:preserveBackups];
[[dataProtectionMatrix cellAtRow:autosaveBox column:0] setState:autosave];
[autosaveIntervalField setStringValue:[NSString stringWithFormat:@"%d", autosaveInterval]];
[[dataProtectionMatrix cellAtRow:deleteResourceWarningBox column:0] setState:deleteResourceWarning];
}
- (IBAction)acceptPrefs:(id)sender
{
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
BOOL preserveBackups = [[dataProtectionMatrix cellAtRow:preserveBackupsBox column:0] intValue]? YES:NO;
BOOL autosave = [[dataProtectionMatrix cellAtRow:autosaveBox column:0] intValue]? YES:NO;
int autosaveInterval = [autosaveIntervalField intValue];
BOOL deleteResourceWarning = [[dataProtectionMatrix cellAtRow:deleteResourceWarningBox column:0] intValue]? YES:NO;
// hide the window
[[self window] orderOut:nil];
// now save the data to the defaults file
[defaults setBool:preserveBackups forKey:@"PreserveBackups"]; // bug: this put 1 or 0 into the defaults file rather than YES or NO
[defaults setBool:autosave forKey:@"Autosave"];
[defaults setInteger:autosaveInterval forKey:@"AutosaveInterval"];
[defaults setBool:deleteResourceWarning forKey:@"DeleteResourceWarning"];
[defaults synchronize];
}
- (IBAction)cancelPrefs:(id)sender
{
// load saved defaults
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
BOOL preserveBackups = [defaults boolForKey:@"PreserveBackups"];
BOOL autosave = [defaults boolForKey:@"Autosave"];
int autosaveInterval = [defaults integerForKey:@"AutosaveInterval"];
BOOL deleteResourceWarning = [defaults boolForKey:@"DeleteResourceWarning"];
// hide the window
[[self window] orderOut:nil];
// and reset dialog to match
[[dataProtectionMatrix cellAtRow:preserveBackupsBox column:0] setState:preserveBackups];
[[dataProtectionMatrix cellAtRow:autosaveBox column:0] setState:autosave];
[autosaveIntervalField setStringValue:[NSString stringWithFormat:@"%d", autosaveInterval]];
[[dataProtectionMatrix cellAtRow:deleteResourceWarningBox column:0] setState:deleteResourceWarning];
}
- (IBAction)resetToDefault:(id)sender
{
// reset prefs window widgets to values stored in defaults.plist file
NSDictionary *defaultsPlist = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"defaults" ofType:@"plist"]];
BOOL preserveBackups = [[defaultsPlist objectForKey:@"PreserveBackups"] intValue]? YES:NO; // bug: this always evaluates to NO, even if the object in the dictionary is YES
BOOL autosave = [[defaultsPlist objectForKey:@"Autosave"] intValue]? YES:NO;
int autosaveInterval = [[defaultsPlist objectForKey:@"AutosaveInterval"] intValue];
BOOL deleteResourceWarning = [[defaultsPlist objectForKey:@"DeleteResourceWarning"] intValue]? YES:NO;
// note that this function does notmodify the user defaults - the user still has to accept or cancel the panel
[[dataProtectionMatrix cellAtRow:preserveBackupsBox column:0] setState:preserveBackups];
[[dataProtectionMatrix cellAtRow:autosaveBox column:0] setState:autosave];
[autosaveIntervalField setStringValue:[NSString stringWithFormat:@"%d", autosaveInterval]];
[[dataProtectionMatrix cellAtRow:deleteResourceWarningBox column:0] setState:deleteResourceWarning];
}
+ (id)sharedPrefsWindowController
{
static PrefsWindowController *sharedPrefsWindowController = nil;
if( !sharedPrefsWindowController )
{
sharedPrefsWindowController = [[PrefsWindowController allocWithZone:[self zone]] init];
}
return sharedPrefsWindowController;
}
@end

44
Cocoa/Classes/Resource.h Normal file
View File

@ -0,0 +1,44 @@
#import <Foundation/Foundation.h>
extern NSString *ResourceChangedNotification;
@interface Resource : NSObject
{
// resource information
NSString *name;
NSString *type;
NSNumber *resID; // signed short
NSNumber *size; // unsigned long
NSNumber *attributes; // unsigned short
// flags
BOOL dirty;
// the actual data
NSData *data;
}
- (NSString *)name;
- (void)setName:(NSString *)newName;
- (NSString *)type;
- (void)setType:(NSString *)newType;
- (NSNumber *)resID;
- (void)setResID:(NSNumber *)newResID;
- (NSNumber *)size;
- (void)setSize:(NSNumber *)newSize;
- (NSNumber *)attributes;
- (void)setAttributes:(NSNumber *)newAttributes;
- (BOOL)dirty;
- (void)setDirty:(BOOL)newValue;
- (NSData *)data;
- (void)setData:(NSData *)newData;
- (id)initWithType:(NSString *)typeValue andID:(NSNumber *)resIDValue;
- (id)initWithType:(NSString *)typeValue andID:(NSNumber *)resIDValue withName:(NSString *)nameValue andAttributes:(NSNumber *)attributesValue;
- (id)initWithType:(NSString *)typeValue andID:(NSNumber *)resIDValue withName:(NSString *)nameValue andAttributes:(NSNumber *)attributesValue data:(NSData *)dataValue ofLength:(NSNumber *)sizeValue;
+ (id)resourceOfType:(NSString *)typeValue andID:(NSNumber *)resIDValue;
+ (id)resourceOfType:(NSString *)typeValue andID:(NSNumber *)resIDValue withName:(NSString *)nameValue andAttributes:(NSNumber *)attributesValue;
+ (id)resourceOfType:(NSString *)typeValue andID:(NSNumber *)resIDValue withName:(NSString *)nameValue andAttributes:(NSNumber *)attributesValue data:(NSData *)dataValue ofLength:(NSNumber *)sizeValue;
@end

155
Cocoa/Classes/Resource.m Normal file
View File

@ -0,0 +1,155 @@
#import "Resource.h"
@implementation Resource
NSString *ResourceChangedNotification = @"ResourceChangedNotification";
- (id)init
{
self = [super init];
[self initWithType:@"" andID:[NSNumber numberWithShort:128]];
return self;
}
- (void)dealloc
{
[name release];
[type release];
[resID release];
[size release];
[attributes release];
[data release];
[super dealloc];
}
- (NSString *)name
{
return name;
}
- (void)setName:(NSString *)newName
{
[name autorelease];
name = [newName copy];
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceChangedNotification object:self];
// NSLog( @"%@ posted beacause name changed to %@", ResourceChangedNotification, name );
}
- (NSString *)type
{
return type;
}
- (void)setType:(NSString *)newType
{
[type autorelease];
type = [newType copy];
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceChangedNotification object:self];
// NSLog( @"%@ posted beacause type changed to %@", ResourceChangedNotification, type );
}
- (NSNumber *)resID
{
return resID;
}
- (void)setResID:(NSNumber *)newResID
{
[resID autorelease];
resID = [newResID copy];
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceChangedNotification object:self];
// NSLog( @"%@ posted beacause res ID changed to %@", ResourceChangedNotification, [resID stringValue] );
}
- (NSNumber *)size
{
return size;
}
- (void)setSize:(NSNumber *)newSize
{
[size autorelease];
size = [newSize copy];
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceChangedNotification object:self];
// NSLog( @"%@ posted beacause size changed to %@", ResourceChangedNotification, [size stringValue] );
}
- (NSNumber *)attributes
{
return attributes;
}
- (void)setAttributes:(NSNumber *)newAttributes
{
[attributes autorelease];
attributes = [newAttributes copy];
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceChangedNotification object:self];
// NSLog( @"%@ posted beacause attributes changed to %@", ResourceChangedNotification, [attributes stringValue] );
}
- (BOOL)dirty
{
return dirty;
}
- (void)setDirty:(BOOL)newValue
{
dirty = newValue;
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceChangedNotification object:self];
// NSLog( @"%@ posted beacause resource became %@", ResourceChangedNotification, dirty? @"dirty":@"clean" );
}
- (NSData *)data
{
return data;
}
- (void)setData:(NSData *)newData
{
[data autorelease];
data = [newData retain];
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceChangedNotification object:self];
// NSLog( @"%@ posted beacause data changed", ResourceChangedNotification );
}
- (id)initWithType:(NSString *)typeValue andID:(NSNumber *)resIDValue
{
[self initWithType:typeValue andID:resIDValue withName:@"" andAttributes:[NSNumber numberWithUnsignedShort:0]];
return self;
}
- (id)initWithType:(NSString *)typeValue andID:(NSNumber *)resIDValue withName:(NSString *)nameValue andAttributes:(NSNumber *)attributesValue
{
[self initWithType:typeValue andID:resIDValue withName:nameValue andAttributes:attributesValue data:[NSData data] ofLength:[NSNumber numberWithUnsignedLong:0]];
return self;
}
- (id)initWithType:(NSString *)typeValue andID:(NSNumber *)resIDValue withName:(NSString *)nameValue andAttributes:(NSNumber *)attributesValue data:(NSData *)dataValue ofLength:(NSNumber *)sizeValue
{
[super init];
[self setName:nameValue];
[self setType:typeValue];
[self setResID:resIDValue];
[self setSize:sizeValue];
[self setAttributes:attributesValue];
[self setData:dataValue];
return self;
}
+ (id)resourceOfType:(NSString *)typeValue andID:(NSNumber *)resIDValue
{
return [[Resource allocWithZone:[self zone]] initWithType:typeValue andID:resIDValue];
}
+ (id)resourceOfType:(NSString *)typeValue andID:(NSNumber *)resIDValue withName:(NSString *)nameValue andAttributes:(NSNumber *)attributesValue
{
return [[Resource allocWithZone:[self zone]] initWithType:typeValue andID:resIDValue withName:nameValue andAttributes:attributesValue];
}
+ (id)resourceOfType:(NSString *)typeValue andID:(NSNumber *)resIDValue withName:(NSString *)nameValue andAttributes:(NSNumber *)attributesValue data:(NSData *)dataValue ofLength:(NSNumber *)sizeValue
{
return [[Resource allocWithZone:[self zone]] initWithType:typeValue andID:resIDValue withName:nameValue andAttributes:attributesValue data:dataValue ofLength:sizeValue];
}
@end

View File

@ -0,0 +1,23 @@
#import <Cocoa/Cocoa.h>
#import "Resource.h"
@class CreateResourceSheetController;
@interface ResourceDataSource : NSObject
{
IBOutlet NSWindow *window;
IBOutlet NSOutlineView *outlineView;
IBOutlet CreateResourceSheetController *createResourceSheetController;
NSMutableArray *resources;
}
- (CreateResourceSheetController *)createResourceSheetController;
- (NSWindow *)window;
- (NSArray *)resources;
- (void)setResources:(NSMutableArray *)newResources;
- (void)addResource:(Resource *)resource;
- (void)generateTestData;
@end

View File

@ -0,0 +1,91 @@
#import "ResourceDataSource.h"
@implementation ResourceDataSource
- (id)init
{
self = [super init];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceDidChange:) name:ResourceChangedNotification object:nil];
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
- (CreateResourceSheetController *)createResourceSheetController
{
return createResourceSheetController;
}
- (NSWindow *)window
{
return window;
}
- (NSArray *)resources
{
return resources;
}
- (void)setResources:(NSMutableArray *)newResources
{
[resources autorelease];
resources = [newResources retain];
[outlineView reloadData];
}
- (void)addResource:(Resource *)resource
{
[resources addObject:resource];
[outlineView reloadData];
// [outlineView noteNumberOfRowsChanged]; // what is this for if it doesn't update the damn outliine view!
}
- (void)resourceDidChange:(NSNotification *)notification
{
[outlineView reloadData];
}
- (void)generateTestData
{
[self addResource:[Resource resourceOfType:@"____" andID:[NSNumber numberWithShort:-1] withName:@"underscore" andAttributes:[NSNumber numberWithUnsignedShort:0x8080]]];
[self addResource:[Resource resourceOfType:@"ÐÐÐÐ" andID:[NSNumber numberWithShort:0] withName:@"hyphen" andAttributes:[NSNumber numberWithUnsignedShort:0xFFFF] data:[NSData data] ofLength:[NSNumber numberWithUnsignedLong:1023]]];
[self addResource:[Resource resourceOfType:@"----" andID:[NSNumber numberWithShort:128] withName:@"minus" andAttributes:[NSNumber numberWithUnsignedShort:0xABCD] data:[NSData data] ofLength:[NSNumber numberWithUnsignedLong:12000]]];
[self addResource:[Resource resourceOfType:@"ÑÑÑÑ" andID:[NSNumber numberWithShort:32000] withName:@"en-dash" andAttributes:[NSNumber numberWithUnsignedShort:0x1234] data:[NSData data] ofLength:[NSNumber numberWithUnsignedLong:4096]]];
[self addResource:[Resource resourceOfType:@"****" andID:[NSNumber numberWithShort:-32000]]];
}
- (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item
{
#pragma unused( outlineView, item )
return [resources objectAtIndex:index];
}
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
{
#pragma unused( outlineView, item )
return NO;
}
- (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
{
#pragma unused( outlineView, item )
return [resources count];
}
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
{
#pragma unused( outlineView )
return [item valueForKey:[tableColumn identifier]];
}
- (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
{
NSString *identifier = [tableColumn identifier];
[item takeValue:object forKey:identifier];
}
@end

View File

@ -0,0 +1,21 @@
#import <Cocoa/Cocoa.h>
#import <Carbon/Carbon.h> // Actually I only need CarbonCore.framework
#import "ResourceDataSource.h"
@interface ResourceDocument : NSDocument
{
IBOutlet NSOutlineView *outlineView;
IBOutlet ResourceDataSource *dataSource;
NSMutableArray *resources;
BOOL saveToDataFork;
HFSUniStr255 *otherFork; // name of fork to save to if not using data fork (usually 'RESOURCE_FORK' as returned from FSGetResourceForkName() -- ignored if saveToDataFork is YES )
}
- (BOOL)readResourceMap:(SInt16)fileRefNum;
- (BOOL)writeResourceMap:(SInt16)fileRefNum;
- (NSOutlineView *)outlineView;
- (ResourceDataSource *)dataSource;
@end

View File

@ -0,0 +1,256 @@
#import "ResourceDocument.h"
#import "Resource.h"
@implementation ResourceDocument
- (id)init
{
self = [super init];
resources = [NSMutableArray array];
otherFork = nil;
return self;
}
- (void)dealloc
{
if( otherFork )
DisposePtr( (Ptr) otherFork );
[resources release];
[super dealloc];
}
- (NSString *)windowNibName
{
// Override returning the nib file name of the document
// If you need to use a subclass of NSWindowController or if your document supports multiple NSWindowControllers, you should remove this method and override -makeWindowControllers instead.
return @"ResourceDocument";
}
- (void)windowControllerDidLoadNib:(NSWindowController *) aController
{
[super windowControllerDidLoadNib:aController];
// Add any code here that need to be executed once the windowController has loaded the document's window.
[dataSource setResources:resources];
}
- (BOOL)keepBackupFile
{
return NO; // return whatever the user preference is for this! (NSDefaults)
}
- (BOOL)windowShouldClose:(NSWindow *)sender
{
NSString *file = [[[sender representedFilename] lastPathComponent] stringByDeletingPathExtension];
if( [file isEqualToString:@""] ) file = @"this document";
NSBeginAlertSheet( @"Save Document?", @"Save", @"Cancel", @"DonÕt Save", sender, self, @selector(didEndShouldCloseSheet:returnCode:contextInfo:), NULL, sender, @"Do you wish to save %@?", file );
return NO;
}
- (void)didEndShouldCloseSheet:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
{
if( returnCode == NSAlertDefaultReturn ) // save then close
{
[self saveDocument:contextInfo];
[(NSWindow *)contextInfo close];
}
else if( returnCode == NSAlertOtherReturn ) // don't save, just close
{
[(NSWindow *)contextInfo close];
}
else if( returnCode == NSAlertErrorReturn )
{
NSLog( @"didEndShouldCloseSheet received NSAlertErrorReturn return code" );
}
// else returnCode == NSAlertAlternateReturn, cancel
}
- (BOOL)readFromFile:(NSString *)fileName ofType:(NSString *)type
{
BOOL succeeded = NO;
OSStatus error = noErr;
HFSUniStr255 *resourceForkName = (HFSUniStr255 *) NewPtrClear( sizeof(HFSUniStr255) );
FSRef *fileRef = (FSRef *) NewPtrClear( sizeof(FSRef) );
SInt16 fileRefNum = 0;
// open fork with resources in it
error = FSPathMakeRef( [fileName cString], fileRef, nil );
error = FSGetResourceForkName( resourceForkName );
SetResLoad( false ); // don't load "preload" resources
error = FSOpenResourceFile( fileRef, resourceForkName->length, (UniChar *) &resourceForkName->unicode, fsRdPerm, &fileRefNum);
if( error ) // try to open data fork instead
error = FSOpenResourceFile( fileRef, 0, nil, fsRdPerm, &fileRefNum);
else otherFork = resourceForkName;
SetResLoad( true ); // restore resource loading as soon as is possible
// read the resources
if( fileRefNum && !error )
succeeded = [self readResourceMap:fileRefNum];
// tidy up loose ends
if( !otherFork ) DisposePtr( (Ptr) resourceForkName ); // only delete if we're not saving it
if( fileRefNum ) FSClose( fileRefNum );
DisposePtr( (Ptr) fileRef );
return succeeded;
}
- (BOOL)readFromURL:(NSURL *)url ofType:(NSString *)type
{
return NO;
}
- (BOOL)readResourceMap:(SInt16)fileRefNum
{
OSStatus error = noErr;
unsigned short i, j, n;
SInt16 oldResFile = CurResFile();
UseResFile( fileRefNum );
for( i = 1; i <= Count1Types(); i++ )
{
ResType resType;
Get1IndType( &resType, i );
n = Count1Resources( resType );
for( j = 1; j <= n; j++ )
{
Str255 nameStr;
long sizeLong;
short resIDShort;
short attrsShort;
Handle resourceHandle;
resourceHandle = Get1IndResource( resType, j );
error = ResError();
if( error != noErr )
{
UseResFile( oldResFile );
return NO;
}
GetResInfo( resourceHandle, &resIDShort, &resType, nameStr );
sizeLong = GetResourceSizeOnDisk( resourceHandle );
attrsShort = GetResAttrs( resourceHandle );
HLockHi( resourceHandle );
// create the resource & add it to the array (am I leaking huge amounts of memory here, or are they dealloced automatically?)
{
NSString *name = [NSString stringWithCString:&nameStr[1] length:nameStr[0]];
NSString *type = [NSString stringWithCString:(char *) &resType length:4];
NSNumber *size = [NSNumber numberWithLong:sizeLong];
NSNumber *resID = [NSNumber numberWithShort:resIDShort];
NSNumber *attributes = [NSNumber numberWithShort:attrsShort];
NSData *data = [NSData dataWithBytes:*resourceHandle length:sizeLong];
Resource *resource = [Resource resourceOfType:type andID:resID withName:name andAttributes:attributes data:data ofLength:size];
[resources addObject:resource];
[resource autorelease];
}
HUnlock( resourceHandle );
ReleaseResource( resourceHandle );
}
}
// save resource map and clean up
UseResFile( oldResFile );
return YES;
}
- (BOOL)writeToFile:(NSString *)fileName ofType:(NSString *)type
{
BOOL succeeded = NO;
OSStatus error = noErr;
FSRef *parentRef = (FSRef *) NewPtrClear( sizeof(FSRef) );
FSRef *fileRef = (FSRef *) NewPtrClear( sizeof(FSRef) );
FSSpec *fileSpec = (FSSpec *) NewPtrClear( sizeof(FSSpec) );
SInt16 fileRefNum = 0;
// create and open file for writing
error = FSPathMakeRef( [[fileName stringByDeletingLastPathComponent] cString], parentRef, nil );
if( otherFork )
{
unichar *uniname = (unichar *) NewPtrClear( sizeof(unichar) *256 );
[[fileName lastPathComponent] getCharacters:uniname];
error = FSCreateResourceFile( parentRef, [[fileName lastPathComponent] length], (UniChar *) uniname, kFSCatInfoNone, nil, otherFork->length, (UniChar *) &otherFork->unicode, fileRef, fileSpec );
if( !error )
error = FSOpenResourceFile( fileRef, otherFork->length, (UniChar *) &otherFork->unicode, fsWrPerm, &fileRefNum);
}
else
{
unichar *uniname = (unichar *) NewPtrClear( sizeof(unichar) *256 );
[[fileName lastPathComponent] getCharacters:uniname];
error = FSCreateResourceFile( parentRef, [[fileName lastPathComponent] length], (UniChar *) uniname, kFSCatInfoNone, nil, 0, nil, fileRef, fileSpec );
if( !error )
error = FSOpenResourceFile( fileRef, 0, nil, fsWrPerm, &fileRefNum);
}
// write resource array to file
if( fileRefNum && !error )
succeeded = [self writeResourceMap:fileRefNum];
// tidy up loose ends
if( fileRefNum ) FSClose( fileRefNum );
DisposePtr( (Ptr) fileRef );
return succeeded;
}
- (BOOL)writeToURL:(NSURL *)url ofType:(NSString *)type
{
return NO;
}
- (BOOL)writeResourceMap:(SInt16)fileRefNum
{
OSStatus error = noErr;
unsigned long i;
SInt16 oldResFile = CurResFile();
UseResFile( fileRefNum );
for( i = 0; i < [resources count]; i++ )
{
Resource *resource = [resources objectAtIndex:i];
Str255 nameStr;
ResType resType;
short resIDShort = [[resource resID] shortValue];
long sizeLong = [[resource size] longValue];
short attrsShort = [[resource attributes] shortValue];
Handle resourceHandle = NewHandleClear( sizeLong );
nameStr[0] = [[resource name] cStringLength];
BlockMoveData( [[resource name] cString], &nameStr[1], nameStr[0] );
[[resource type] getCString:(char *) &resType maxLength:4];
HLockHi( resourceHandle );
[[resource data] getBytes:*resourceHandle];
HUnlock( resourceHandle );
AddResource( resourceHandle, resType, resIDShort, nameStr );
if( ResError() == addResFailed )
{
NSLog( @"Saving failed; could not add resource \"%@\" of type %@ to file.", [resource name], [resource type] );
error = addResFailed;
}
else
{
SetResAttrs( resourceHandle, attrsShort );
ChangedResource( resourceHandle );
UpdateResFile( fileRefNum );
}
}
// save resource map and clean up
UseResFile( oldResFile );
return error? NO:YES;
}
- (NSOutlineView *)outlineView
{
return outlineView;
}
- (ResourceDataSource *)dataSource
{
return dataSource;
}
@end

View File

@ -0,0 +1,9 @@
#import <Foundation/Foundation.h>
@interface SizeFormatter : NSNumberFormatter
{
}
- (NSString *)stringForObjectValue:(id)obj;
@end

View File

@ -0,0 +1,45 @@
#import "SizeFormatter.h"
@implementation SizeFormatter
- (void)awakeFromNib
{
[self setFormat:@"#,##0.0"];
[self setLocalizesFormat:YES];
[self setAllowsFloats:YES];
}
- (NSString *)stringForObjectValue:(id)obj
{
NSMutableString *string = [NSMutableString string];
float value = [obj floatValue];
int power = 0;
while( value >= 1024 && power <= 30 )
{
power += 10; // 10 == KB, 20 == MB, 30 == GB
value /= 1024;
}
switch( power )
{
case 0:
[string appendFormat:@"%.0f", value];
break;
case 10:
[string appendFormat:@"%.1f KB", value];
break;
case 20:
[string appendFormat:@"%.1f MB", value];
break;
default:
[string appendFormat:@"%.1f GB", value];
break;
}
return string;
}
@end

View File

@ -0,0 +1,4 @@
{
IBClasses = ({CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; });
IBVersion = 1;
}

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="0.9">
<dict>
<key>IBUserGuides</key>
<dict>
<key>AboutPanel</key>
<dict>
<key>guideLocations</key>
<array/>
<key>guidesLocked</key>
<string>NO</string>
</dict>
</dict>
</dict>
</plist>

Binary file not shown.

View File

@ -0,0 +1,29 @@
{
IBClasses = (
{
ACTIONS = {
openResource = id;
playSound = id;
showCreateResourceSheet = id;
showInfo = id;
showPrefs = id;
};
CLASS = ApplicationDelegate;
LANGUAGE = ObjC;
SUPERCLASS = NSObject;
},
{
ACTIONS = {
openResource = id;
playSound = id;
showCreateResourceSheet = id;
showInfo = id;
showPrefs = id;
};
CLASS = FirstResponder;
LANGUAGE = ObjC;
SUPERCLASS = NSObject;
}
);
IBVersion = 1;
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="0.9">
<dict>
<key>IBDocumentLocation</key>
<string>156 127 432 426 0 74 1280 928 </string>
<key>IBMainMenuLocation</key>
<string>205 655 347 44 0 74 1280 928 </string>
<key>IBUserGuides</key>
<dict/>
</dict>
</plist>

Binary file not shown.

View File

@ -0,0 +1,6 @@
/* Localized versions of Info.plist keys */
CFBundleName = "ResKnife";
CFBundleShortVersionString = "Development Version";
CFBundleGetInfoString = "ResKnife 0.4d3, Copyright 2001 Nicholas Shanks.";
NSHumanReadableCopyright = "Copyright © 2001 Nicholas Shanks.";

View File

@ -0,0 +1,20 @@
{
IBClasses = (
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
{CLASS = InfoWindow; LANGUAGE = ObjC; SUPERCLASS = NSPanel; },
{
ACTIONS = {attributesChanged = id; };
CLASS = InfoWindowController;
LANGUAGE = ObjC;
OUTLETS = {
attributesMatrix = id;
iconView = id;
nameView = id;
resIDView = id;
typeView = id;
};
SUPERCLASS = NSWindowController;
}
);
IBVersion = 1;
}

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="0.9">
<dict>
<key>IBDocumentLocation</key>
<string>377 192 384 449 0 74 1280 928 </string>
<key>IBUserGuides</key>
<dict>
<key>InfoWindow</key>
<dict>
<key>guideLocations</key>
<array/>
<key>guidesLocked</key>
<string>NO</string>
</dict>
</dict>
</dict>
</plist>

Binary file not shown.

View File

@ -0,0 +1,5 @@
/* Localized versions of application-critical strings */
/* File window default resource names */
"Untitled Resource" = "Untitled Resource";
"Custom Icon" = "Custom Icon";

View File

@ -0,0 +1,13 @@
{
IBClasses = (
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
{
ACTIONS = {acceptPrefs = id; cancelPrefs = id; resetToDefault = id; };
CLASS = PrefsWindowController;
LANGUAGE = ObjC;
OUTLETS = {autosaveIntervalField = id; dataProtectionMatrix = id; };
SUPERCLASS = NSWindowController;
}
);
IBVersion = 1;
}

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="0.9">
<dict>
<key>IBDocumentLocation</key>
<string>70 184 468 280 0 74 1280 928 </string>
<key>IBUserGuides</key>
<dict>
<key>PrefsWindow</key>
<dict>
<key>guideLocations</key>
<array/>
<key>guidesLocked</key>
<string>NO</string>
</dict>
</dict>
</dict>
</plist>

Binary file not shown.

View File

@ -0,0 +1,53 @@
{
IBClasses = (
{CLASS = AttributesFormatter; LANGUAGE = ObjC; SUPERCLASS = NSFormatter; },
{
ACTIONS = {
hideCreateResourceSheet = id;
showCreateResourceSheet = id;
typePopupSelection = id;
};
CLASS = CreateResourceSheetController;
LANGUAGE = ObjC;
OUTLETS = {
attributesMatrix = id;
cancelButton = id;
createButton = id;
dataSource = id;
nameView = id;
parent = id;
resIDView = id;
typePopup = id;
typeView = id;
};
SUPERCLASS = NSWindowController;
},
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
{CLASS = NameFormatter; LANGUAGE = ObjC; SUPERCLASS = NSFormatter; },
{
CLASS = OutlineViewDelegate;
LANGUAGE = ObjC;
OUTLETS = {
attributesFormatter = id;
nameFormatter = id;
sizeFormatter = id;
window = id;
};
SUPERCLASS = NSObject;
},
{
CLASS = ResourceDataSource;
LANGUAGE = ObjC;
OUTLETS = {createResourceSheetController = id; outlineView = id; window = id; };
SUPERCLASS = NSObject;
},
{
CLASS = ResourceDocument;
LANGUAGE = ObjC;
OUTLETS = {dataSource = id; outlineView = id; };
SUPERCLASS = NSDocument;
},
{CLASS = SizeFormatter; LANGUAGE = ObjC; SUPERCLASS = NSNumberFormatter; }
);
IBVersion = 1;
}

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="0.9">
<dict>
<key>IBDocumentLocation</key>
<string>14 132 480 547 0 74 1280 928 </string>
<key>IBMainMenuLocation</key>
<string>52 694 73 138 0 74 1280 928 </string>
<key>IBUserGuides</key>
<dict>
<key>CreateResourceSheet</key>
<dict>
<key>guideLocations</key>
<array/>
<key>guidesLocked</key>
<string>NO</string>
</dict>
<key>Window</key>
<dict>
<key>guideLocations</key>
<array/>
<key>guidesLocked</key>
<string>NO</string>
</dict>
</dict>
</dict>
</plist>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,6 @@
{
PreserveBackups = YES;
Autosave = YES;
AutosaveInterval = 5;
DeleteResourceWarning = YES;
}

6
Cocoa/main.c Normal file
View File

@ -0,0 +1,6 @@
#import <Cocoa/Cocoa.h>
int main(int argc, const char *argv[])
{
return NSApplicationMain(argc, argv);
}

View File

@ -0,0 +1,998 @@
#include "Events.h"
#include "HexWindow.h"
#include "Utility.h"
extern globals g;
extern prefs p;
/******************/
/* EVENT HANDLING */
/******************/
/*** CARBON WINDOW EVENT HANDLER ***/
pascal OSStatus CarbonWindowEventHandler( EventHandlerCallRef handler, EventRef event, void *userData )
{
#pragma unused( handler )
OSStatus error = eventNotHandledErr;
Plug_PlugInRef plugRef = (Plug_PlugInRef) userData;
WindowRef window = GetUserFocusWindow();
// get event type
UInt32 eventClass = GetEventClass( event );
UInt32 eventKind = GetEventKind( event );
// get event parameters
if( eventClass == kEventClassWindow )
GetEventParameter( event, kEventParamDirectObject, typeWindowRef, null, sizeof(WindowRef), null, &window );
if( !window ) return error;
Plug_WindowRef plugWindow = Host_GetPlugWindowFromWindowRef( window );
if( !plugWindow ) return error;
HexWindowPtr hexWindow = (HexWindowPtr) Host_GetWindowRefCon( plugWindow );
if( !hexWindow ) return error;
// get window rect
Rect windowBounds;
GetWindowPortBounds( window, &windowBounds );
// handle event
static EventHandlerRef resizeEventHandlerRef = null;
switch( eventClass )
{
case kEventClassWindow:
switch( eventKind )
{
case kEventWindowClose:
delete hexWindow;
break;
case kEventWindowActivated:
case kEventWindowDeactivated:
if( hexWindow->activeWindow && hexWindow->insertionPointVisable )
BlinkInsertionPoint( null, window ); // this has to be done before the window is marked as deactivated
// hexWindow->activeWindow = !hexWindow->activeWindow; // bug: OS X is sending the event twice (naughty Apple!), so i shall do this more correctly as follows
if( eventKind == kEventWindowActivated )
hexWindow->activeWindow = true;
else hexWindow->activeWindow = false;
InvalidateWindowRect( window, &windowBounds );
break;
case kEventWindowBoundsChanging:
error = hexWindow->BoundsChanging( event );
break;
case kEventWindowBoundsChanged:
error = hexWindow->BoundsChanged( event );
break;
case kEventWindowDrawContent:
error = hexWindow->DrawContent( event );
break;
case kEventWindowHandleContentClick:
{ // get mouse
Point mouse;
error = GetEventParameter( event, kEventParamMouseLocation, typeQDPoint, null, sizeof(Point), null, &mouse );
if( !error )
{
MakeLocal( window, mouse, &mouse );
// get modifier keys
UInt32 modifiers = null;
error = GetEventParameter( event, kEventParamKeyModifiers, typeUInt32, null, sizeof(UInt32), null, &modifiers );
if( error ) break;
// identify click is in edit boxes & act accordingly
Boolean clickHex = false; // clicked in hex rect?
Boolean clickAscii = false; // clicked in ascii rect? - neither means not editing
Plug_WindowRef plugWindow = Host_GetPlugWindowFromWindowRef( window );
HexWindowPtr hexWindow = (HexWindowPtr) Host_GetWindowRefCon( plugWindow );
if( PtInRect( mouse, &hexWindow->hexRect ) ) { clickHex = true; hexWindow->editingHex = true; }
if( PtInRect( mouse, &hexWindow->asciiRect ) ) { clickAscii = true; hexWindow->editingHex = false; }
if( clickHex || clickAscii ) error = HandleEditClick( window, event, mouse, (EventModifiers) LoWord(modifiers) );
else error = eventNotHandledErr;
}
else error = eventNotHandledErr;
} break;
}
break;
case kEventClassKeyboard:
switch( eventKind )
{
case kEventRawKeyDown:
case kEventRawKeyRepeat:
{ signed char charCode; // key character pressed
UInt32 modifiers = null;
error = GetEventParameter( event, kEventParamKeyMacCharCodes, typeChar, null, sizeof(char), null, &charCode );
if( error ) break;
error = GetEventParameter( event, kEventParamKeyModifiers, typeUInt32, null, sizeof(UInt32), null, &modifiers );
if( error ) break;
HandleKeyDown( window, charCode, (EventModifiers) LoWord(modifiers) );
} break;
}
// calculate new scrollbar values & redraw window
hexWindow->UpdateHexInfo();
InvalidateWindowRect( window, &windowBounds );
break;
}
return error;
}
/*** CARBON HUMAN INTERFACE EVENT HANDLER ***/
pascal OSStatus CarbonHIEventHandler( EventHandlerCallRef handler, EventRef event, void *userData )
{
#pragma unused( handler, userData )
OSStatus error = eventNotHandledErr;
WindowRef window = GetUserFocusWindow(); // overridden below for window class events
if( !window ) return error;
// get event type
UInt32 eventClass = GetEventClass( event );
UInt32 eventKind = GetEventKind( event );
// get event parameters
Plug_WindowRef plugWindow = Host_GetPlugWindowFromWindowRef( window );
if( !plugWindow ) return error;
HexWindowPtr hexWindow = (HexWindowPtr) Host_GetWindowRefCon( plugWindow );
if( !hexWindow ) return error;
// handle event
switch( eventClass )
{
case kEventClassMenu:
switch( eventKind )
{
case kEventMenuEnableItems:
{ Plug_ResourceRef resource = Host_GetTargetResource( plugWindow );
Boolean canPlaySound = false;
if( Host_GetResourceType( resource ) == soundListRsrc )
canPlaySound = true;
// get host to set menus so we can modify them
Host_UpdateMenus( resource );
// edit menu
EnableCommand( null, kHICommandUndo, false );
EnableCommand( null, kHICommandRedo, false );
EnableCommand( null, kHICommandCut, hexWindow->selStart != hexWindow->selEnd );
EnableCommand( null, kHICommandCopy, hexWindow->selStart != hexWindow->selEnd );
EnableCommand( null, kHICommandPaste, true ); // bug
EnableCommand( null, kHICommandClear, hexWindow->selStart != hexWindow->selEnd );
error = noErr;
} break;
}
break;
case kEventClassCommand:
HICommand command;
Plug_ResourceRef resource = Host_GetTargetResource( plugWindow );
error = GetEventParameter( event, kEventParamDirectObject, typeHICommand, null, sizeof(HICommand), null, &command );
if( error ) return eventNotHandledErr;
switch( eventKind )
{
case kEventCommandProcess:
switch( command.commandID )
{
/* case kHICommandOK:
case kHICommandCancel:
case kHICommandQuit:
case kHICommandUndo:
case kHICommandRedo:
case kHICommandCut:
SendEventToWindow( copyEvent, window );
SendEventToWindow( clearEvent, window );
error = noErr;
break;
*/
case kHICommandCopy:
{ // copy should be disabled if there isn't a selection, but just in caseÉ
if( hexWindow->selStart == hexWindow->selEnd ) return error;
// lock the data
Size size;
ScrapRef scrap;
ClearCurrentScrap();
error = GetCurrentScrap( &scrap );
if( error ) return error;
SInt8 state = HGetState( hexWindow->data );
HLock( hexWindow->data );
if( hexWindow->editingHex )
{
// copy data with hex formatting
size = 3*(hexWindow->selEnd - hexWindow->selStart) -1;
Ptr hex = NewPtrClear( size );
Ptr ascii = NewPtrClear( hexWindow->selEnd - hexWindow->selStart );
BlockMoveData( *hexWindow->data + hexWindow->selStart, ascii, hexWindow->selEnd - hexWindow->selStart );
AsciiToHex( ascii, hex, hexWindow->selEnd - hexWindow->selStart );
error = PutScrapFlavor( scrap, kScrapFlavorTypeText, kScrapFlavorMaskNone, size, hex );
DisposePtr( hex );
DisposePtr( ascii );
}
else
{
// copy raw data as byte stream
size = hexWindow->selEnd - hexWindow->selStart;
Ptr ascii = NewPtrClear( size );
BlockMoveData( *hexWindow->data + hexWindow->selStart, ascii, size );
error = PutScrapFlavor( scrap, kScrapFlavorTypeText, kScrapFlavorMaskNone, size, ascii );
DisposePtr( ascii );
}
HSetState( hexWindow->data, state );
error = noErr;
} break;
case kHICommandPaste:
{ Size size;
ScrapRef scrap;
error = GetCurrentScrap( &scrap );
if( error ) return error;
error = GetScrapFlavorSize( scrap, kScrapFlavorTypeText, &size );
if( error ) return error;
if( size > 0 )
{
Ptr bytes = NewPtr( size );
error = GetScrapFlavorData( scrap, kScrapFlavorTypeText, &size, bytes );
if( !error )
{
hexWindow->InsertBytes( null, hexWindow->selStart - hexWindow->selEnd, hexWindow->selEnd ); // remove this when using the above
hexWindow->InsertBytes( bytes, size, hexWindow->selStart );
hexWindow->selStart = hexWindow->selEnd += size;
}
DisposePtr( bytes );
Host_SetResourceDirty( resource, true );
}
error = noErr;
} break;
case kHICommandClear:
hexWindow->InsertBytes( nil, hexWindow->selStart - hexWindow->selEnd, hexWindow->selEnd );
hexWindow->selEnd = hexWindow->selStart;
Host_SetResourceDirty( resource, true );
error = noErr;
break;
case kHICommandSelectAll:
hexWindow->selStart = 0;
hexWindow->selEnd = GetHandleSize( hexWindow->data );
error = noErr;
break;
/* case kHICommandHide:
case kHICommandPreferences:
case kHICommandZoomWindow:
case kHICommandMinimizeWindow:
case kHICommandArrangeInFront:
case kHICommandAbout:
*/ default:
error = eventNotHandledErr;
break;
}
break;
case kEventCommandUpdateStatus:
error = eventNotHandledErr;
break;
default:
error = eventNotHandledErr;
break;
}
break;
}
// most calls need window updating, so do it here
Rect windowBounds;
hexWindow->UpdateHexInfo();
GetWindowPortBounds( window, &windowBounds );
InvalidateWindowRect( window, &windowBounds );
return error;
}
#if !TARGET_API_MAC_CARBON
/*** CLASSIC WINDOW EVENT HANDLER ***/
pascal OSStatus ClassicWindowEventHandler( EventRecord *event, UInt32 eventKind, void *userData )
{
#pragma unused( event, userData )
OSStatus error = eventNotHandledErr;
/* Plug_PlugInRef plugRef = (Plug_PlugInRef) userData;
WindowRef window;
GetEventParameter( event, kEventParamDirectObject, typeWindowRef, null, sizeof(WindowRef), null, &window );
*/
switch( eventKind )
{
case kEventWindowDrawContent:
error = DrawWindow( window );
break;
case kEventWindowHandleContentClick:
SysBeep(0);
break;
}
return error;
}
#endif
/*****************/
/* WINDOW EVENTS */
/*****************/
pascal OSStatus ConstrainWindowResize( EventHandlerCallRef handler, EventRef event, void *userData )
{
#pragma unused( handler )
Rect windowBounds;
HexWindowPtr hexWindow = (HexWindowPtr) userData;
OSStatus error = GetEventParameter( event, kEventParamCurrentBounds, typeQDRectangle, null, sizeof(Rect), null, &windowBounds );
if( error ) return eventNotHandledErr;
// constrain window width
UInt8 modulo = (windowBounds.right - windowBounds.left - 13*kHexCharWidth - kScrollBarWidth) % (4*kDataBlockWidth);
if( modulo < (2*kDataBlockWidth) ) windowBounds.right -= modulo;
else windowBounds.right += (4*kDataBlockWidth) - modulo;
// constrain window height
modulo = (windowBounds.bottom - windowBounds.top - kHeaderHeight - 2*kTextMargin -4) % kHexLineHeight;
if( modulo < (kHexLineHeight/2) ) windowBounds.bottom -= modulo;
else windowBounds.bottom += kHexLineHeight - modulo;
// update window rect to constrained version
if( (windowBounds.bottom - windowBounds.top) < kMinimumWindowHeight ) windowBounds.bottom = windowBounds.top + kMinimumWindowHeight;
if( (windowBounds.right - windowBounds.left) < kMinimumWindowWidth ) windowBounds.right = windowBounds.left + kMinimumWindowWidth;
error = SetEventParameter( event, kEventParamCurrentBounds, typeQDRectangle, sizeof(Rect), &windowBounds );
if( error ) error = eventNotHandledErr;
// resize controls & update hex info
hexWindow->BoundsChanged( event );
return noErr;
}
/***************/
/* USER EVENTS */
/***************/
/*** HANDLE CLICK IN HEX/ASCII REGION ***/
OSStatus HandleEditClick( WindowRef window, EventRef event, Point mouse, EventModifiers modifiers )
{
OSStatus error = eventNotHandledErr;
// get hex info
Plug_WindowRef plugWindow = Host_GetPlugWindowFromWindowRef( window );
HexWindowPtr hexWindow = (HexWindowPtr) Host_GetWindowRefCon( plugWindow );
// a mouse down event has been recieved and is within hexRect or asciiRect
UInt16 clickLine; // from zero, the line in which the click occoured
UInt16 clickChar; // 0 to 16, the char after the clickloc, or at line end
// get line clicked on
clickLine = (mouse.v - kHeaderHeight - kTextMargin)/kHexLineHeight + hexWindow->topline;
if( clickLine > hexWindow->lastline ) // beyond last line
{
hexWindow->selStart = hexWindow->selEnd = GetHandleSize( hexWindow->data );
return noErr;
}
// get char clicked on -- duplicated in dragging routine
if( hexWindow->editingHex ) clickChar = (mouse.h - kHexCharWidth *10) / (kHexCharWidth*3);
else clickChar = (mouse.h - kHexCharWidth *60) / kHexCharWidth;
// check for drags
Point globalMouse;
MakeGlobal( window, mouse, &globalMouse );
Boolean dragging = WaitMouseMoved( globalMouse );
unsigned long selectFromChar = (clickLine *16) + clickChar;
unsigned long selectToChar = selectFromChar;
// define selection region
RgnHandle hexRgn = NewRgn(), asciiRgn = NewRgn(), selectedRgn = NewRgn();
FindSelectedRegions( window, hexRgn, asciiRgn );
UnionRgn( hexRgn, asciiRgn, selectedRgn );
// drag current selection
if( PtInRgn( mouse, selectedRgn ) && dragging )
{
OSErr error = noErr;
DragReference theDragRef;
ItemReference theItemRef = 1;
FlavorFlags theFlags = nil;
short resCounter = 0;
Size dataSize = hexWindow->selEnd - hexWindow->selStart;
RgnHandle dragRgn = NewRgn(), subtractRgn = NewRgn();
Handle dataToDrag = NewHandleClear( dataSize * (hexWindow->editingHex? 3:1) - (hexWindow->editingHex? 1:0) );
NewDrag( &theDragRef );
if( MemError() ) return eventNotHandledErr;
// get region of dragged items
if( hexWindow->editingHex ) dragRgn = hexRgn;
else dragRgn = asciiRgn;
CopyRgn( dragRgn, subtractRgn ); // duplicate region
InsetRgn( subtractRgn, 2, 2 ); // inset it by 2 pixels
DiffRgn( dragRgn, subtractRgn, dragRgn ); // subtract subRgn from dragRgn
// get the drag data
EventRecord eventRec;
Boolean eventValid = ConvertEventRefToEventRecord( event, &eventRec );
if( !eventValid ) eventValid = true; // bug: for some reason the event converter is not returning valid events, but the drag still works
if( dataToDrag && eventValid )
{
// I can't tell what the previous state of editingHex was, so cannot restore it.
// as such, i will redraw the window with the selection flipped if necessary
hexWindow->DrawContent();
SInt8 dataState = HGetState( hexWindow->data );
SInt8 dragState = HGetState( dataToDrag );
HLock( hexWindow->data );
HLock( dataToDrag );
if( hexWindow->editingHex ) AsciiToHex( *hexWindow->data + hexWindow->selStart, *dataToDrag, dataSize );
else BlockMoveData( *hexWindow->data + hexWindow->selStart, *dataToDrag, dataSize );
HSetState( hexWindow->data, dataState );
HSetState( dataToDrag, dragState );
// do the drag
SetPoint( &globalMouse, 0, 0 );
MakeGlobal( window, globalMouse, &globalMouse );
OffsetRgn( dragRgn, globalMouse.h, globalMouse.v );
error = AddDragItemFlavor( theDragRef, theItemRef, kScrapFlavorTypeText, *dataToDrag, GetHandleSize(dataToDrag), theFlags );
error = TrackDrag( theDragRef, &eventRec, dragRgn );
// when dragging from the ACSII pane, drag will contain ÔasciiÕ, when dragging from the HEX pane, drag will contain Ô61 73 63 69 69Õ
}
// clear up
if( dataToDrag ) DisposeHandle( dataToDrag );
if( theDragRef ) DisposeDrag( theDragRef );
if( subtractRgn ) DisposeRgn( subtractRgn );
if( dragRgn ) DisposeRgn( dragRgn );
}
// dragging new selection
else if( dragging )
{
// remove insetion point if visable
if( hexWindow->activeWindow && hexWindow->insertionPointVisable )
BlinkInsertionPoint( null, window );
Point localMouse;
while( WaitMouseUp() )
{
// get local mouse co-ords
GetMouse( &mouse );
MakeLocal( window, mouse, &localMouse );
// get line clicked on
clickLine = (localMouse.v - kHeaderHeight - kTextMargin)/kHexLineHeight + hexWindow->topline;
// get char clicked on
if( hexWindow->editingHex ) clickChar = (localMouse.h - kHexCharWidth *10) / (kHexCharWidth*3);
else clickChar = (localMouse.h - kHexCharWidth *60) / kHexCharWidth;
// update selection according to mouse position and scroll to maintain visibility
selectToChar = (clickLine *16) + clickChar;
if( selectToChar < 0 ) selectToChar = 0;
if( selectToChar > GetHandleSize(hexWindow->data) -1 ) selectToChar = GetHandleSize(hexWindow->data) -1;
if( selectFromChar < selectToChar )
{
hexWindow->selStart = selectFromChar;
hexWindow->selEnd = selectToChar +1;
// hexScrollToLine( theWindow, clickLine, kBottomOfWindow );
}
else if( selectFromChar > selectToChar )
{
hexWindow->selStart = selectToChar;
hexWindow->selEnd = selectFromChar;
// hexScrollToLine( theWindow, clickLine, kTopOfWindow );
}
else
{
hexWindow->selStart = selectFromChar;
hexWindow->selEnd = selectToChar +1;
}
// draw window
hexWindow->DrawContent();
}
}
// change cursor position
else
{
// remove insertion point if visable
if( hexWindow->activeWindow && hexWindow->insertionPointVisable )
BlinkInsertionPoint( null, window );
if( modifiers & shiftKey ) // extend selection
{
if( selectFromChar < hexWindow->selStart ) hexWindow->selStart = selectFromChar;
else hexWindow->selEnd = selectFromChar +1;
}
else // normal click
{
if( mouse.v < GetHandleSize(hexWindow->data) ) hexWindow->selStart = selectFromChar;
else hexWindow->selStart = GetHandleSize(hexWindow->data);
hexWindow->selEnd = selectToChar;
}
if( hexWindow->selStart < 0 ) hexWindow->selStart = 0;
if( hexWindow->selEnd > GetHandleSize(hexWindow->data) ) hexWindow->selEnd = GetHandleSize(hexWindow->data);
// invalidate window incase there was a selection
Rect windowBounds;
GetWindowPortBounds( window, &windowBounds );
InvalidateWindowRect( window, &windowBounds );
}
DisposeRgn( hexRgn );
DisposeRgn( asciiRgn );
DisposeRgn( selectedRgn );
return noErr;
}
/*** HANDLE EDIT DRAG ***/
OSStatus HandleEditDrag( WindowRef window, EventRef event, Point mouse, EventModifiers modifiers )
{
#pragma unused( window, event, mouse, modifiers )
return eventNotHandledErr;
}
/*** HANDLE KEY DOWN ***/
OSStatus HandleKeyDown( WindowRef window, unsigned char charCode, EventModifiers modifiers )
{
OSStatus error = eventNotHandledErr;
// get hex info
Plug_WindowRef plugWindow = Host_GetPlugWindowFromWindowRef( window );
Plug_ResourceRef resource = Host_GetTargetResource( plugWindow );
HexWindowPtr hexWindow = (HexWindowPtr) Host_GetWindowRefCon( plugWindow );
// handle arrow keys
Boolean resEdited = false;
switch( charCode )
{
case kTabCharCode:
case kEnterCharCode:
case kReturnCharCode:
hexWindow->editingHex = !hexWindow->editingHex;
break;
case kBackspaceCharCode: // delete
if( hexWindow->selStart == hexWindow->selEnd ) {
if( hexWindow->selStart != 0 ) {
hexWindow->InsertBytes( nil, -1, hexWindow->selEnd ); // delete prev char
hexWindow->selStart = hexWindow->selEnd -= 1; } }
else {
hexWindow->InsertBytes( nil, hexWindow->selStart - hexWindow->selEnd, hexWindow->selEnd ); // remove selection
hexWindow->selEnd = hexWindow->selStart; }
Host_SetResourceDirty( resource, true );
break;
case kDeleteCharCode: // forward delete
if( hexWindow->selStart == hexWindow->selEnd )
{
if( hexWindow->selStart != GetHandleSize( hexWindow->data ) )
hexWindow->InsertBytes( nil, -1, hexWindow->selEnd +1 ); // delete next char
}
else
{
hexWindow->InsertBytes( nil, hexWindow->selStart - hexWindow->selEnd, hexWindow->selEnd ); // remove selection
hexWindow->selEnd = hexWindow->selStart;
}
Host_SetResourceDirty( resource, true );
break;
case kLeftArrowCharCode:
case kRightArrowCharCode:
case kUpArrowCharCode:
case kDownArrowCharCode:
error = HandleArrowKeyDown( window, charCode, modifiers );
break;
default:
if( hexWindow->editingHex ) // editing in hexadecimal
{
Boolean deletePrev = false; // delete prev typing to add new one
if( hexWindow->editedHigh ) // edited high bits already
{
// shift typed char into high bits and add new low char
if( charCode >= 0x30 && charCode <= 0x39 ) charCode -= 0x30; // 0 to 9
else if( charCode >= 0x61 && charCode <= 0x66 ) charCode -= 0x57; // a to f
else if( charCode >= 0x93 && charCode <= 0x98 ) charCode -= 0x8A; // A to F
else break;
hexWindow->hexChar <<= 4; // store high bit
hexWindow->hexChar += charCode & 0x0F; // add low bit
hexWindow->selStart += 1;
hexWindow->selEnd = hexWindow->selStart;
hexWindow->editedHigh = false;
deletePrev = true;
}
else // editing low bits
{
// put typed char into low bits
if( charCode >= 0x30 && charCode <= 0x39 ) charCode -= 0x30; // 0 to 9
else if( charCode >= 0x61 && charCode <= 0x66 ) charCode -= 0x57; // a to f
else if( charCode >= 0x93 && charCode <= 0x98 ) charCode -= 0x8A; // A to F
else break;
hexWindow->hexChar = charCode & 0x0F;
hexWindow->editedHigh = true;
}
hexWindow->InsertBytes( nil, hexWindow->selStart - hexWindow->selEnd, hexWindow->selEnd ); // remove selection
hexWindow->selEnd = hexWindow->selStart;
if( deletePrev )
{
hexWindow->InsertBytes( nil, -1, hexWindow->selStart ); // remove previous hex char
hexWindow->InsertBytes( &hexWindow->hexChar, 1, hexWindow->selStart -1 ); // insert typed char (bug fix hack)
}
else hexWindow->InsertBytes( &hexWindow->hexChar, 1, hexWindow->selStart ); // insert typed char
}
else // editing in ascii
{
hexWindow->InsertBytes( nil, hexWindow->selStart - hexWindow->selEnd, hexWindow->selEnd ); // remove selection
hexWindow->selEnd = hexWindow->selStart;
hexWindow->InsertBytes( &charCode, 1, hexWindow->selStart ); // insert typed char
hexWindow->selStart += 1;
hexWindow->selEnd = hexWindow->selStart;
}
Host_SetResourceDirty( resource, true );
break;
}
// check selection is within resource
if( hexWindow->selStart > hexWindow->selEnd ) hexWindow->selStart = hexWindow->selEnd;
if( hexWindow->selStart > GetHandleSize(hexWindow->data) ) hexWindow->selStart = GetHandleSize(hexWindow->data);
if( hexWindow->selEnd > GetHandleSize(hexWindow->data) ) hexWindow->selEnd = GetHandleSize(hexWindow->data);
// modify key pressed so scroller interperets it correctly
if( modifiers & controlKey ) switch( charCode )
{
case kUpArrowCharCode:
charCode = kDownArrowCharCode;
break;
case kDownArrowCharCode:
charCode = kUpArrowCharCode;
break;
case kLeftArrowCharCode:
charCode = kRightArrowCharCode;
break;
case kRightArrowCharCode:
charCode = kLeftArrowCharCode;
break;
}
// get scrollbar
#if TARGET_API_MAC_CARBON
ControlRef scrollbar;
ControlID id = { kScrollbarSignature, 0 };
GetControlByID( window, &id, &scrollbar );
#else
ControlRef scrollbar = hexWindow->scrollbar;
#endif
// scroll to selection
switch( charCode )
{
case kUpArrowCharCode:
if( hexWindow->selStart /16 < hexWindow->topline +1 )
SetControlValue( scrollbar, hexWindow->selStart /16 -1 );
break;
case kDownArrowCharCode:
if( hexWindow->selEnd /16 > hexWindow->bottomline -1 )
SetControlValue( scrollbar, hexWindow->selEnd /16 - (hexWindow->bottomline - hexWindow->topline) +1 );
break;
case kBackspaceCharCode:
case kLeftArrowCharCode:
if( hexWindow->selStart /16 < hexWindow->topline +1 )
SetControlValue( scrollbar, hexWindow->selStart /16 -1 );
break;
case kRightArrowCharCode:
default:
if( hexWindow->selEnd /16 > hexWindow->bottomline -1 )
SetControlValue( scrollbar, hexWindow->selEnd /16 - (hexWindow->bottomline - hexWindow->topline) +1 );
break;
}
return error;
}
/*** HANDLE ARROW KEY DOWN ***/
OSStatus HandleArrowKeyDown( WindowRef window, unsigned char charCode, EventModifiers modifiers )
{
OSStatus error = noErr;
// get hex info
Plug_WindowRef plugWindow = Host_GetPlugWindowFromWindowRef( window );
Plug_ResourceRef resource = Host_GetTargetResource( plugWindow );
HexWindowPtr hexWindow = (HexWindowPtr) Host_GetWindowRefCon( plugWindow );
if( modifiers & optionKey ) switch( charCode ) // move selection
{
case kLeftArrowCharCode:
hexWindow->selStart -= 1;
hexWindow->selEnd -= 1;
break;
case kRightArrowCharCode:
hexWindow->selStart += 1;
hexWindow->selEnd += 1;
break;
case kUpArrowCharCode:
hexWindow->selStart -= 16;
hexWindow->selEnd -= 16;
break;
case kDownArrowCharCode:
hexWindow->selStart += 16;
hexWindow->selEnd += 16;
break;
}
else if( modifiers & shiftKey ) switch( charCode ) // extend selection
{
case kLeftArrowCharCode:
hexWindow->selStart -= 1;
break;
case kRightArrowCharCode:
hexWindow->selEnd += 1;
break;
case kUpArrowCharCode:
hexWindow->selStart -= 16;
break;
case kDownArrowCharCode:
hexWindow->selEnd += 16;
break;
}
else if( modifiers & controlKey ) switch( charCode ) // reduce selection
{
case kLeftArrowCharCode:
hexWindow->selEnd -= 1;
break;
case kRightArrowCharCode:
hexWindow->selStart += 1;
break;
case kUpArrowCharCode:
hexWindow->selEnd -= 16;
break;
case kDownArrowCharCode:
hexWindow->selStart += 16;
break;
}
else switch( charCode ) // move cursor
{
case kLeftArrowCharCode:
if( hexWindow->selStart == hexWindow->selEnd )
{
if( hexWindow->selStart >= 1 ) hexWindow->selStart -= 1;
if( hexWindow->selEnd >= 1 ) hexWindow->selEnd -= 1;
}
else hexWindow->selEnd = hexWindow->selStart;
hexWindow->editedHigh = false;
break;
case kRightArrowCharCode:
if( hexWindow->selStart == hexWindow->selEnd )
{
hexWindow->selStart += 1;
hexWindow->selEnd += 1;
}
else hexWindow->selStart = hexWindow->selEnd;
hexWindow->editedHigh = false;
break;
case kUpArrowCharCode:
if( hexWindow->selStart == hexWindow->selEnd )
{
if( hexWindow->selStart >= 16 ) hexWindow->selStart -= 16;
else hexWindow->selStart = 0;
if( hexWindow->selEnd >= 16 ) hexWindow->selEnd -= 16;
else hexWindow->selEnd = 0;
}
else hexWindow->selEnd = hexWindow->selStart;
hexWindow->editedHigh = false;
break;
case kDownArrowCharCode:
if( hexWindow->selStart == hexWindow->selEnd ) {
hexWindow->selStart += 16;
hexWindow->selEnd += 16; }
else hexWindow->selStart = hexWindow->selEnd;
hexWindow->editedHigh = false;
break;
}
return error;
}
/*** FIND SELECTED REGIONS ***/
OSStatus FindSelectedRegions( WindowRef window, RgnHandle hexRgn, RgnHandle asciiRgn )
{
// get hex info structure
Plug_WindowRef plugWindow = Host_GetPlugWindowFromWindowRef( window );
HexWindowPtr hexWindow = (HexWindowPtr) Host_GetWindowRefCon( plugWindow );
// get window bounds
Rect windowBounds, subtractRect;
RgnHandle subtractRgn = NewRgn();
GetWindowPortBounds( window, &windowBounds );
// start and end points of selection relative to first visable char
Boolean clipTop, clipBottom;
signed long startLine = hexWindow->selStart/16 - hexWindow->topline;
signed long endLine = (hexWindow->selEnd - hexWindow->selEnd %16)/16 - hexWindow->topline +1;
// find hex region
Rect hexSelRect;
SetRect( &hexSelRect, kHexCharWidth *11 -1, startLine * kHexLineHeight, kHexCharWidth *58 +1, endLine * kHexLineHeight );
OffsetRect( &hexSelRect, 0, kHeaderHeight + kTextMargin + 2 );
clipTop = hexSelRect.top < kHeaderHeight + kTextMargin +2;
clipBottom = hexSelRect.bottom > windowBounds.bottom - kTextMargin -2;
if( clipTop ) hexSelRect.top = kHeaderHeight + kTextMargin +2;
if( clipBottom ) hexSelRect.bottom = windowBounds.bottom - kTextMargin -2;
RectRgn( hexRgn, &hexSelRect );
if( !clipTop )
{
SetRect( &subtractRect, hexSelRect.left, hexSelRect.top, hexSelRect.left + (hexWindow->selStart % 16) * (kHexCharWidth *3), hexSelRect.top + kHexLineHeight );
RectRgn( subtractRgn, &subtractRect );
DiffRgn( hexRgn, subtractRgn, hexRgn );
}
if( !clipBottom )
{
SetRect( &subtractRect, hexSelRect.right - (16 - hexWindow->selEnd % 16) * (kHexCharWidth *3), hexSelRect.bottom - kHexLineHeight, hexSelRect.right, hexSelRect.bottom );
RectRgn( subtractRgn, &subtractRect );
DiffRgn( hexRgn, subtractRgn, hexRgn );
}
// find ascii region
Rect asciiSelRect;
SetRect( &asciiSelRect, kHexCharWidth *60 -1, startLine * kHexLineHeight, kHexCharWidth *76 +1, endLine * kHexLineHeight );
OffsetRect( &asciiSelRect, 0, kHeaderHeight + kTextMargin + 2 );
if( clipTop ) asciiSelRect.top = kHeaderHeight + kTextMargin +2;
if( clipBottom ) asciiSelRect.bottom = windowBounds.bottom - kTextMargin -2;
RectRgn( asciiRgn, &asciiSelRect );
if( !clipTop )
{
SetRect( &subtractRect, asciiSelRect.left, asciiSelRect.top, asciiSelRect.left + (hexWindow->selStart % 16) * kHexCharWidth, asciiSelRect.top + kHexLineHeight );
RectRgn( subtractRgn, &subtractRect );
DiffRgn( asciiRgn, subtractRgn, asciiRgn );
}
if( !clipBottom )
{
SetRect( &subtractRect, asciiSelRect.right - (16 - hexWindow->selEnd % 16) * kHexCharWidth, asciiSelRect.bottom - kHexLineHeight, asciiSelRect.right, asciiSelRect.bottom );
RectRgn( subtractRgn, &subtractRect );
DiffRgn( asciiRgn, subtractRgn, asciiRgn );
}
// clear up
DisposeRgn( subtractRgn );
return noErr;
}
/*** UPDATE SELECTION ***/
OSStatus UpdateSelection( WindowRef window, Boolean editingHex )
{
// get controls
ControlRef root, hex, ascii;
GetRootControl( window, &root );
GetIndexedSubControl( root, 3, &hex );
GetIndexedSubControl( root, 4, &ascii );
// reflect selection
Size actualSize;
ControlEditTextSelectionRec selection;
GetControlData( editingHex? hex:ascii, kControlEditTextPart, kControlEditTextSelectionTag, sizeof(ControlEditTextSelectionRec), &selection, &actualSize );
if( editingHex )
{
selection.selStart /= 3;
selection.selEnd = (selection.selEnd +1) /3;
}
else
{
selection.selStart *= 3;
selection.selEnd = (selection.selEnd *3) -1;
}
SetControlData( editingHex? ascii:hex, kControlEditTextPart, kControlEditTextSelectionTag, actualSize, &selection );
return noErr;
}
/********************/
/* CONTROL HANDLING */
/********************/
/*** TRACK SCROLL BAR ***/
pascal void TrackScrollbar( ControlRef control, short part )
{
WindowRef window = GetControlOwner(control);
Plug_WindowRef plugWindow = Host_GetPlugWindowFromWindowRef( window );
HexWindowPtr hexWindow = (HexWindowPtr) Host_GetWindowRefCon( plugWindow );
// decide how many lines to scroll ( and in which direction )
short startValue, delta, endValue, max;
if( !part ) return;
switch( part )
{
case kControlUpButtonPart: // up (20)
delta = -1;
break;
case kControlDownButtonPart: // down (21)
delta = 1;
break;
case kControlPageUpPart: // page up (22)
delta = hexWindow->topline - hexWindow->bottomline +1;
break;
case kControlPageDownPart: // page down (23)
delta = hexWindow->bottomline - hexWindow->topline -1;
break;
default:
delta = 0;
break;
}
// calculate and correct control value
max = GetControlMaximum( control );
startValue = GetControlValue( control );
endValue = startValue + delta;
if( endValue < 0 ) endValue = 0;
if( endValue > max ) endValue = max;
SetControlValue( control, endValue );
hexWindow->UpdateHexInfo();
// update the window
// InvalidateWindowRect( window, &windowBounds ); // doesn't update live scroll immediatly anyway, so may as well not call it
hexWindow->DrawContent();
}
/******************/
/* TIMER ROUTINES */
/******************/
/*** BLINK INSERTION POINT ***/
pascal void BlinkInsertionPoint( EventLoopTimerRef inTimer, void *inUserData )
{
#pragma unused( inTimer ) // inTimer can be null (if routine was not called from a timer)
// get window's info structure
WindowRef window = (WindowRef) inUserData;
Plug_WindowRef plugWindow = Host_GetPlugWindowFromWindowRef( window );
HexWindowPtr hexWindow = (HexWindowPtr) Host_GetWindowRefCon( plugWindow );
// if not focus window, don't flash cursor
if( !hexWindow->activeWindow ) return;
// if there's a selection, don't flash cursor
if( hexWindow->selStart != hexWindow->selEnd ) return;
// if insertion point is not within visable region, don't flash cursor
if( hexWindow->selStart < hexWindow->topline * 16 ) return;
if( hexWindow->selEnd >= (hexWindow->bottomline +1) * 16 ) return;
GrafPtr oldPort;
GetPort( &oldPort );
SetPortWindowPort( window );
Rect blinkRect;
long theStart = hexWindow->selStart - hexWindow->topline * 16;
long theEnd = hexWindow->selEnd - hexWindow->topline * 16;
if( hexWindow->editingHex ) SetRect( &blinkRect, kHexCharWidth *11 + (theStart %16) * (kHexCharWidth *3) -1, (theStart /16) * kHexLineHeight + kTextMargin +2,
kHexCharWidth *11 + (theStart %16) * (kHexCharWidth *3) +1, (theStart /16) * kHexLineHeight + kTextMargin +2 + kHexLineHeight );
else SetRect( &blinkRect, kHexCharWidth *60 + (theStart %16) * kHexCharWidth -1, (theStart /16) * kHexLineHeight + kTextMargin +2,
kHexCharWidth *60 + (theStart %16) * kHexCharWidth +1, (theStart /16) * kHexLineHeight + kTextMargin +2 + kHexLineHeight );
OffsetRect( &blinkRect, 0, kHeaderHeight );
InvertRect( &blinkRect );
hexWindow->insertionPointVisable = !hexWindow->insertionPointVisable;
SetPort( oldPort );
}

View File

@ -0,0 +1 @@
#include "Hex Editor.h" #ifndef _ResKnife_HexEditor_Events_ #define _ResKnife_HexEditor_Events_ // classic event handler #if !TARGET_API_MAC_CARBON typedef CALLBACK_API(OSStatus, ClassicEventHandlerProcPtr) (EventRecord *event, UInt32 eventKind, void *userData); typedef STACK_UPP_TYPE(ClassicEventHandlerProcPtr) ClassicEventHandlerUPP; enum { uppClassicEventHandlerProcInfo = 0x00000FF0 }; /* pascal 4_bytes Func(4_bytes, 4_bytes, 4_bytes) */ #ifdef __cplusplus inline ClassicEventHandlerUPP NewClassicEventHandlerUPP(ClassicEventHandlerProcPtr userRoutine) { return (ClassicEventHandlerUPP)NewRoutineDescriptor((ProcPtr)(userRoutine), uppClassicEventHandlerProcInfo, GetCurrentArchitecture()); } #else #define NewClassicEventHandlerUPP(userRoutine) (ClassicEventHandlerUPP)NewRoutineDescriptor((ProcPtr)(userRoutine), uppClassicEventHandlerProcInfo, GetCurrentArchitecture()) #endif #endif /*! * @function CarbonWindowEventHandler * @discussion */ pascal OSStatus CarbonWindowEventHandler( EventHandlerCallRef handler, EventRef event, void *userData ); /*! * @function CarbonHIEventHandler * @discussion */ pascal OSStatus CarbonHIEventHandler( EventHandlerCallRef handler, EventRef event, void *userData ); #if !TARGET_API_MAC_CARBON /*! * @function ClassicWindowEventHandler * @discussion */ pascal OSStatus ClassicWindowEventHandler( EventRecord *event, UInt32 eventKind, void *userData ); #endif /*! * @function ConstrainWindowResize */ pascal OSStatus ConstrainWindowResize( EventHandlerCallRef handler, EventRef event, void *userData ); /*! * @function SizeChanging */ OSStatus SizeChanging( WindowRef window, EventRef event ); /*! * @function SizeChanged */ OSStatus SizeChanged( WindowRef window ); /*! * @function HandleEditClick */ OSStatus HandleEditClick( WindowRef window, EventRef event, Point mouse, EventModifiers modifiers ); /*! * @function HandleEditDrag */ OSStatus HandleEditDrag( WindowRef window, EventRef event, Point mouse, EventModifiers modifiers ); /*! * @function HandleKeyDown */ OSStatus HandleKeyDown( WindowRef window, unsigned char charCode, EventModifiers modifiers ); /*! * @function HandleArrowKeyDown */ OSStatus HandleArrowKeyDown( WindowRef window, unsigned char charCode, EventModifiers modifiers ); /*! * @function FindSelectedRegions */ OSStatus FindSelectedRegions( WindowRef window, RgnHandle hexRgn, RgnHandle asciiRgn ); /*! * @function UpdateSelection */ OSStatus UpdateSelection( WindowRef window, Boolean editingHex ); /*! * @function HexKeyFilter */ pascal ControlKeyFilterResult HexKeyFilter( ControlRef theControl, SInt16 *keyCode, SInt16 *charCode, EventModifiers *modifiers ); /*! * @function AsciiKeyFilter */ pascal ControlKeyFilterResult AsciiKeyFilter( ControlRef theControl, SInt16 *keyCode, SInt16 *charCode, EventModifiers *modifiers ); /*! * @function TrackScrollbar */ pascal void TrackScrollbar( ControlRef control, short part ); /*! * @function BlinkInsertionPoint */ pascal void BlinkInsertionPoint( EventLoopTimerRef inTimer, void *inUserData ); #endif

View File

@ -0,0 +1,409 @@
#include "HexWindow.h"
#include "Events.h"
#include "stdio.h"
// #include "strings.h"
extern globals g;
extern prefs p;
/*** CREATOR ***/
HexWindow::HexWindow( WindowRef newWindow )
{
// set contents to zero
memset( this, 0, sizeof(HexWindow) );
// initalise the bits that need initalising
window = newWindow;
#if USE_NIBS
// load stuff from nib file
#elif TARGET_API_MAC_CARBON
// create root control
ControlRef root;
CreateRootControl( window, &root );
// create header
header = null;
left = null;
right = null;
// create scroll bar
Rect windowBounds;
ControlActionUPP liveTrackingProc = NewControlActionUPP( TrackScrollbar );
GetWindowPortBounds( window, &windowBounds );
windowBounds.top += kHeaderHeight -1;
windowBounds.bottom -= kScrollBarWidth -2;
windowBounds.left = windowBounds.right - kScrollBarWidth +1;
windowBounds.right += 1;
CreateScrollBarControl( window, &windowBounds, 0, 0, 0, 0, true, liveTrackingProc, &scrollbar );
ControlID id = { kScrollbarSignature, 0 };
SetControlID( scrollbar, &id );
#else
// only create a scroll bar
scrollbar = GetNewControl( kSystem7ScrollBarControl, window );
#endif
}
/*** DESTRUCTOR ***/
HexWindow::~HexWindow( void )
{
// Host_ReleaseResourceData( hexInfo->data ); // decreases refCount
RemoveEventLoopTimer( timer );
DisposeControl( scrollbar );
}
/**********/
/* EVENTS */
/**********/
/*** BOUNDS CHANGING ***/
OSStatus HexWindow::BoundsChanging( EventRef event )
{
OSStatus error = noErr;
#if TARGET_API_MAC_CARBON
// check that window is not just being dragged
UInt32 attributes;
error = GetEventParameter( event, kEventParamAttributes, typeUInt32, null, sizeof(UInt32), null, &attributes );
if( error || attributes & kWindowBoundsChangeUserDrag ) return eventNotHandledErr;
// get new bounds
Rect windowBounds;
error = GetEventParameter( event, kEventParamCurrentBounds, typeQDRectangle, null, sizeof(Rect), null, &windowBounds );
if( error ) return eventNotHandledErr;
// constrain window width
UInt8 modulo = (windowBounds.right - windowBounds.left - 13*kHexCharWidth - kScrollBarWidth) % (4*kDataBlockWidth);
if( modulo < (2*kDataBlockWidth) ) windowBounds.right -= modulo;
else windowBounds.right += (4*kDataBlockWidth) - modulo;
// constrain window height
modulo = (windowBounds.bottom - windowBounds.top - kHeaderHeight - 2*kTextMargin -4) % kHexLineHeight;
if( modulo < (kHexLineHeight/2) ) windowBounds.bottom -= modulo;
else windowBounds.bottom += kHexLineHeight - modulo;
// update window rect to constrained version
if( (windowBounds.bottom - windowBounds.top) < kMinimumWindowHeight ) windowBounds.bottom = windowBounds.top + kMinimumWindowHeight;
if( (windowBounds.right - windowBounds.left) < kMinimumWindowWidth ) windowBounds.right = windowBounds.left + kMinimumWindowWidth;
error = SetEventParameter( event, kEventParamCurrentBounds, typeQDRectangle, sizeof(Rect), &windowBounds );
if( error ) error = eventNotHandledErr;
if( g.systemVersion < kMacOSX ) return noErr;
error = BoundsChanged( event );
#endif
return error;
}
/*** BOUNDS CHANGED ***/
OSStatus HexWindow::BoundsChanged( EventRef event )
{
Rect windowBounds;
OSStatus error = GetEventParameter( event, kEventParamCurrentBounds, typeQDRectangle, null, sizeof(Rect), null, &windowBounds );
if( error ) return eventNotHandledErr;
#if TARGET_API_MAC_CARBON
// resize header
SizeControl( header, (windowBounds.right - windowBounds.left) +2, kHeaderHeight +1 );
SizeControl( left, (windowBounds.right - windowBounds.left) /2 -4, kHeaderHeight -4 );
SizeControl( right, (windowBounds.right - windowBounds.left) /2 -4, kHeaderHeight -4 );
MoveControl( right, (windowBounds.right - windowBounds.left) /2, 2 );
#endif
// resize scrollbar
MoveControl( scrollbar, (windowBounds.right - windowBounds.left) - kScrollBarWidth +1, kHeaderHeight -1 );
SizeControl( scrollbar, kScrollBarWidth, (windowBounds.bottom - windowBounds.top) - kHeaderHeight - kScrollBarWidth +3 );
// calculate new scrollbar values & redraw window
UpdateHexInfo();
InvalidateWindowRect( window, &windowBounds );
EventRef updateEvent;
error = CreateEvent( null, kEventClassWindow, kEventWindowUpdate, GetCurrentEventTime(), 0, &updateEvent );
if( error == noErr )
{
SetEventParameter( updateEvent, kEventParamDirectObject, typeWindowRef, sizeof(WindowRef), &window );
SendEventToWindow( updateEvent, window );
ReleaseEvent( updateEvent );
}
return noErr;
}
/*** CONTENT CLICK ***/
OSStatus HexWindow::ContentClick( EventRef event )
{
#pragma unused( event )
return eventNotHandledErr;
}
/*** DRAW CONTENT ***/
OSStatus HexWindow::DrawContent( EventRef event )
{
#pragma unused( event ) // could be null if I called this directly, therefore I ignore the param
// set window
GrafPtr oldPort;
GetPort( &oldPort );
SetPortWindowPort( window );
// initalise rects
RGBColour colour;
Rect windowBounds, drawingBounds;
GetWindowPortBounds( window, &windowBounds );
SetRect( &drawingBounds, windowBounds.left, windowBounds.top + kHeaderHeight, windowBounds.right - kScrollBarWidth +1, windowBounds.bottom );
SetRect( &hexRect, kHexCharWidth *11 -3, kTextMargin + kHeaderHeight, kHexCharWidth *58 +3, windowBounds.bottom - kTextMargin );
SetRect( &asciiRect, kHexCharWidth *60 -3, kTextMargin + kHeaderHeight, kHexCharWidth *76 +3, windowBounds.bottom - kTextMargin );
#if Use_GWorlds
CGrafPtr origPort;
GDHandle origDev;
GWorldPtr theGWorld;
PixMapHandle thePixMap;
// create GWorld
GetGWorld( &origPort, &origDev );
// ( storage, bit depth, rect, colour table, GDevice, option flags ) // bit depth 0 = screen depth
NewGWorld( &theGWorld, p.GWorldDepth, &drawingBounds, null, null, 0 );
if( !theGWorld )
{
Host_DebugError( "\pNewGWorld() failed", 0 );
return eventNotHandledErr;
}
SetGWorld( theGWorld, null );
thePixMap = GetGWorldPixMap( theGWorld );
// lock the pixelmap in place
Boolean pixelsLocked = LockPixels( thePixMap );
if( !pixelsLocked )
{
UpdateGWorld( &theGWorld, 0, &drawingBounds, null, null, 0 );
pixelsLocked = LockPixels( thePixMap );
if( !pixelsLocked ) // if I still can't lock the damn pixels, give up! (don't even attempt writing to a moving target :)
{
SetGWorld( origPort, origDev );
DisposeGWorld( theGWorld );
Host_DebugError( "\pUpdateGWorld() failed", 0 );
return eventNotHandledErr;
}
}
#endif
// set font
short font;
GetFNum( "\pCourier", &font );
TextFont( font );
TextFace( 0 );
TextSize( 12 );
PenNormal();
// clear the background
RGBBackColor( &g.bgColour );
EraseRect( &drawingBounds );
// set text colour
if( activeWindow )
colour = g.black;
else colour = g.textColour;
RGBForeColor( &colour );
// draw box around hex
RGBBackColor( &g.white );
EraseRect( &hexRect );
FrameRect( &hexRect );
if( activeWindow && p.GWorldDepth > 1 )
{
RGBForeColor( &g.white );
MoveTo( hexRect.left, hexRect.bottom );
LineTo( hexRect.right, hexRect.bottom );
LineTo( hexRect.right, hexRect.top );
RGBForeColor( &g.bevelColour );
MoveTo( hexRect.right, hexRect.top -1 );
LineTo( hexRect.left -1, hexRect.top -1 );
LineTo( hexRect.left -1, hexRect.bottom );
}
// draw box around ascii
RGBForeColor( &colour );
RGBBackColor( &g.white );
EraseRect( &asciiRect );
FrameRect( &asciiRect );
if( activeWindow && p.GWorldDepth > 1 )
{
RGBForeColor( &g.white );
MoveTo( asciiRect.left, asciiRect.bottom );
LineTo( asciiRect.right, asciiRect.bottom );
LineTo( asciiRect.right, asciiRect.top );
RGBForeColor( &g.bevelColour );
MoveTo( asciiRect.right, asciiRect.top -1 );
LineTo( asciiRect.left -1, asciiRect.top -1 );
LineTo( asciiRect.left -1, asciiRect.bottom );
}
// hilight where selected text will be
if( selStart != selEnd )
{
// get regions of selected text
RgnHandle hexRgn = NewRgn(), asciiRgn = NewRgn(), insetRgn = NewRgn();
FindSelectedRegions( window, hexRgn, asciiRgn );
// set foreground colour to hilight colour
RGBColour hilightColour;
GetPortHilightColour( GetWindowPort(window), &hilightColour );
RGBForeColor( &hilightColour );
// draw what needs to be drawn
PenSize( 2, 2 );
if( editingHex ) PaintRgn( hexRgn );
else FrameRgn( hexRgn );
if( !editingHex ) PaintRgn( asciiRgn );
else FrameRgn( asciiRgn );
PenNormal();
DisposeRgn( hexRgn );
DisposeRgn( asciiRgn );
DisposeRgn( insetRgn );
}
// reset text colour
if( activeWindow )
colour = g.black;
else colour = g.textColour;
RGBForeColor( &colour );
// get useful data
Plug_WindowRef plugWindow = Host_GetPlugWindowFromWindowRef( window );
Plug_ResourceRef resource = Host_GetTargetResource( plugWindow );
// get resource length & lock data handle
UInt32 length = Host_GetResourceSize( resource ); // which of these two would be faster?
// UInt32 length = GetHandleSize( data ); // the host callback returns a value from a struct, GetHandleSize probably does the same
HLock( data );
if( Host_GetResourceSize( resource ) != GetHandleSize( data ) )
{
SetGWorld( origPort, origDev );
Host_DebugError( "\presource size != handle size", Host_GetResourceSize( resource ) ); // would be nice if I could pass both values! (any one know how to convert a number to > 1? - i.e. use "12.34" to pass 12 and 34)
SetGWorld( theGWorld, null );
}
// init variables
char buffer[16*4 +11];
long addr; // offset of byte in current res chunk
UInt32 line, // current line number
currentByte = topline *16; // offset of byte in resource
short hexPos, asciiPos;
unsigned char ascii, hex1, hex2; // HexEdit uses 'register short' not 'unsigned char' ?!?!
// start line count at scroll value
for( line = topline; line <= (lastline < bottomline? lastline:bottomline); line++ )
{
hexPos = 10;
asciiPos = 59;
sprintf( buffer, "%08lX: ", currentByte );
// draw bytes
for( addr = 0; addr < 16; addr++ )
{
if( currentByte < length )
{
BlockMoveData( *data + currentByte, &ascii, 1 );
hex1 = ascii;
hex2 = ascii;
hex1 >>= 4;
hex1 &= 0x0F;
hex2 &= 0x0F;
hex1 += (hex1 < 10)? 0x30 : 0x37;
hex2 += (hex2 < 10)? 0x30 : 0x37;
buffer[hexPos++] = hex1;
buffer[hexPos++] = hex2;
buffer[hexPos++] = 0x20;
if( ascii >= p.lowChar && ascii < p.highChar )
buffer[asciiPos++] = ascii;
else buffer[asciiPos++] = 0x2E; // full stop
}
else
{
// without this the ascii would be printed right next to the hex on the last line
buffer[hexPos++] = 0x20;
buffer[hexPos++] = 0x20;
buffer[hexPos++] = 0x20;
buffer[asciiPos++] = 0x20;
}
// fill hex/ascii gap with a space to make it print
buffer[58] = 0x20;
// advance current byte
currentByte++;
}
MoveTo( kHexCharWidth, kHeaderHeight + kTextMargin + kHexLineHeight*(line - topline +1) );
DrawText( buffer, 0, 75 ); // buffer, first byte, byte count
}
// unlock handle and record window heights
HUnlock( data );
#if Use_GWorlds
SetGWorld( origPort, origDev );
RGBBackColor( &g.white );
RGBForeColor( &g.black );
CopyBits( GetPortBitMapForCopyBits(theGWorld), GetPortBitMapForCopyBits(GetWindowPort(window)), &drawingBounds /*source rect*/, &drawingBounds /*dest rect*/, srcCopy, null );
UnlockPixels( thePixMap ); // line redundant as GWorld is disposed of next!
DisposeGWorld( theGWorld );
#endif
// restore old port
SetPort( oldPort );
return eventNotHandledErr;
}
/****************/
/* MAINTAINANCE */
/****************/
/*** UPDATE HEX INFO ***/
OSStatus HexWindow::UpdateHexInfo( void )
{
// hex and ascii rects
Rect windowBounds;
GetWindowPortBounds( window, &windowBounds );
SetRect( &hexRect, kHexCharWidth *11 -3, kTextMargin + kHeaderHeight, kHexCharWidth *58 +3, windowBounds.bottom - kTextMargin );
SetRect( &asciiRect, kHexCharWidth *60 -3, kTextMargin + kHeaderHeight, kHexCharWidth *76 +3, windowBounds.bottom - kTextMargin );
// scrollbar globals
firstline = 0;
topline = GetControlValue( scrollbar );
bottomline = ((windowBounds.bottom - windowBounds.top - kHeaderHeight - 2*kTextMargin -4) / kHexLineHeight) + topline -1;
lastline = (GetHandleSize( data ) /16) - (GetHandleSize( data ) %16? 0:1);
// scrollbar values
SInt32 number = lastline - (bottomline - topline);
if( number <= 0 ) SetControlValue( scrollbar, 0 );
SetControlMaximum( scrollbar, (number > 0)? number:0 );
SetControlViewSize( scrollbar, bottomline - topline );
return noErr;
}
/*** INSERT BYTES ***/
Boolean HexWindow::InsertBytes( void *newData, signed long length, unsigned long offset )
{
signed long size = (signed long) GetHandleSize( data );
if( size + length <= 0 ) length = -size; // don't dispose of resource, just set it to zero length
SInt8 state = HGetState( data );
HLock( data );
if( length > 0 ) // writing things
{
SetHandleSize( data, size + length );
if( MemError() ) return false;
BlockMoveData( *data + offset, *data + offset + length, size - offset );
BlockMoveData( newData, *data + offset, length );
}
else if( length < 0 ) // deleting things
{
BlockMoveData( *data + offset, *data + offset + length, size - offset );
SetHandleSize( data, size + length );
if( MemError() ) return false;
}
HSetState( data, state );
return true;
}

View File

@ -0,0 +1 @@
#include "Hex Editor.h" /*! * @header HexWindow * @discussion This is my data structure for saving all data which pertains to one editing session. Each window has one and only one associated HexWindow class. */ /*! * @class HexWindow * @abstract Stors data pertinanet to a window. * @discussion This class is stored in the refcon of the window, and contains all the methods necessary to maintain the window's groovy looks :-) */ typedef class HexWindow { /*! @var window Stores the Mac OS <tt>WindowRef</tt> pertaining to this window. */ WindowRef window; /*! @var header Header control (the grey bar at the top of the window). */ ControlRef header; /*! @var left Left hand side static text control (in the header). */ ControlRef left; /*! @var right Right hand side static text control (in the header). */ ControlRef right; /*! @var scrollbar Scroll bar down the right hand side */ ControlRef scrollbar; #if !TARGET_API_MAC_CARBON /*! @var themeSavvy True if this window is using an Appearance Manager WDEF. (Also used to determine if Appearance controls should be drawn if this window.) */ Boolean themeSavvy; #endif public: // all these variables should be private // non-controls version /*! @var hexRect The text well in which hexadecimal is drawn */ Rect hexRect; /*! @var asciiRect The text well in which ASCII is drawn */ Rect asciiRect; /*! @var selStart offset of first char of selection */ UInt32 selStart; /*! @var selEnd if selEnd == selStart, no selection exists */ UInt32 selEnd; /*! @var timer blinks the insertion point */ EventLoopTimerRef timer; Handle data; Boolean editingHex; // currently editing in hexadecimal? Boolean editedHigh; // already typed part of this char Boolean activeWindow; // is this window the user focus? Boolean insertionPointVisable; SInt8 hexChar; // the data currently being typed UInt32 firstline; // first line of valid data UInt32 lastline; // last line of valid data UInt32 topline; // line at top of screen UInt32 bottomline; // line at bottom of screen public: // methods HexWindow( WindowRef newWindow = null ); ~HexWindow( void ); // events /*! * @function BoundsChanging */ OSStatus BoundsChanging( EventRef event ); /*! * @function BoundsChanged */ OSStatus BoundsChanged( EventRef event ); /*! * @function ContentClick */ OSStatus ContentClick( EventRef event ); /*! * @function DrawContent */ OSStatus DrawContent( EventRef event = null ); /*! * @function UpdateHexInfo */ OSStatus UpdateHexInfo( void ); /*! * @function InsertBytes */ Boolean InsertBytes( void *data, signed long length, unsigned long offset ); friend OSStatus Plug_InitInstance( Plug_PlugInRef plug, Plug_ResourceRef resource ); } HexWindow, *HexWindowPtr;

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
#include "Hex Editor.h" #ifndef _ResKnife_HexEditor_Initalisation_ #define _ResKnife_HexEditor_Initalisation_ /*! * @function InitGlobals */ OSStatus InitGlobals( void ); #endif

View File

@ -0,0 +1,233 @@
#include "Utility.h"
/**********************/
/* QUICKDRAW ROUTINES */
/**********************/
/*** SET COLOUR ***/
void SetColour( RGBColor *colour, UInt16 red, UInt16 green, UInt16 blue )
{
colour->red = red;
colour->green = green;
colour->blue = blue;
}
/*** MAKE LOCAL ***/
void MakeLocal( WindowRef window, Point globalPoint, Point *localPoint )
{
GrafPtr oldPort;
GetPort( &oldPort );
SetPortWindowPort( window );
localPoint->h = globalPoint.h;
localPoint->v = globalPoint.v;
GlobalToLocal( localPoint );
SetPort( oldPort );
}
/*** MAKE GLOBAL ***/
void MakeGlobal( WindowRef window, Point localPoint, Point *globalPoint )
{
GrafPtr oldPort;
GetPort( &oldPort );
SetPortWindowPort( window );
globalPoint->h = localPoint.h;
globalPoint->v = localPoint.v;
LocalToGlobal( globalPoint );
SetPort( oldPort );
}
/*****************************/
/* HEX <==> ASCII CONVERSION */
/*****************************/
/*** ASCII TO TEXT ***/
void AsciiToText( char *source, char *dest, unsigned long size )
{
char ascii = 0x00, text = 0x00;
unsigned long sourceOffset = 0, destOffset = 0;
while( sourceOffset < size )
{
ascii = *(source + sourceOffset);
if( ascii < 0x20 || ascii >= 0x7F ) text = (char) 0x2E; // full stop
else if( ascii == 0x20 ) text = (char) 0xCA; // nbsp
else text = ascii;
*(dest + destOffset++) = text;
sourceOffset++;
}
}
/*** ASCII TO HEX ***/
void AsciiToHex( char *source, char *dest, unsigned long size )
{
char hex1 = 0x00, hex2 = 0x00;
unsigned long sourceOffset = 0, destOffset = 0;
while( sourceOffset < size )
{
hex1 = *(source + sourceOffset);
hex2 = *(source + sourceOffset);
hex1 >>= 4;
hex1 &= 0x0F;
hex2 &= 0x0F;
hex1 += (hex1 < 10)? 0x30 : 0x37;
hex2 += (hex2 < 10)? 0x30 : 0x37;
*(dest + destOffset++) = hex1;
*(dest + destOffset++) = hex2;
*(dest + destOffset++) = 0x20;
sourceOffset++;
}
}
/*** HEX TO ASCII ***/
void HexToAscii( char *source, char *dest, unsigned long size )
{
char currentByte = 0x00, newByte = 0x00, tempByte = 0x00;
unsigned long sourceOffset = 0, destOffset = 0;
while( sourceOffset < size )
{
currentByte = *(source + sourceOffset);
if( currentByte >= 0x30 && currentByte <= 0x39 ) newByte = currentByte - 0x30; // 0 to 9
else if( currentByte >= 0x41 && currentByte <= 0x46 ) newByte = currentByte - 0x37; // A to F
else if( currentByte >= 0x61 && currentByte <= 0x66 ) newByte = currentByte - 0x57; // a to f
else newByte = 0x00;
newByte <<= 4;
currentByte = *(source + sourceOffset +1);
if( currentByte >= 0x30 && currentByte <= 0x39 ) tempByte = currentByte - 0x30; // 0 to 9
else if( currentByte >= 0x41 && currentByte <= 0x46 ) tempByte = currentByte - 0x37; // A to F
else if( currentByte >= 0x61 && currentByte <= 0x66 ) tempByte = currentByte - 0x57; // a to f
else tempByte = 0x00;
newByte += tempByte & 0x0F;
*(dest + destOffset++) = newByte;
sourceOffset += 3;
}
}
/*** LONG TO HEX ***/
void LongToHex( char *source, char *dest )
{
// copy of AsciiToHex but with changes as noted
char hex1 = 0x00, hex2 = 0x00;
unsigned long sourceOffset = 0, destOffset = 0;
while( sourceOffset < sizeof(unsigned long) ) // size is always four
{
hex1 = *(source + sourceOffset);
hex2 = *(source + sourceOffset);
hex1 >>= 4;
hex1 &= 0x0F;
hex2 &= 0x0F;
hex1 += (hex1 < 10)? 0x30 : 0x37;
hex2 += (hex2 < 10)? 0x30 : 0x37;
*(dest + destOffset++) = hex1;
*(dest + destOffset++) = hex2; // no space inserted
sourceOffset++;
}
}
/*******************/
/* STRING ROUTINES */
/*******************/
/*** C STRING LENGTH ***/
unsigned long CStringLength( char *string )
{
unsigned long length;
Boolean end = false;
for( length = 0; end == false; length++ )
if( *(string + length) == 0x00 ) end = true;
return length;
}
/*** PASCAL STRING LENGTH ***/
unsigned char PStringLength( unsigned char *string )
{
return *string;
}
/*** TYPE TO C STRING ***/
void TypeToCString( const OSType type, char *string )
{
BlockMoveData( &type, &string[0], sizeof(OSType) );
string[sizeof(OSType)] = 0x00;
}
/*** TYPE TO PASCAL STRING ***/
void TypeToPString( const OSType type, Str255 string )
{
string[0] = sizeof(OSType);
BlockMoveData( &type, &string[1], sizeof(OSType) );
}
/*** TYPE TO CORE FOUNDATION STRING ***/
void TypeToCFString( const OSType type, CFStringRef *string )
{
char cString[5];
TypeToCString( type, (char *) &cString );
*string = CFStringCreateWithCString( CFAllocatorGetDefault(), (char *) &cString, kCFStringEncodingMacRoman );
}
/*** COPY C STRING ***/
void CopyCString( UInt8 *source, UInt8 *dest )
{
// #pragma warning off
while( *dest++ = *source++ );
// #pragma warning reset
}
/*** COPY PASCAL STRING ***/
void CopyPString( UInt8 *source, UInt8 *dest )
{
UInt8 length = *source, count;
for( count = 0; count <= length; count++ )
*dest++ = *source++;
}
/*** EQUAL C STRINGS ***/
Boolean EqualCStrings( UInt8 *source, UInt8 *dest )
{
while( *source != 0x00 )
if( *source++ != *dest++ ) return false;
return true;
}
/*** EQUAL PASCAL STRINGS ***/
Boolean EqualPStrings( UInt8 *source, UInt8 *dest )
{
UInt8 length = *source, count;
for( count = 0; count <= length; count++ )
if( *source++ != *dest++ ) return false;
return true;
}
/*** APPEND ONE PASCAL STRING ONTO ANOTHER ***/
void AppendPString( Str255 original, ConstStr255Param added )
{
short numberBytes = added[0]; // length of string to be added
short totalLength = added[0] + original[0];
if( totalLength > 255 ) // too long, adjust number of bytes to add
{
totalLength = 255;
numberBytes = totalLength - original[0];
}
BlockMoveData( &added[1], &original[totalLength-numberBytes + 1], numberBytes );
original[0] = totalLength; // new length of original string
while( ++totalLength <= 255 )
original[totalLength] = 0x00; // set rest of string to zero
}
/*****************/
/* MENU ROUTINES */
/*****************/
/*** ENABLE MENU COMMAND ***/
void EnableCommand( MenuRef menu, MenuCommand command, Boolean enable )
{
if( enable ) EnableMenuCommand( menu, command );
else DisableMenuCommand( menu, command );
}

View File

@ -0,0 +1,31 @@
#include "Hex Editor.h"
#ifndef _ResKnife_HexEditor_Utility_
#define _ResKnife_HexEditor_Utility_
/* QuickDraw Routines */
void SetColour( RGBColor *colour, UInt16 red, UInt16 green, UInt16 blue );
void MakeLocal( WindowRef window, Point globalPoint, Point *localPoint );
void MakeGlobal( WindowRef window, Point localPoint, Point *globalPoint );
/* ASCII <=> hex */
void AsciiToText( char *source, char *dest, unsigned long size );
void AsciiToHex( char *source, char *dest, unsigned long size );
void HexToAscii( char *source, char *dest, unsigned long size );
void LongToHex( char *source, char *dest );
/* strings */
unsigned long CStringLength( char *string );
unsigned char PStringLength( unsigned char *string );
void TypeToCString( const OSType type, char *string );
void TypeToPString( const OSType type, Str255 string );
void TypeToCFString( const OSType type, CFStringRef *string );
void CopyCString( UInt8 *source, UInt8 *dest );
void CopyPString( UInt8 *source, UInt8 *dest );
Boolean EqualCStrings( UInt8 *source, UInt8 *dest );
Boolean EqualPStrings( UInt8 *source, UInt8 *dest );
void AppendPString( Str255 original, ConstStr255Param added );
void EnableCommand( MenuRef menu, MenuCommand command, Boolean enable );
#endif

149
Hex Editor/Hex Editor.h Normal file
View File

@ -0,0 +1,149 @@
#if !TARGET_API_MAC_OS8
#include <Carbon/Carbon.h>
#endif
#ifndef _ResKnife_Plug_
#define _ResKnife_Plug_ 1
#include "HostCallbacks.h"
#endif
#ifndef _ResKnife_HexEditor_
#define _ResKnife_HexEditor_
// abbreviations
#define null NULL
#define Use_Nibs 0
#define Use_GWorlds 1
// Easire constants
#define RGBColour RGBColor
// Easier API call names
#define GetWindowRefCon( window ) (long) GetWRefCon( window )
#define SetWindowRefCon( window, refcon ) SetWRefCon( window, refcon )
#define GetWindowTitle( window, string ) GetWTitle( window, string )
#define SetWindowTitle( window, name ) SetWTitle( window, name )
#define InvalidateRect( bounds ) InvalRect( bounds )
#define InvalidateWindowRect( window, bounds ) (OSStatus) InvalWindowRect( window, bounds )
#define RectToRegion( region, rect ) RectRgn( region, rect )
#define SetPoint( point, x, y ) SetPt( point, x, y )
/* apperance.h */
#define SetThemeTextColour( c, d, cd ) (OSStatus) SetThemeTextColor( c, d, cd )
#define IsThemeInColour( d, cd ) (Boolean) IsThemeInColor( d, cd )
#define GetThemeAccentColours( out ) (OSStatus) GetThemeAccentColors( out )
#define SetThemeTextColourForWindow( w, a, d, cd ) (OSStatus) SetThemeTextColorForWindow( w, a, d, cd )
#define GetThemeBrushAsColour( b, d, cd, out ) (OSStatus) GetThemeBrushAsColor( b, d, cd, out )
#define GetThemeTextColour( c, d, cd, out) (OSStatus) GetThemeTextColor( c, d, cd, out)
/* some other file */
#define HilightColour( colour ) HiliteColor( colour )
#define GetPortHilightColour( window, colour ) GetPortHiliteColor( window, colour )
/* Global Variables */
struct globals
{
// application
Str255 fragName;
Str255 prefsName;
// system info
SInt32 systemVersion;
Boolean dragAvailable;
Boolean translucentDrag;
Boolean navAvailable;
Boolean useAppearance;
// colours
RGBColour white; // 0xFFFF, 65535
RGBColour bgColour; // 0xEEEE, 61166
RGBColour sortColour; // 0xDDDD, 56797
RGBColour bevelColour; // 0xAAAA, 43690
RGBColour textColour; // 0x7777, 30583
RGBColour frameColour; // 0x5555, 21845
RGBColour black; // 0x0000, 0
};
/* Preferences */
struct prefs
{
UInt32 version; // == kHexEditorCurrentVersion, when saved to disk allows older prefs to be read in
// highest and lowest chars displayed
UInt8 lowChar;
UInt8 highChar;
UInt8 GWorldDepth;
};
// MacOS versions
const SInt32 kMacOSSevenPointOne = 0x00000710;
const SInt32 kMacOSSevenPointFivePointFive = 0x00000755;
const SInt32 kMacOSEight = 0x00000800;
const SInt32 kMacOSEightPointFive = 0x00000850;
const SInt32 kMacOSEightPointSix = 0x00000860;
const SInt32 kMacOSNine = 0x00000900;
const SInt32 kMacOSNinePointOne = 0x00000910;
const SInt32 kMacOSTen = 0x00001000;
const SInt32 kMacOS71 = kMacOSSevenPointOne;
const SInt32 kMacOS755 = kMacOSSevenPointFivePointFive;
const SInt32 kMacOS8 = kMacOSEight;
const SInt32 kMacOS85 = kMacOSEightPointFive;
const SInt32 kMacOS86 = kMacOSEightPointSix;
const SInt32 kMacOS9 = kMacOSNine;
const SInt32 kMacOS91 = kMacOSNinePointOne;
const SInt32 kMacOSX = kMacOSTen;
/*** APPLE EVENT SUPPORT ***/
const OSType kResEditorAEType = FOUR_CHAR_CODE('ResK');
const OSType kResTransferType = FOUR_CHAR_CODE('rsrc');
enum DragReceiveType // copy & paste uses these too
{
kScrapFlavorTypeHex = FOUR_CHAR_CODE('HEX '),
kScrapFlavorTypeResource = kResTransferType
};
/*** CONSTANTS ***/
const UInt32 kHexEditorCurrentVersion = 0x00030003;
const UInt16 kHeaderHeight = 20;
const UInt16 kScrollBarWidth = 16;
const UInt16 kTextMargin = 5; // top & bottom margin for hand-drawn editing areas
const UInt16 kTextFrameBorder = 9; // border around controls
const UInt16 kTextInnerBuffer = 2; // border within controls
const UInt16 kHexCharWidth = 7;
const UInt16 kHexLineHeight = 11;
const UInt16 kDataBlockWidth = (8*kHexCharWidth);
const UInt16 kOffsetColumnWidth = (10*kHexCharWidth); // no need to consider border on leftmost edge of hex field
const UInt16 kMinimumWindowWidth = kOffsetColumnWidth + (4*kDataBlockWidth) + (3*kHexCharWidth) + kScrollBarWidth;
const UInt16 kDefaultWindowWidth = kMinimumWindowWidth + (4*kDataBlockWidth);
const UInt16 kMinimumWindowHeight = kHeaderHeight + (2*kTextMargin) + (10*kHexLineHeight) +4;
const UInt16 kDefaultWindowHeight = kMinimumWindowHeight + (6*kHexLineHeight);
const UInt32 kHeaderSignature = FOUR_CHAR_CODE('head');
const UInt32 kLeftTextSignature = FOUR_CHAR_CODE('left');
const UInt32 kRightTextSignature = FOUR_CHAR_CODE('rght');
const UInt32 kOffsetTextSignature = FOUR_CHAR_CODE('offs');
const UInt32 kHexTextSignature = FOUR_CHAR_CODE('hex ');
const UInt32 kAsciiTextSignature = FOUR_CHAR_CODE('asci');
const UInt32 kScrollbarSignature = FOUR_CHAR_CODE('scrl');
/* RESOURCES */
enum // menus
{
kEditorMenu = 128
};
enum // windows
{
kFileWindow7 = 128,
kFileWindow8 = 129
};
enum // controls
{
kSystem7ScrollBarControl = 128,
kAppearanceScrollBarControl = 129,
kNormalHeaderControl = 130
};
#endif

View File

@ -0,0 +1 @@
#include "Initalisation.h" globals g; /*** INITALISE NEW EDITOR INSTANCE ***/ OSStatus Plug_InitInstance( Plug_PlugInRef plug, Plug_ResourceRef resource ) { // get system version OSStatus error = Gestalt( gestaltSystemVersion, &g.systemVersion ); if( error ) return error; // create window Rect creationBounds; WindowRef window; SetRect( &creationBounds, 0, 0, kDefaultWindowWidth, kDefaultWindowHeight ); OffsetRect( &creationBounds, 8, 48 ); WindowAttributes attributes = kWindowCloseBoxAttribute | kWindowCollapseBoxAttribute | kWindowStandardHandlerAttribute | kWindowInWindowMenuAttribute; if( g.systemVersion >= kMacOSX ) attributes |= kWindowLiveResizeAttribute; error = CreateNewWindow( kDocumentWindowClass, attributes, &creationBounds, &window ); // register mac window with host and retreive plug window Plug_WindowRef plugWindow = Host_RegisterWindow( plug, resource, window ); // cerate new pict window class PictWindowPtr pictWindow = new PictWindow( window ); // set window refCon to my class Host_SetWindowRefCon( plugWindow, (UInt32) pictWindow ); // set the window pic to the data handle PicHandle picture = (PicHandle) Host_GetResourceData( resource ); if( picture == null ) Host_DisplayError( "\pNo picture could be obtained.", "\p", 0 ); // get pict rect PictInfo pictInfo; GetPictInfo( picture, &pictInfo, 0, 0, 0, 0 ); Rect pictRect; pictRect.top = 0; pictRect.left = 0; pictRect.right = pictInfo.sourceRect.right - pictInfo.sourceRect.left; pictRect.bottom = pictInfo.sourceRect.bottom - pictInfo.sourceRect.top; SizeWindow( window, pictRect.right, pictRect.bottom, false ); #if TARGET_API_MAC_CARBON ControlRef picControl; // this is better than SetWindowPic() in Carbon ControlButtonContentInfo content; content.contentType = kControlContentPictHandle; content.u.picture = picture; // bug: if handle dissapears, control is fucked CreatePictureControl( window, &pictRect, &content, true, &picControl ); // DrawOneControl( picControl ); // bug: work around for bug in ControlManager /* HLockHi( picture ); SetControlData( picControl, kControlPicturePart, kControlPictureHandleTag, sizeof(picture), *picture ); */ #else SetWindowPic( window, picture ); // this doesn't work properly on X #endif // show window ShowWindow( window ); SelectWindow( window ); return error; }

View File

@ -0,0 +1 @@
#include "PICT Editor.h" typedef class PictWindow PictWindow, *PictWindowPtr; /*** PICT WINDOW ***/ class PictWindow { WindowRef window; Rect rect; // size of picture, { 0, 0, x, y } public: PictWindow( WindowRef newWindow ); };

View File

View File

@ -0,0 +1,7 @@
#include "Initalisation.h"
/*** CONSTRUCTOR ***/
PictWindow::PictWindow( WindowRef newWindow )
{
window = newWindow;
}

Some files were not shown because too many files have changed in this diff Show More