/* convert.c - Part of the unsea program.
 *   Copyright 1992 by David W. Rankin, Jr.
 * 
 * See "unsea.txt" for full copyright information applying 
 * to all text in this package. 
 *
 *
 * This file contains the source code for the converters and interpreters
 * within unsea, including the CRC conversion constants. */
 

#include "unsea.h"

/* crctab based upon BinHex and MacBinary standard CRC "seed" of
 * 0x1021. */
const unsigned short crctab[] = { 
    0x0000,  0x1021,  0x2042,  0x3063,  0x4084,  0x50a5,  0x60c6,  0x70e7,
    0x8108,  0x9129,  0xa14a,  0xb16b,  0xc18c,  0xd1ad,  0xe1ce,  0xf1ef,
    0x1231,  0x0210,  0x3273,  0x2252,  0x52b5,  0x4294,  0x72f7,  0x62d6,
    0x9339,  0x8318,  0xb37b,  0xa35a,  0xd3bd,  0xc39c,  0xf3ff,  0xe3de,
    0x2462,  0x3443,  0x0420,  0x1401,  0x64e6,  0x74c7,  0x44a4,  0x5485,
    0xa56a,  0xb54b,  0x8528,  0x9509,  0xe5ee,  0xf5cf,  0xc5ac,  0xd58d,
    0x3653,  0x2672,  0x1611,  0x0630,  0x76d7,  0x66f6,  0x5695,  0x46b4,
    0xb75b,  0xa77a,  0x9719,  0x8738,  0xf7df,  0xe7fe,  0xd79d,  0xc7bc,
    0x48c4,  0x58e5,  0x6886,  0x78a7,  0x0840,  0x1861,  0x2802,  0x3823,
    0xc9cc,  0xd9ed,  0xe98e,  0xf9af,  0x8948,  0x9969,  0xa90a,  0xb92b,
    0x5af5,  0x4ad4,  0x7ab7,  0x6a96,  0x1a71,  0x0a50,  0x3a33,  0x2a12,
    0xdbfd,  0xcbdc,  0xfbbf,  0xeb9e,  0x9b79,  0x8b58,  0xbb3b,  0xab1a,
    0x6ca6,  0x7c87,  0x4ce4,  0x5cc5,  0x2c22,  0x3c03,  0x0c60,  0x1c41,
    0xedae,  0xfd8f,  0xcdec,  0xddcd,  0xad2a,  0xbd0b,  0x8d68,  0x9d49,
    0x7e97,  0x6eb6,  0x5ed5,  0x4ef4,  0x3e13,  0x2e32,  0x1e51,  0x0e70,
    0xff9f,  0xefbe,  0xdfdd,  0xcffc,  0xbf1b,  0xaf3a,  0x9f59,  0x8f78,
    0x9188,  0x81a9,  0xb1ca,  0xa1eb,  0xd10c,  0xc12d,  0xf14e,  0xe16f,
    0x1080,  0x00a1,  0x30c2,  0x20e3,  0x5004,  0x4025,  0x7046,  0x6067,
    0x83b9,  0x9398,  0xa3fb,  0xb3da,  0xc33d,  0xd31c,  0xe37f,  0xf35e,
    0x02b1,  0x1290,  0x22f3,  0x32d2,  0x4235,  0x5214,  0x6277,  0x7256,
    0xb5ea,  0xa5cb,  0x95a8,  0x8589,  0xf56e,  0xe54f,  0xd52c,  0xc50d,
    0x34e2,  0x24c3,  0x14a0,  0x0481,  0x7466,  0x6447,  0x5424,  0x4405,
    0xa7db,  0xb7fa,  0x8799,  0x97b8,  0xe75f,  0xf77e,  0xc71d,  0xd73c,
    0x26d3,  0x36f2,  0x0691,  0x16b0,  0x6657,  0x7676,  0x4615,  0x5634,
    0xd94c,  0xc96d,  0xf90e,  0xe92f,  0x99c8,  0x89e9,  0xb98a,  0xa9ab,
    0x5844,  0x4865,  0x7806,  0x6827,  0x18c0,  0x08e1,  0x3882,  0x28a3,
    0xcb7d,  0xdb5c,  0xeb3f,  0xfb1e,  0x8bf9,  0x9bd8,  0xabbb,  0xbb9a,
    0x4a75,  0x5a54,  0x6a37,  0x7a16,  0x0af1,  0x1ad0,  0x2ab3,  0x3a92,
    0xfd2e,  0xed0f,  0xdd6c,  0xcd4d,  0xbdaa,  0xad8b,  0x9de8,  0x8dc9,
    0x7c26,  0x6c07,  0x5c64,  0x4c45,  0x3ca2,  0x2c83,  0x1ce0,  0x0cc1,
    0xef1f,  0xff3e,  0xcf5d,  0xdf7c,  0xaf9b,  0xbfba,  0x8fd9,  0x9ff8,
    0x6e17,  0x7e36,  0x4e55,  0x5e74,  0x2e93,  0x3eb2,  0x0ed1,  0x1ef0
    };

unsigned short updatecrc(unsigned char i, unsigned short crc)
{
	extern const unsigned short crctab[];
	
	return ((crc<<8) ^ crctab[(crc>>8) ^ i]);

} /* end of updatecrc() */

void convert_mb_header(unsigned char block[])

