
/* 
	mtClassHexViewer.m - This is a sample MetroTools tool module which 
	illustrates how a tool module is written. See the shell file 'MTool.m' and 
	the document 'ToolsAPI.wn' for more information. You are welcome to use any 
	code in this file in your development of a MetroTools' tool module.
	
	Author: Kathryn Koploy-Miller
	Date: 6/17/92
	Version: 1.0  
	Copyright: 1992 Metrosoft, All Rights Reserved.
*/

#import <stdlib.h>
#import <libc.h>
#import <strings.h>
#import <sys/file.h>
#import <streams/streams.h>
#import <appkit/ScrollView.h>
#import <appkit/Text.h>

#import "IconView.h"
#import "mtClassHexViewer.h"


/* hex dump defines */
#define  FILE_CHUNK  16
#define  SINGLE_LINE_LENGTH  16


@implementation mtClassHexViewer

- GetToolWindow:(Window**)theWind;
{
/* 
	This method is called when the user first selects the tool. It is 
	requesting your module's control window. The content view of the window is 
	gotten by MetroTools and is installed in the tool control area of the 
	MetroTools main window. Return the window in 'theWind'. The window's size 
	should be no larger than 460x360.
*/
	*theWind = toolWindow;
	
	return( self );
}

- DisplayPrefs
{
/* 
	This method is called when the user selects the 'Preferences' button on the 
	MetroTools main window when your tool is active. If you have preferences or 
	other auxillary controls that you don't want in the main tool area, place 
	them in your own window and bring that window up here. Typically, the 
	credits go into this window.
*/
	[prefsWindow makeKeyAndOrderFront:self];
	
	return( self );
}

- (BOOL) DisplayHelp
{
/*
	This method is called when the user selects the 'Help' button from the 
	MetroTools main window when your tool is active. 
	
	If you want to handle help in the default way, you don't need to do 
	anything here but return NO. If you return NO, that means that you didn't 
	handle the help request. MetroTools then searches for this module's help 
	file in the standard MetroTools help directories. These directories are: 
	
		MetroTools.app/Help
		/($HOME)/Apps/MetroToolModules/Help
		/LocalApps/MetroToolModules/Help
	
	The help file must be in rtf format and must have the naming convention of 
	'(toolname).help' where (toolname) is the name of your tool module. 
	
	If you wish to handle the help request yourself, return YES and MetroTools 
	will not do anything more.
*/
	
	return( NO );
}

- InitSelf:(unsigned short *)toolFlags
{
/*
	This method is called when MetroTools first loads it in. If there is any 
	intialization you would like to do upon loading, do it here. Note: 
	currently 'toolFlags' is unused. Set it to 0 for future compatibility.
*/

	*toolFlags = 0;
	
	return( self );
}

- doActivate
{
/*
	This method is called when the user selects your tool icon in the 
	MetroTools main window. If you have anything to set up before being the 
	current tool, do it here. This is called BEFORE it is displayed, so last 
	minute initialization can occur here.
*/

	return( self );
}

- doDeactivate
{
/* 
	This routine is called when the user selects another tool icon in the 
	MetroTools main window when your tool is active. If you have anything to 
	turn off or deallocate, do it here. Please, be kind to other tools. If you 
	are NOT the current tool, turn off any unnecessary animations, and 
	deallocate any unnecessary storage.
*/

	return( self );
}

- unload
{
/*
	This routine is called when MetroTools is about to quit and/or this tool is 
	about to be unloaded. If there is any last thing you need to do, such as 
	updating and closing files, do it here.
*/

	return( self );
}

/* drag-and-drop routines */

- (BOOL)MTiconEntered:(id*)iconView:(id*)fileNameTextField:(BOOL*)doFolders
{
/*
	This method is called by MetroTools when a file icon enters the tool panel, 
	and your tool is active. If the tool does not accept icons, it should 
	return NO and set the return variables to nominal values.

	If the does accept icons, it should return YES and set the return variables 
	appropriately. The id pointed to by iconView should be set to the id of the 
	view in the tool panel to be used to display icons as they are dragged in. 
	The id pointed to by fileNameTextField should be set to the id of a text 
	field to be used to display the name of the file represented by the icon 
	being dragged in. If either the icon view or the text field isn't used by 
	the tool, the tool should return nil for the corresponding id. The boolean 
	pointed to by doFolders should be set to reflect if the tool receives 
	folders as single items or as a series of file items representing the files 
	contained in the folder (and inside any folders contained in the folder).

	The tool may wish to make some visual indication of its own that an icon 
	has been dragged in. Upon returning YES,  MetroTools will render the icon 
	in the registered view and the represented file name in the registered text 
	field.
*/

	*iconView = iconWell;
	*fileNameTextField = fileNameText;
	*doFolders = NO;
	
	return( YES );
}

