/***********************************************************************\
Common class for doing some rudimentarly interactions with ps files in all Convert programs
Copyright (C) 1993 David John Burrowes

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

The author, David John Burrowes, can be reached at:
	davidjohn@kira.net.netcom.com
	David John Burrowes
	1926 Ivy #10
	San Mateo, CA 94403-1367
\***********************************************************************/

#import "PSFile.h"
#import<stdio.h>
#import <stdlib.h>
#import <string.h>
#include <stdarg.h>	// For variable arguments stuff

@implementation PSFile

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	Method:	writeDCDcomment:
//	Parameters:	the line of text we are to write as a comment
//	Returns: 	a Reply
//	Description:
//		This writes the specified string to the PS file, following it with a newline, and
//		preceeding it immediately with a %% so it appears as a PS DCD comment
//		It does no formatting of the line, as some other smarter routine should.
//	Note:
//		This blindly assumes that it first thing on a new line.  A good PS file object
//		should be keeping track of these things, and jump to a new line if we aren't.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- WriteDSCComment: (CString) comment
{
	CString	output = NewCString(strlen(comment) + 4);

	sprintf(output, "%%%%%s\n", comment);	//That's, two percents and a string. =)
	[self Write: strlen(output) BytesFrom: (ByteString) output];
	FreeCString(output);
	return self;
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	Method:		WriteDSCCommentUsing:WithFormat:
//	Parameters:	A buffer provided by the caller, a format, and N arguments to be written
//	Returns: 	self
//	Stores:		nothing (bug)
//	Description:
//		This writes out a text string given variable arguments, as a DSC comment.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- WriteDSCCommentUsing: (CString) buffer WithFormat: (CString) format, ...;
{
	va_list parameter_list;
	CString	output;

	va_start(parameter_list, format);

	vsprintf(buffer, format, parameter_list); 	// doc implies this does a va_end

	output = NewCString(strlen(buffer) + 4);
	sprintf(output, "%%%%%s\n", buffer);	//That's, two percents and a string. =)
	[self Write: strlen(output) BytesFrom: (ByteString) output];
	FreeCString(output);
	return self;
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	Method:	WriteComment:
//	Parameters:	the line of text we are to write as a comment
//	Returns: 	a Reply
//	Description:
//		This writes the specified string to the PS file, following it with a newline, and
//		preceeding it immediately with a %.
//		It does no formatting of the line, as some other smarter routine should.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- WriteComment: (CString) comment
{
	CString	output = NewCString(strlen(comment) + 3);

	sprintf(output, "%%%s\n", comment);	//That's, one percent and a string. =)
	[self Write: strlen(output) BytesFrom: (ByteString) output];
	FreeCString(output);
	return self;
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	Method:		WriteCommentUsing:WithFormat:
//	Parameters:	A buffer provided by the caller, a format, and N arguments to be written
//	Returns: 	self
//	Stores:		nothing (bug)
//	Description:
//		This writes out a text string given variable arguments, as a PS comment.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- WriteCommentUsing: (CString) buffer WithFormat: (CString) format, ...;
{
	va_list parameter_list;
	CString	output;
	
	va_start(parameter_list, format);

	vsprintf(buffer, format, parameter_list);  	// doc implies this does a va_end

	output = NewCString(strlen(buffer) + 2);
	sprintf(output, "%%%s\n", buffer);	//That's, 1 percent and a string.
	[self Write: strlen(output) BytesFrom: (ByteString) output];
	FreeCString(output);
	return self;
}




//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	Method:	writePSline:
//	Parameters:	the line of text we are to write
//	Returns: 	a Reply
//	Description:
//		This writes the specified string to the PS file, following it with a newline.
//		It does no formatting of the line, as some other smarter routine should.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- WritePSLine: (CString) theLine
{
	CString	output = NewCString(strlen(theLine) + 2);

	sprintf(output, "%s\n", theLine);
	[self Write: strlen(output) BytesFrom: (ByteString) output];
	FreeCString(output);
	return self;
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	Method:		WritePSLineUsing:WithFormat:
//	Parameters:	A buffer provided by the caller, a format, and N arguments to be written
//	Returns: 	self
//	Stores:		nothing (bug)
//	Description:
//		This writes out a text string given variable arguments
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- WritePSLineUsing: (CString) buffer WithFormat: (CString) format, ...;
{
	va_list parameter_list;
	CString	output;
	
	va_start(parameter_list, format);

	vsprintf(buffer, format, parameter_list);  	// doc implies this does a va_end

	output = NewCString(strlen(buffer) + 1);
	sprintf(output, "%s\n", buffer);
	[self Write: strlen(output) BytesFrom: (ByteString) output];
	FreeCString(output);
	return self;
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	Method:	write:BytesOfHexData:
//	Parameters:	The number of Bytes to write
//				A buffer of binary data
//	Returns: 	self
//	Description:
//		This method writes out num Bytes of data from the buffer specified by buffer.
//		buffer is not modified.  Each Byte is converted to a pair of hexidcecimal digits,
//		and these are written out.  When the whole buffer has been written, a newline
//		is added.
//		The intended use for this method is for dumping raw image data to be used
//		with PS operators like (surprisingly) image.
//	History:
//		93.08.21	djb	rewrote so that this did all it's hex conversion itself rather than
//					calling WriteByteAsHex over and over... it seemed to be that that
//					was almost certainly an enormous performance drain.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- Write: (PositiveInteger) num BytesOfHexDataFrom: (ByteString) buffer
{
	PositiveInteger	index;
	CString			dest		= NewCString((num*2 ) + 1);
	Byte			nibble1;
	Byte			nibble2;

	for (index = 0; index < num; index++)
	{
		nibble1 = buffer[index] >> 4;
		nibble2 = ( buffer[index] & 0x0F);

		if (nibble1 < 10)
			dest[index*2] =  (Character) '0'+nibble1; // digit 0-9
		else
			dest[index*2] =  (Character) 'A'+nibble1-10; // cap A-F
	
		if (nibble2 < 10)
			dest[(index*2) + 1] =   (Character) '0'+nibble2; // digit 0-9
		else
			dest[(index*2)+1] = (Character) 'A'+nibble2-10; // cap A-F
	}
	dest[index*2] = EndOfCString;
	
	[self   WriteTextLine: dest];
	FreeCString(dest);

	return self;
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	Method:	write:InvertedBytesOfHexDataFrom:
//	Parameters:	The number of Bytes to write
//				A buffer of binary data
//	Returns: 	self
//	Description:
//		This method writes out num Bytes of data from the buffer specified by buffer.
//		buffer is not modified.  Each Byte is converted to a pair of hexidcecimal digits,
//		and these are written out with a newline following all.
//		During the process, the Byte is inverted (thus 00 becomes FF, etc.
//		The intended use for this method is for dumping raw image data to be used
//		with PS operators like (surprisingly) image.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- Write: (PositiveInteger) num InvertedBytesOfHexDataFrom: (ByteString) buffer
{
	PositiveInteger index;
	for (index = 0; index < num; index++)
		[self	WriteByteAsHex: ~buffer[index]];
	[self ForceNewLine];
	return self;
}


- ForceNewLine
{
	return [self WriteByte: (Byte) '\n'];
	return self;
}


- WriteByteAsHex: (Byte) theByte
{
	Byte		nibble1 = theByte >> 4;
	Byte		nibble2 = (theByte & 0x0F);
		
	if (nibble1 < 10)
		[self WriteByte: (Byte) '0'+nibble1]; // digit 0-9
	else
		[self WriteByte: (Byte) 'A'+nibble1-10]; // cap A-F

	if (nibble2 < 10)
		[self WriteByte: (Byte) '0'+nibble2]; // digit 0-9
	else
		[self WriteByte: (Byte) 'A'+nibble2-10]; // cap A-F
	return self;
}


@end