/* macbin.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. 
 *
 *
 * macbin.c holds the unsea_mb() and associated routines. */
 
 #include "unsea.h"
 
int unsea_mb(char *oldfilename, char *newfilename)
{
	/* start of declared variables */
	
	extern struct starting_flags stflags;
	
	FILE *oldfilep; /* the original SEA MacBinary file */
	
	FILE *newfilep; /* the new non-SEA MacBinary file */
	
	unsigned long int i, /* general counter */

		datablock,
			/* holds the number of blocks in the data fork of the sea */

		resblock;
			/* same as datablock, except for the resource fork */
	
	unsigned char fileblock[128];  /* storage area for blocks in the MacBinary file */
	
	unsigned char *kfileblock; /* This pointer is for kblock transmission, if needed. */
	
	int j, kblocks;      /* other counters */
	    
	/* start of code */
	
	/* Let's see if the file even exists */
	if ( (oldfilep=fopen(oldfilename,"rb") ) == NULL)
		{
		 fprintf(stderr, "Cannot open %s to convert.\n", oldfilename);
		 
		 return 1; /* Standard error return */
		}
	
	/* Can I read the file?? */
	if (getfileblock(oldfilep,fileblock,128) ) /* getfileblock() 
	                                          returns 1 as an error */
		{ ERROR("Unable to read %s.\n", oldfilename);
		
		  return 1;
		}
		
	/* Is it a SEA, and if so what kind? Let's check. */
	if ((!check_mb_sea(fileblock))||(!stflags.sea_mode))
		/* if check_mb_sea or sea_mode == 0, then the file is not
		 * an mb_sea.*/
	
		{ ERROR("%s is not a valid file for unsea.\n", oldfilename);
		
		  return 1;  /* spit it back */
		
		}
	
	/* Get a new filename for the file if one was not provided */
	
	if (!strlen(newfilename))
		
		convert_file_name(oldfilename, newfilename, TRUE);
			/* The TRUE says that a "new_" prefix is to be used
			 * if necessary */
	
	/* Can we open the new file?? If there is one there by the
	 * same name, the answer is no, unless option 'o' has
	 * been selected. In that case, it is yes, no matter what.*/
	   			
	if(!(stflags.overwrite)&&((newfilep=fopen(newfilename,"r"))!=NULL))
	
		{ ERROR3("New file %s for converting %s already exists.\n", newfilename, oldfilename);
	
		  return 1;
		}
	
	/* Now let's see if the new file can be created... */
	if ( (newfilep=fopen(newfilename,"wb") ) == NULL) /* UNSEA can't open the output file */
	
		{ printf("File error opening file %s for converting %s.\n", newfilename, oldfilename);
	
		  fclose(oldfilep);
		
		  return 1;
		}
	/* how long are the two forks of the Mac SEA file?? Note that
	 * getforksize() produces a figure in x bytes, while getblocksize()
	 * produces the number of 128 byte blocks in said number. */
	 
	datablock=getblocksize(getforksize(&fileblock[83]));
	
	resblock=getblocksize(getforksize(&fileblock[87]));
	
	/* Let's now let the user know about what this SEA is like,
	 * unless he already told us not to, via the b option. */
	if(!stflags.less_talk)
		{
		
		printf("Opening %s for MacBinary conversion.\n\t SEA type:",oldfilename);
	
		switch (stflags.sea_mode){
		
			case 1:
				printf("Compact Pro. \n");
				break;
		
			case 3:
				printf("StuffIt Deluxe/Lite\n");
				break;
			}
		printf("\t Output file: %s \n\t\
 Output file size (in bytes): %ld \n",newfilename,((datablock+1)*128));
 
		}
	/* Let's produce a block header for "newfilename" */
	convert_mb_header(fileblock);
	
	/* now, push the converted header into the new file, dealing
	   gracefully (at least somewhat gracefully...) with any
	   file errors. */
	if (sendfileblock(newfilep,fileblock,128) )
		{
		 ERROR3("File error accessing file %s for converting %s.\n", newfilename, oldfilename);
		 
		 DELETE_FILE(newfilename);
		 	/* Let's clean up the newly-generated file, as well. */
		 return 1;
		}
	
	/* Send the data block through unmolested, if it exists at all. */
	if (datablock)
		{
		
		if(((datablock/8)>2)&&((kfileblock=calloc(1024,1))!=NULL))
			{ /* Basically, is the "fast" method worth the effort, and if
			   * so, can we get space for it?? */
			
			kblocks = (datablock / 8);
			
			for(i=1;i<= kblocks;i++)
				{
				if((getfileblock(oldfilep,kfileblock,1024))||(sendfileblock(newfilep,kfileblock,1024)))
					{
					 ERROR3("File error during conversion of %s into %s.\n", oldfilename,newfilename);
				 
					 DELETE_FILE(newfilename);
		 			/* Let's clean up the newly-generated file, as well. */
		 			 return 1;
					}
				datablock -= 8;
				}
				
			free(kfileblock);
			}/* There, the "big" parts are out of the way... */
	

/* Now, let's get the leftovers... */
		for(i=1;i<=datablock;i++)
		{
			if((getfileblock(oldfilep,fileblock,128))||(sendfileblock(newfilep,fileblock,128)))
				{
				 ERROR3("File error during conversion of %s into %s.\n", oldfilename,newfilename);
				 
				 DELETE_FILE(newfilename);
		 			/* Let's clean up the newly-generated file, as well. */
		 			return 1;
				 }
				 
		}
		
	} /* End of datablock sending */
	
	/* Now that we have sent the data block, we can trash the old res fork */
	if(((resblock/8)>2)&&((kfileblock=calloc(1024,1))!=NULL))
			{ /* Again, is the "fast" method worth the effort, and if
			   * so, can we get space for it?? */
			
			kblocks = (resblock / 8);
			
			for(i=1;i<= kblocks;i++)
				{
				if(getfileblock(oldfilep,kfileblock,1024))
					{
					 ERROR3("File error during conversion of %s into %s.\n", oldfilename,newfilename);
				 
					 DELETE_FILE(newfilename);
		 			/* Let's clean up the newly-generated file, as well. */
		 			 return 1;
					}
				resblock -= 8;
				}
				
			free(kfileblock);
			}/* There, the "big" parts are out of the way... */
	for(i=1;i<=resblock;i++)
		{
		/* Again, let's check for errors (my, aren't we being paranoid
		 * about errors.. ;) */
		if (getfileblock(oldfilep,fileblock,128) )
			{
			 ERROR3("File error during conversion of %s into %s.\n", oldfilename,newfilename);
			  
			 DELETE_FILE(newfilename);
		 		/* Let's clean up the newly-generated file, as well. */
			 return 1;
			 }
		}

	/* Send the rest of oldfile over, if any. (for compatability with
	 * standard, which allows Info block after the two forks.) */
	
	while ( (j=fgetc(oldfilep) ) != EOF)
		{
		  fputc(j,newfilep);
		}
	
	ERROR3("%s successfully converted to %s.\n\n", oldfilename, newfilename);
	
	return 0; /* a job well done :) */
	
}  /* end of unsea_mb() */

