2001-10-19 19:41:13 +00:00
# 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 )
{
2002-02-11 01:22:17 +00:00
// BlockMoveData( *data + currentByte, &ascii, 1 );
hex1 = * ( * data + currentByte ) ;
hex2 = * ( * data + currentByte ) ;
2001-10-19 19:41:13 +00:00
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 ;
}