{	
	extern struct starting_flags stflags;
	
	char newfilename[64], oldfilename[64];
			/* 64 is one more than the maximum length of a file in a
			 * MB archive */
	
	unsigned short crc = 0;
	
	int i, j;
	
	
	j= (int) (block[1]);
	
	for(i=0; i<=j; i++)
		oldfilename[i] = block[i+2];
	
	strcpy(newfilename,"");
	
	/* Let's get the name converted here... (j is the length of the
	 * new file name, which is not necessarily the same size as
	 * the old one (but still less than 63 chars long) */
	 
	convert_file_name(oldfilename, newfilename,FALSE);
		/* the FALSE means that cfn() will leave the filename alone if it
		 * doesn't have *.sea as its structure (the optimal choice for
		 * the internal name of a MacBinary file, since a lot of them have
		 * more unconventional names. */
	
	j=strlen(newfilename);
	
	block[1] = j; /* put that length in the new block */
	
	for(i=0;i<j;i++)
		block[i+2] = newfilename[i];
	
	/* Now, we have to \0 the rest of the name space, as per
	 * the standard. */
	
	for(i=(j+2); i<65; i++)
		block[i]= '\0';
	
	/* Let's change the creator and type, as appropriate.*/
	
	switch (stflags.sea_mode)
		{
		case 1: /* Compact Pro SEAs */
			/* first the type */
			restypecopy(block, 65, "PACT");
		
			/* then the creator */
			restypecopy(block, 69, "CPCT");
	 		
	 		break;
	 	
	 	case 3: /* StuffIt SEAs */
		 	/* first the type */
			restypecopy(block, 65, "SITD");
		
			/* then the creator */
			restypecopy(block, 69, "SIT!");
			
			break;
		
		}
		
	/* Now, let's tell the Finder that the SEA doesn't have an icon, by
	 * zeroing the BNDL flag bit. */
	 
	block[73] = block[73] & 0xdf;
	
	/* Need to make the resource block into length 0 */
	block[87]=block[88]=block[89]=block[90]=0;

/* The MB2 parts of unsea don't work right, so I am making all unsea
 * files MB1. The MB2 code is left in here for copyright's sake, however. *	
	/* for safety's sake, let's upgrade all MB files to MB 2 status *
	
	block[122]=block[123]=129;
	
	/* finally, we need to redo the CRC blocks for the header *
	
	for(i=0;i<124;i++)
		
		crc = updatecrc(block[i], crc);
		
	block[124] = (char) ((crc&0xff00)>>8); /* high byte of the CRC-16 *
	
	block[125] = (char) (crc&0xff); /* the low order of the CRC-16 *
	
	/* now we are done [CRC stuff] */
/* Here's the MB1 hack code. */
	block[122]=block[123]=block[124]=block[125]=0;	
/* End of MB1 hack */	
	
	return;
	
} /* end of convert_mb_header() */

unsigned long int getforksize(unsigned char block[4])
{ /* This routine takes 4 type unsigned char #s and makes them into
   * a type unsigned long. Used mainly to determine the length of the
   * two forks of the MacBinary and BinHex files. */
   
	unsigned long int x;
	
	x=((unsigned long)(block[0])<<24)|((unsigned long)(block[1])<<16);
	
	x+=((unsigned long)(block[2])<<8)|((unsigned long) (block[3]));
	
	return x;
	
} /* end of getforksize() */

unsigned long getblocksize(unsigned long x)
{ /* Converts an unsigned long byte count into an unsigned byte block
   * count. Used by unsea_mb() */
   
	unsigned long y;
	
	y = (x / 128);
	
	if (x % 128)
		
		y++;
	
	return y;

} /* End of getblocksize() */

int convert_file_name(char *oldfname, char *newfname, const int convert_all)

{
	/* NOTE: This routine either assumes the file is of form *.sea.bin
	 * or of form *.sea. If neither, then it names the file "new_*",
	 * with a maximum length of the lesser of FILENAME_MAX and 63. */
	
	extern struct starting_flags stflags;
	
	int i;
		
	strcpy(newfname, oldfname);
	
	i = strlen(newfname);
	
	if((!strncmp(&newfname[i-3],"bin",3))||(!strncmp(&newfname[i-3],"BIN",3)))
		{
		/* if the file has the suffix *.bin, check if it has the form
		 * *.sea.bin.  */
		if((!strncmp(&newfname[i-7],"sea",3))||(!strncmp(&newfname[i-7],"SEA",3)))
			
			switch (stflags.sea_mode) {
			case 1:
				strncpy(&newfname[i-7],"cpt",3);
				break;
			
			case 3:
				strncpy(&newfname[i-7],"sit",3);
				break;
			
			default:
				printf("Catastrophic value error in sea_mode.\n");
				return 1;
			}
		else /* It doesn't have *.sea.bin, so make it new_*.bin */
			{
			strcpy(newfname, "new_");
			strcat(newfname, oldfname);
			newfname[63]= '\0'; /* Maximum length is 63 characters, if it
			                     * does not know better. (see below) */
			}
		
		} 
	/* it doesn't have *.bin, so convert from there */
	/* Here if of form *.sea*/
	else if((!strncmp(&newfname[i-3],"sea",3))||(!strncmp(&newfname[i-3],"SEA",3)))
			{
			switch (stflags.sea_mode)
				{
				case 1:
					strncpy(&newfname[i-3],"cpt",3);
					break;
			
				case 3:
					strncpy(&newfname[i-3],"sit",3);
					break;
			
				default:
					printf("Catastrophic value error in sea_mode\n");
					return 1;
				}
			
			}
		
	else if (convert_all)
		/* If none of these, and the calling routine desires all file
		 * names to be converted... */
			{
			
			strcpy(newfname, "new_");
		
			strcat(newfname, oldfname);
		
			newfname[63]= '\0'; /* see comment at last newfname[63]='\0' */
			
			}
		/* end of if statements */
	
	return 0;
	
} /* end of convert_file_name() */