int check_mb_sea(unsigned char block[])
{
	extern struct starting_flags stflags;
	
	int i;   /* counter, both general and specific */
	
	char restype[5]; /* 4 byte length, for file type and creator */
	
	int j;

	stflags.sea_mode = 0;
	
	if (block[0] || block[74] || block[82])
		return 0;  /* If any of these are != 0, this is NOT a MB file */
	
	/* From this point on, cmb() should return 1, to indicate that this
	 * is a MB file, simply not a MB SEA*/
	
	for(i=0;i<4;i++)
		restype[i]=block[65+i];

	restype[4] = 0;
	
	if (strcmp(restype, "APPL")) /* This is TRUE if restype != "APPL" */
		return 1;  /* Can add "appe" here if needed later... */
	
	/* Time to do the same thing with the creator type */
	
	for(i=0; i<4; i++)
		restype[i]=block[69+i];
	
	if ((!stflags.ignore_cpt_seas)&&(!strcmp(restype, "EXTR")))
		/* If we can even read CompactPro SEAs, is it one? */
		{
		stflags.sea_mode = 1;
		
		return 1; /* it is */}
		
	else if ((!stflags.ignore_sitd_seas)&&(!strcmp(restype, "aust")))
		/* Can we read StuffIt SEAs, and if so is this file one? */
		{
		stflags.sea_mode = 3;
		
		return 1; /* Yep. :) */}
	
	return 1;
	/* None of these is true, so instead, let's just return 
	 * that it's a MacBinary file. */

} /* end of check_mb_sea() */