- (void)MTiconExited:sender
{
/*
	This method is called by MetroTools if the user drags an icon back out of 
	the panel, and you are the current tool. If the tool made some form of 
	additional visual indication of the icon being dragged into the panel, it 
	would probably "undo" that indication within this method. The tool might 
	also deallocate any structures allocated during the MTiconEntered method. 
	MetroTools takes care of clearing the icon view and file name fields, so 
	the tool need not worry about that.
*/
}

   
- (void)MTiconReleased:sender
{
/* 
	This method is called by MetroTools if the user releases an icon within the 
	panel and you are the current tool. This method allows the tool to take any 
	additional action required prior to processing the individual file or files 
	represented by the dropped icon, such as initializing or allocating data 
	structures. This is also a convenient place to grab the id of the 
	MetroTools tool controller object for later use.
*/
}


- (BOOL)MTprocessFile:(char *)name
{
/*
	This method is called by MetroTools for each file represented by an icon 
	dropped into the panel.

	This is the method that will actually perform some kind of processing on 
	the file. The name parameter contains a fully-qualified path name for the 
	represented file. The method would typically return YES to continue 
	processing the remaining files represented by the icon, if any.

	If the tool would like to suspend or abort processing of files, it would 
	return NO. This might be done in response to an error condition or in an 
	attempt to synchronize file processing with some otherwise asynchronous 
	activity monitored by the tool.

	To continue with processing after returning NO from the MTprocesFile: 
	method, the tool should invoke the MetroTools tool controller's MTdoNext: 
	method:

		[mtid MTdoNext:self];	(in ToolController.h)

	In this example, mtid refers to an id global to the tool that received the 
	tool controller object id during the MTiconReleased: method.

	To abort processing files represented by a dropped icon, the tool need not 
	perform any action on MetroTools, but should clear its icon view and file 
	name field.
*/
	[self loadFileAsHex:name];
	
	/* this example will return NO here so that we won't get multiple files. */
	
	return( NO );
}

- (void)MTfinished:sender
{
/*
	This method is called when there are no more files to process after being 
	called with a MTIconReseased: selector. Typically you would deallocate 
	temporary storage used during processing of files here. Also, you should 
	clear out the iconView and fileName fields here.
*/
}


/* support methods */

- loadFileAsHex:(char*)name
{
	int     in;
	int		i;
	int		count;
	int     total_bytes;
	char    ascii_line[SINGLE_LINE_LENGTH + 1];
	char    dot_string[SINGLE_LINE_LENGTH + 1];
	char	out_line[SINGLE_LINE_LENGTH * 6];
	char    hex_string[SINGLE_LINE_LENGTH * 5 + 1];
	char	a_char[4];
	NXStream *stream_ptr;
	
	/* inits */
	dot_string[SINGLE_LINE_LENGTH] = 0;
	hex_string[SINGLE_LINE_LENGTH * 2] = 0;
	total_bytes =0;
	
	/* read in file and convert to hex dump */
	if((in = open(name, O_RDONLY )) < 0)
		return( self );	
	
	if(!(stream_ptr = NXOpenMemory(NULL, 0, NX_READWRITE)))
		{
			close(in);
			return(self);
		}
	while( count = read(in, ascii_line, FILE_CHUNK))
		{
		    total_bytes += count;
			for(i=0; i<count; i++)
			   if((ascii_line[i] < ' ' ) || (ascii_line[i] > 127))
			   		dot_string[i] = '.';
				else
				    dot_string[i] = ascii_line[i];
			for(i=count; i<FILE_CHUNK; i++)
				dot_string[i] = ' ';
			dot_string[FILE_CHUNK] = '\0';
				
			for(i=0; i<SINGLE_LINE_LENGTH/2; i++)
			  {
			  	if(i*2+1 < count)
					{
			  			a_char[0] = (ascii_line[i*2] >> 4) & 0x0f;
						a_char[1] = ascii_line[i*2] & 0x0f;
						a_char[2] = (ascii_line[i*2 + 1] >> 4) & 0x0f;
						a_char[3] = ascii_line[i*2 + 1] & 0x0f;
			   			sprintf(&(hex_string[i*5]), " %X%X%X%X",a_char[0], 
							a_char[1], a_char[2], a_char[3]);

					}
				else if (i*2 < count)
					{
			  			a_char[0] = (ascii_line[i*2] >> 4) & 0x0f;
						a_char[1] = ascii_line[i*2] & 0x0f;
			    		sprintf(&(hex_string[i*5]), " %X%X  ",a_char[0], 
							a_char[1]);
					}
				else
			    	sprintf(&(hex_string[i*5]), "     ");
			
			   }
				
			hex_string[strlen(hex_string)] = '\0';
			sprintf(out_line, " %08X: %s  | %s\n", total_bytes, 
				hex_string, dot_string);
						
			NXWrite(stream_ptr, out_line, strlen(out_line)); /* appends */
		
		}
	
	/* now load the converted text into the text object */
	NXSeek(stream_ptr, 0, NX_FROMSTART);
	[[textScrollArea docView] readText:stream_ptr];
	[[textScrollArea docView] sizeToFit];
	
	NXClose(stream_ptr);	
	close(in);
	
	/* clear out the icon view as last thing we do */
	[(IconView*)iconWell clear];
	
	return( self );
}

@end
