home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Hack-Phreak Scene Programs
/
cleanhpvac.zip
/
cleanhpvac
/
HPACK78S.ZIP
/
amiga.c
next >
Wrap
C/C++ Source or Header
|
1992-11-26
|
26KB
|
896 lines
/****************************************************************************
* *
* HPACK Multi-System Archiver *
* =========================== *
* *
* Amiga-Specific Routines *
* AMIGA.C Updated 20/11/92 *
* *
* This program is protected by copyright and as such any use or copying of *
* this code for your own purposes directly or indirectly is highly uncool *
* and if you do so there will be....trubble. *
* And remember: We know where your kids go to school. *
* *
* Copyright 1992 Peter C. Gutmann. All rights reserved *
* *
****************************************************************************/
/* "The difference is not in the hardware, but in the operating system...
the Amiga has one, the PC has DOS" - James Pullen */
/* We can't include "defs.h" since some of the defines conflict with
built-in ones and Lattice/SAS C 5.10 doesn't seem to like them being
#undef'd and redefined, so we define the necessary defs.h defines here.
"You're talking about an Amiga compiler here" - N.McB
"It could be seen as a very good argument for believing in some form of
divine retribution" - Arne Rohde
"This compiler has a plethora of insects" - Misquote from the Amiga Rom
Kernel Reference Manual */
typedef unsigned char BOOLEAN;
#define FALSE 0
#define TRUE 1
#define OK 0
#define ERROR -1
#define inline
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <proto/dos.h> /* PNM 18 Nov 1992 */
#include <proto/exec.h>
#include <proto/icon.h>
#include <exec/memory.h>
#include <workbench/workbench.h>
#define _DEFS_DEFINED /* Trick crc16.h into not #including defs.h */
#include "error.h"
#include "filesys.h"
#include "flags.h"
#include "frontend.h"
#include "system.h"
#include "tags.h"
#include "hpacklib.h"
#include "io/hpackio.h"
#include "io/fastio.h"
#include "crc/crc16.h"
/* The time difference between the Amiga and Unix epochs, in seconds */
#define AMIGA_TIME_OFFSET 0x0F0C3F00L
/* DICE doesn't seem to have MODE_READWRITE defined */
#ifndef MODE_READWRITE
#define MODE_READWRITE 1004
#endif /* !MODE_READWRITE */
/* The maximum length of a file comment (80 chars + '\0') */
#define COMMENT_SIZE 81
/* AmigaDOS handles all files in terms of a FileHandle struct. The HPACK
routines can be generalized to handle this, but it's far easier to simply
add our own file table management code */
typedef struct DiskObject DISKOBJECT;
typedef struct FileHandle FILEHANDLE;
typedef struct FileInfoBlock FILEINFOBLOCK;
typedef struct FileLock LOCK;
typedef struct Image IMAGE;
typedef struct Message MESSAGE;
typedef struct MsgPort MSGPORT;
typedef struct StandardPacket STANDARDPACKET;
#define MAX_HANDLES 20
static FILEHANDLE *fileTable[ MAX_HANDLES ] = { NULL };
/* Find a free entry in the file table */
static int getHandle( void )
{
int i;
/* Search the file table for a free handle */
for( i = 0; i < MAX_HANDLES; i++ )
if( fileTable[ i ] == NULL )
return( i );
/* File table full */
return( ERROR );
}
/* Free a file table entry */
static inline void freeHandle( const FD theFile )
{
fileTable[ theFile ] = NULL;
}
/* All directories are accessed via read locks. If an error occurs, we have
to clear the read locks or they can't be written to any more. We do this
by keeping a global table of locks and stepping through unlocking
directories when we perform an error exit */
#define MAX_LOCKS 25
static LOCK *lockTable[ MAX_LOCKS ] = { NULL };
static int lockCount = 0;
static inline void addLock( const LOCK *theLock )
{
if( lockCount < MAX_LOCKS )
lockTable[ lockCount++ ] = theLock;
else
/* Should never happen */
puts( "Lock table overflow" );
}
static inline void clearLastLock( void )
{
if( lockCount )
lockTable[ --lockCount ] = NULL;
else
/* Should never happen */
puts( "Lock table underflow" );
}
void clearLocks( void )
{
while( lockCount )
{
UnLock( ( BPTR ) lockTable[ --lockCount ] );
lockTable[ lockCount ] = NULL;
}
}
/****************************************************************************
* *
* HPACKIO Functions *
* *
****************************************************************************/
/* Create a new file - use Open() with the MODE_NEWFILE parameter */
FD hcreat( const char *fileName, const int attr )
{
FILEHANDLE *theHandle;
FD theFD;
if( ( theHandle = ( FILEHANDLE * ) Open( fileName, MODE_NEWFILE ) ) == NULL || \
( theFD = getHandle() ) == ERROR )
return( ERROR );
fileTable[ theFD ] = theHandle;
return( theFD );
}
/* Open an existing file */
FD hopen( const char *fileName, const int mode )
{
FILEHANDLE *theHandle;
LONG openMode = ( mode != S_DENYNONE ) ? MODE_READWRITE : MODE_OLDFILE;
FD theFD;
if( ( theHandle = ( FILEHANDLE * ) Open( fileName, openMode ) ) == NULL || \
( theFD = getHandle() ) == ERROR )
return( ERROR );
fileTable[ theFD ] = theHandle;
return( theFD );
}
/* Close a file */
int hclose( const FD theFile )
{
Close( ( BPTR ) fileTable[ theFile ] );
freeHandle( theFile );
return( OK );
}
/* Read data from a file */
int hread( const FD theFile, void *buffer, const unsigned int count )
{
return( ( int ) Read( ( BPTR ) fileTable[ theFile ], buffer, ( long ) count ) );
}
/* Write data to a file */
int hwrite( const FD theFile, void *buffer, const unsigned int count )
{
return( ( int ) Write( ( BPTR ) fileTable[ theFile ], buffer, ( long ) count ) );
}
/* Seek to a position in a file */
long hlseek( const FD theFile, const long offset, const int origin )
{
/* The AmigaDOS Seek() call returns the *previous* position rather than
the current one, so we need to perform two calls, one to move the
pointer and a second one to find out where we now are. In addition
the origin codes are SEEK_SET = -1, SEEK_CURR = 0, SEEK_END = 1 so
we subtract one from the given codes to get the Amiga ones */
if( Seek( ( BPTR ) fileTable[ theFile ], offset, ( long ) origin - 1 ) != IO_ERROR )
return( Seek( ( BPTR ) fileTable[ theFile ], 0L, OFFSET_CURRENT ) );
else
return( IO_ERROR );
}
/* Return the current position in a file */
long htell( const FD theFile )
{
return( Seek( ( BPTR ) fileTable[ theFile ], 0L, OFFSET_CURRENT ) );
}
/* Truncate a file at the current position. Needs KS 2.0 or above. Under
KS 1.3 it's possible by sending an ACTION_SET_FILE_SIZE packet to the
file handler */
int htruncate( const FD theFile )
{
return( ( SetFileSize( theFile, OFFSET_BEGINNING, htell( theFile ) ) != IO_ERROR ) ? \
OK : IO_ERROR );
}
/* Remove a file */
int hunlink( const char *fileName )
{
return( DeleteFile( fileName ) ? OK : ERROR );
}
/* Create a directory. Since the lock is only transient, we don't bother
adding it to the lock table */
int hmkdir( const char *dirName, const int attr )
{
LOCK *dirLock;
if( ( dirLock = ( LOCK * ) CreateDir( dirName ) ) == NULL )
return( ERROR );
UnLock( ( BPTR ) dirLock );
return( OK );
}
/* Rename a file */
int hrename( const char *oldName, const char *newName )
{
return( Rename( oldName, newName ) ? OK : ERROR );
}
/* Set/change a file's attributes */
int hchmod( const char *fileName, const WORD attr )
{
return( SetProtection( fileName, ( long ) attr ) ? OK : ERROR );
}
/****************************************************************************
* *
* HPACKLIB Functions *
* *
****************************************************************************/
/* Modes for the CON: handler (raw and cooked) */
#define CON_MODE 0
#define RAW_MODE 1
/* Get a char, no echo. Needs KS 2.0 or above. Under KS 1.x it's possible
by sending an ACTION_SCREEN_MODE packet to the console handler */
int hgetch( void )
{
int ch;
SetMode( Input(), RAW_MODE );
Write( Output(), "\x1b[20l", 5 ); /* Turn off CRLF translation */
ch = getchar();
SetMode( Input(), CON_MODE );
return( ch );
}
/****************************************************************************
* *
* SYSTEM Functions *
* *
****************************************************************************/
/* Set a file's timestamp. Needs KS 2.0. Under 1.2 or 1.3 it's possible by
sending an ACTION_SET_DATE packet to the file's handler */
#define SECS_PER_DAY 86400 /* Seconds per day */
void setFileTime( const char *fileName, const LONG fileTime )
{
struct DateStamp dateStamp;
#if 0
MSGPORT *taskPort;
LOCK *dirLock, *fileLock;
MSGPORT *replyPort;
STANDARDPACKET packet;
char pFileName[ MAX_FILENAME + 1 ];
#endif /* 0 */
long seconds;
/* Extract the day, minute, tick counts and put in the DateStamp structure */
seconds = fileTime - AMIGA_TIME_OFFSET;
dateStamp.ds_Days = seconds / SECS_PER_DAY;
seconds %= SECS_PER_DAY;
dateStamp.ds_Minute = seconds / 60;
dateStamp.ds_Tick = ( seconds % 60 ) * TICKS_PER_SECOND;
/* Set the timestamp */
SetFileDate( fileName, &dateStamp );
#if 0
/* Try and open a message port to the file, and put a lock on it */
if( ( taskPort = ( MSGPORT * ) DeviceProc( fileName ) ) == NULL || \
( fileLock = ( LOCK * ) Lock( fileName, SHARED_LOCK ) ) == NULL )
return;
/* Get a lock on the directory containing the file, and convert the
filename to a Pascal string (euurgghh, Macintoshness!) */
dirLock = ( LOCK * ) ParentDir( fileLock );
UnLock( fileLock );
strcpy( pFileName + 1, findFilenameStart( fileName ) );
*pFileName = strlen( pFileName + 1 );
/* Get a port for the message reply */
if( replyPort = ( MSGPORT * ) CreatePort( 0L, 0L ) != NULL )
{
/* Set up the packet to send */
packet.sp_Msg.mn_Node.ln_Name = ( char * ) &( packet.sp_Pkt );
packet.sp_Pkt.dp_Link = &( packet.sp_Msg );
packet.sp_Pkt.dp_Port = replyPort;
packet.sp_Pkt.dp_Type = ACTION_SET_DATE;
packet.sp_Pkt.dp_Arg1 = ( LONG ) NULL;
packet.sp_Pkt.dp_Arg2 = ( LONG ) dirLock;
packet.sp_Pkt.dp_Arg3 = ( LONG ) pFileName >> 2;
packet.sp_Pkt.dp_Arg4 = ( LONG ) &dateStamp;
/* Send the message and wait for a reply */
PutMsg( taskPort, ( MESSAGE * ) &packet );
WaitPort( replyPort );
GetMsg( replyPort ); /* Status = packet.sp_Pkt.dp_Res1 */
DeletePort( replyPort );
}
/* Clean up */
UnLock( dirLock );
#endif /* 0 */
}
#ifndef GUI
/* The following two functions aren't needed for the GUI version */
#define DEFAULT_ROWS 24
#define DEFAULT_COLS 80
void getScreenSize( void )
{
/* Not really appropriate so just default to 24x80 */
screenWidth = DEFAULT_COLS;
screenHeight = DEFAULT_ROWS;
}
int getCountry( void )
{
return( 0 ); /* Default to US */
}
#endif /* GUI */
/* Find the first/next file in a directory. The Amiga requires that a
lock be placed on a directory before it is accessed. These functions
try to unlock a directory as soon as possible once they've finished with
it rather than relying on findEnd(), to allow other processes to access
the information as well */
static void getFileInfo( FILEINFO *fileInfo )
{
FILEINFOBLOCK *infoBlock = ( FILEINFOBLOCK * ) fileInfo->infoBlock; /* Took "&" off parameter, PNM 22 Nov 92 */
/* Copy relevant fields across to fileInfo block. When converting the
timestamp we approximate 1 tick == 1 second, which is close enough */
fileInfo->isDir = infoBlock->fib_DirEntryType > 0;
strcpy( fileInfo->fName, infoBlock->fib_FileName );
fileInfo->fSize = infoBlock->fib_Size;
fileInfo->fTime = AMIGA_TIME_OFFSET + \
( infoBlock->fib_Date.ds_Days * 86400 ) + \
( infoBlock->fib_Date.ds_Minute * 60 ) + \
( infoBlock->fib_Date.ds_Tick / TICKS_PER_SECOND );
fileInfo->fAttr = infoBlock->fib_Protection;
fileInfo->hasComment = *infoBlock->fib_Comment ? TRUE : FALSE;
}
BOOLEAN findFirst( const char *pathName, const ATTR fileAttr, FILEINFO *fileInfo )
{
char filePath[ MAX_PATH ];
int filePathLen = strlen( ( char * ) pathName );
BOOLEAN matchIndividual = TRUE;
fileInfo->matchAttr = fileAttr;
fileInfo->infoBlock = NULL;
/* If we want to open a directory we need to zap the slash to get a pure
directory path component */
strcpy( filePath, ( char * ) pathName );
if( !filePathLen )
/* No path, match all files in current directory */
matchIndividual = FALSE;
else
/* Check for whole-directory match */
if( filePath[ filePathLen - 1 ] == SLASH )
{
filePath[ filePathLen - 1 ] = '\0';
matchIndividual = FALSE;
}
/* Place a lock on the file/directory, allocate room for the
information, and get it */
if( ( fileInfo->infoBlock = AllocMem( sizeof( FILEINFOBLOCK ), \
MEMF_PUBLIC | MEMF_CLEAR ) ) == NULL )
error( OUT_OF_MEMORY );
if( ( fileInfo->lock = ( void * ) Lock( filePath, ACCESS_READ ) ) == NULL )
return( FALSE );
if( !Examine( ( BPTR ) fileInfo->lock, \
( FILEINFOBLOCK * ) fileInfo->infoBlock ) ) /* Took "&" off parameter, PNM 22 Nov 92 */
{
UnLock( ( BPTR ) fileInfo->lock ); /* Took "&" off parameter, PNM 22 Nov 92 */
fileInfo->lock = NULL;
FreeMem( fileInfo->infoBlock, sizeof( FILEINFOBLOCK ) );
fileInfo->infoBlock = NULL;
return( FALSE );
}
addLock( ( LOCK * ) fileInfo->lock ); /* Took "&" off parameter, PNM 22 Nov 92 */
getFileInfo( fileInfo );
/* If we're looking for files within a directory, we need to call
findNext() since the Examine() call will read the parent directory
not it's contents. ExNext() reads the contents */
if( !matchIndividual )
return( findNext( fileInfo ) );
/* Return FALSE if we've found the wrong type of file */
return( ( fileInfo->matchAttr != FILES_DIRS && fileInfo->isDir ) ? \
FALSE : TRUE );
}
BOOLEAN findNext( FILEINFO *fileInfo )
{
do
/* Try and get info on the next file/dir */
if( !ExNext( ( BPTR ) fileInfo->lock, \
( FILEINFOBLOCK * ) fileInfo->infoBlock ) ) /* Took "&" off parameter, PNM 22 Nov 92 */
{
UnLock( ( BPTR ) fileInfo->lock ); /* Took "&" off parameter, PNM 22 Nov 92 */
clearLastLock();
fileInfo->lock = NULL;
FreeMem( fileInfo->infoBlock, sizeof( FILEINFOBLOCK ) );
fileInfo->infoBlock = NULL;
return( FALSE );
}
/* Sometimes we only want to match files, not directories */
while( ( fileInfo->matchAttr == ALLFILES ) ? \
( ( FILEINFOBLOCK * ) fileInfo->infoBlock)->fib_DirEntryType > 0 : 0 );
getFileInfo( fileInfo );
return( TRUE );
}
void findEnd( FILEINFO *fileInfo )
{
/* Unlock the directory (rarely used since it's usually done by findNext()) */
if( fileInfo->lock != NULL )
{
UnLock( ( BPTR ) fileInfo->lock ); /* Took "&" off parameter, PNM 22 Nov 92 */
clearLastLock();
fileInfo->lock = NULL;
}
/* Free the memory used by the FileInfoBlock (also rarely used since
findNext() does it */
if( fileInfo->infoBlock != NULL )
{
FreeMem( fileInfo->infoBlock, sizeof( FILEINFOBLOCK ) );
fileInfo->infoBlock = NULL;
}
}
/* Store the comment for a file/directory in an archive in HPACK tagged format */
int storeComment( const FILEINFO *fileInfo, const FD outFD )
{
int commentLength = strlen( ( ( FILEINFOBLOCK * ) fileInfo->infoBlock )->fib_Comment );
int dataLength = commentLength, i;
BOOLEAN isDir = !outFD;
/* Write the comment tag header */
if( isDir )
dataLength += addDirData( TAG_COMMENT, TAGFORMAT_STORED, commentLength, LEN_NONE );
else
dataLength += writeTag( TAG_COMMENT, TAGFORMAT_STORED, commentLength, LEN_NONE );
/* Now write the comment data */
if( isDir )
{
/* Write comment to directory data area */
checksumDirBegin( RESET_CHECKSUM );
for( i = 0; i < commentLength; i++ )
fputDirByte( ( ( FILEINFOBLOCK * ) fileInfo->infoBlock )->fib_Comment[ i ] );
checksumDirEnd();
fputDirWord( crc16 );
}
else
{
/* Write comment to file data area */
checksumBegin( RESET_CHECKSUM );
for( i = 0; i < commentLength; i++ )
fputByte( ( ( FILEINFOBLOCK * ) fileInfo->infoBlock )->fib_Comment[ i ] );
checksumEnd();
fputWord( crc16 );
}
return( dataLength + sizeof( WORD ) );
}
/* Set the comment for a file/directory from an HPACK tag */
void setComment( const char *filePath, const TAGINFO *tagInfo, const FD srcFD )
{
char comment[ COMMENT_SIZE ];
int i, commentSize = ( tagInfo->dataLength > COMMENT_SIZE - 1 ) ? \
COMMENT_SIZE - 1 : tagInfo->dataLength;
/* Make sure we can read the comment */
if( tagInfo->dataFormat != TAGFORMAT_STORED )
{
/* Don't know how to handle compressed comments yet, skip it */
skipSeek( tagInfo->dataLength );
return;
}
/* Read in as much of the comment as we can, skip the rest */
for( i = 0; i < commentSize; i++ )
comment[ i ] = fgetByte();
comment[ i ] = '\0';
if( tagInfo->dataLength - commentSize )
skipSeek( tagInfo->dataLength - commentSize );
/* Set the file's comment */
SetComment( filePath, comment );
}
/* Initialise/cleanup functions for extra info handling */
struct Library *IconLib = NULL;
void initExtraInfo( void )
{
/* Try and open icon library */
if( ( IconLib = OpenLibrary( "icon.library", 33 ) ) == NULL )
error( INTERNAL_ERROR );
}
void endExtraInfo( void )
{
/* Close icon library */
if( IconLib != NULL )
CloseLibrary( IconLib );
}
/* Set extra info for an archive, copy extra info from one file to another */
void setExtraInfo( const char *filePath )
{
/* The HPACK icon image (there should be four of these, one per file
type of normal, secured, encrypted, both) */
__chip static UWORD hpackIconData[] = {
/* Icon image data */
0xffff,
0x8001,
0x8001,
0x8001,
0x8001,
0x8001,
0x8001,
0x8001,
0x8001,
0x8001,
0x8001,
0x8001,
0x8001,
0x8001,
0x8001,
0xffff,
0xffff,
0x8001,
0x8001,
0x8001,
0x8001,
0x8001,
0x8001,
0x8001,
0x8001,
0x8001,
0x8001,
0x8001,
0x8001,
0x8001,
0x8001,
0xffff
};
static IMAGE hpackIconImage = {
0, 0, /* Top corner */
16, 16, 2, /* Width, height, depth */
hpackIconData, /* Data */
0, 0, /* PlanePick, PlaneOnOff */
NULL /* Next image */
};
/* The tool types for normal, secured, encrypted, and both, archives */
static BYTE *normalToolType[] = { "FILETYPE=HPAK", NULL };
static BYTE *securedToolType[] = { "FILETYPE=HPKS", NULL };
static BYTE *encrToolType[] = { "FILETYPE=HPKC", NULL };
static BYTE *bothToolType[] = { "FILETYPE=HPKB", NULL };
/* The disk object for the HPACK icon */
static DISKOBJECT hpackIcon = {
WB_DISKMAGIC, /* Magic number */
WB_DISKVERSION, /* Structure version number */
{ /* Embedded gadget structure */
NULL, /* Next gadget pointer */
0, 0, 16, 16, /* Left, top, width, height */
GADGIMAGE | GADGHBOX, /* Flags (must use) */
GADGIMMEDIATE | RELVERIFY, /* Activ.flags (must use) */
BOOLGADGET, /* Type (must use) */
&hpackIconImage, /* Image data */
NULL, NULL, NULL, NULL, 0, NULL /* Unused fields */
},
WBPROJECT, /* Icon type */
"Hpack", /* Default tool name */
normalToolType, /* Tool type array */
NO_ICON_POSITION, NO_ICON_POSITION, /* Put it anywhere */
NULL, NULL, /* Unused fields */
20000 /* Stack size for tool */
};
/* Set the icon image and tool type depending on what the archive type is */
switch( cryptFlags & ( CRYPT_PKE_ALL | CRYPT_CKE_ALL | CRYPT_SIGN_ALL ) )
{
case CRYPT_PKE_ALL:
case CRYPT_CKE_ALL:
/* Encrypted archive */
hpackIcon.do_ToolTypes = encrToolType;
break;
case CRYPT_SIGN_ALL:
/* Secured archive */
hpackIcon.do_ToolTypes = securedToolType;
break;
case CRYPT_PKE_ALL | CRYPT_SIGN_ALL:
case CRYPT_CKE_ALL | CRYPT_SIGN_ALL:
/* Encrypted + secured archive */
hpackIcon.do_ToolTypes = bothToolType;
break;
}
/* Write out the new disk object */
PutDiskObject( filePath, &hpackIcon );
}
void copyExtraInfo( const char *srcFilePath, const char *destFilePath )
{
DISKOBJECT *iconObject;
/* Read in the .info data from the source and write it to the destination */
if( ( iconObject = GetDiskObject( srcFilePath ) ) != NULL )
{
PutDiskObject( destFilePath, iconObject );
FreeDiskObject( iconObject );
}
}
/* Store the DiskObject associated with a file/directory, in an archive in
HPACK tagged form */
#define calcImageSize(theImage) ( ( ( ( theImage.Width ) + 15 ) & 0xFFF0 ) * \
theImage.Height * theImage.Depth )
LONG storeDiskObject( const char *pathName, const FD outFD )
{
DISKOBJECT *theObject;
int i, iconImageSize, iconLength;
BOOLEAN isDir = !outFD;
IMAGE *theImage;
/* Try and get the DiskObject for the file/directory */
if( ( theObject = GetDiskObject( pathName ) ) == NULL )
return( 0L );
/* Perform a few sanity checks on the icon information. According to
the ROM Kernel reference manual we should only handle icons with the
following magic values set up */
if( ( theObject->do_Gadget.Flags & GADGIMAGE ) && \
( theObject->do_Gadget.Activation == ( GADGIMMEDIATE | RELVERIFY ) ) && \
( theObject->do_Gadget.GadgetType == BOOLGADGET ) )
{
/* It's a icon gadget, store it as an AMIGA_ICON tag */
theImage = ( IMAGE * ) theObject->do_Gadget.GadgetRender;
iconImageSize = calcImageSize( ( * theImage ) );
iconLength = sizeof( WORD ) + sizeof( WORD ) + sizeof( WORD ) + \
sizeof( WORD ) + sizeof( WORD ) + sizeof( BYTE ) + \
sizeof( BYTE ) + sizeof( BYTE) + iconImageSize + \
sizeof( WORD );
if( isDir )
{
/* Write directory icon data */
addDirData( TAG_AMIGA_ICON, TAGFORMAT_STORED, iconLength, LEN_NONE );
checksumDirBegin( RESET_CHECKSUM );
fputDirWord( theImage->LeftEdge );
fputDirWord( theImage->TopEdge );
fputDirWord( theImage->Width );
fputDirWord( theImage->Height );
fputDirWord( theImage->Depth );
fputDirByte( theImage->PlanePick );
fputDirByte( theImage->PlaneOnOff );
fputDirByte( theObject->do_Type );
for( i = 0; i < iconImageSize; i++ )
fputDirWord( theImage->ImageData[ i ] );
checksumDirEnd();
fputDirWord( crc16 );
}
else
{
/* Write file icon data */
writeTag( TAG_AMIGA_ICON, TAGFORMAT_STORED, iconLength, LEN_NONE );
checksumBegin( RESET_CHECKSUM );
fputWord( theImage->LeftEdge );
fputWord( theImage->TopEdge );
fputWord( theImage->Width );
fputWord( theImage->Height );
fputWord( theImage->Depth );
fputByte( theImage->PlanePick );
fputByte( theImage->PlaneOnOff );
fputByte( theObject->do_Type );
for( i = 0; i < iconImageSize; i++ )
fputWord( theImage->ImageData[ i ] );
checksumEnd();
fputWord( crc16 );
}
}
FreeDiskObject( theObject );
}
/* Set the icon for a file/directory */
static DISKOBJECT defaultDiskObject = {
WB_DISKMAGIC, /* Magic number */
WB_DISKVERSION, /* Structure version number */
{ /* Embedded gadget structure */
NULL, /* Next gadget pointer */
0, 0, 0, 0, /* Left, top, width, height */
GADGIMAGE | GADGHCOMP, /* Flags (must use) */
GADGIMMEDIATE | RELVERIFY, /* Activ.flags (must use) */
BOOLGADGET, /* Type (must use) */
NULL, /* Image data */
NULL, NULL, NULL, NULL, 0, NULL /* Unused fields */
},
WBPROJECT, /* Icon type */
"", /* Default tool name */
NULL, /* Tool type array */
NO_ICON_POSITION, NO_ICON_POSITION, /* Put it anywhere */
NULL, NULL, /* Unused fields */
0L /* Stack size for tool */
};
void setIcon( const char *filePath, const TAGINFO *tagInfo, const FD srcFD )
{
DISKOBJECT *theObject;
IMAGE iconImage, *oldIconImage;
BYTE oldType;
int i, iconImageSize;
/* Try and get an existing DiskObject for the file/directory */
if( ( theObject = GetDiskObject( filePath ) ) == NULL )
/* None exists yet, use default object */
theObject = &defaultDiskObject;
/* Switch to new ImageData information */
oldType = theObject->do_Type;
oldIconImage = ( IMAGE * ) theObject->do_Gadget.GadgetRender;
theObject->do_Gadget.GadgetRender = ( APTR ) &iconImage;
/* Set up the Image fields */
checksumSetInput( tagInfo->dataLength - sizeof( WORD ), RESET_CHECKSUM );
iconImage.LeftEdge = fgetWord();
iconImage.TopEdge = fgetWord();
iconImage.Width = fgetWord();
iconImage.Height = fgetWord();
iconImage.Depth = fgetWord();
iconImage.PlanePick = fgetWord();
iconImage.PlaneOnOff = fgetWord();
theObject->do_Type = fgetByte();
iconImageSize = calcImageSize( iconImage );
if( ( iconImage.ImageData = \
( WORD * ) hmalloc( iconImageSize * sizeof( WORD ) ) ) == NULL )
error( OUT_OF_MEMORY );
for( i = 0; i < iconImageSize; i++ )
iconImage.ImageData[ i ] = fgetWord();
iconImage.NextImage = NULL;
/* If the data was non-corrupted, set the new icon */
if( fgetWord() == crc16 )
PutDiskObject( filePath, theObject );
/* Free up in-memory data structures */
hfree( iconImage.ImageData );
theObject->do_Gadget.GadgetRender = ( APTR ) oldIconImage;
theObject->do_Type = oldType;
FreeDiskObject( theObject );
}
#if defined( LATTICE ) && !defined( __SASC )
/* memcpy() which handles overlapping memory ranges */
void memmove( char *dest, char *src, int length )
{
int itmp = ( length + 7 ) >> 3;
if( dest > src )
{
dest += length;
src += length;
switch( length & 3 )
{
case 0: do { *--dest = *--src;
case 7: *--dest = *--src;
case 6: *--dest = *--src;
case 5: *--dest = *--src;
case 4: *--dest = *--src;
case 3: *--dest = *--src;
case 2: *--dest = *--src;
case 1: *--dest = *--src;
} while( --itmp > 0 );
}
}
else
{
switch( length & 3 )
{
case 0: do { *dest++ = *src++;
case 7: *dest++ = *src++;
case 6: *dest++ = *src++;
case 5: *dest++ = *src++;
case 4: *dest++ = *src++;
case 3: *dest++ = *src++;
case 2: *dest++ = *src++;
case 1: *dest++ = *src++;
} while( --itmp > 0 );
}
}
/* This was added mainly to frighten you */
}
#endif /* LATTICE && !__SASC */