Milán Major

netscape-revival

1 branch
Code

lib/libi18n/is2euckr.c

/* -*- Mode: C; tab-width: 4 -*- */
/*	is2euckr.c	*/

#include "intlpriv.h"


extern int MK_OUT_OF_MEMORY;


/* net_iso2euckr(obj, isobuf, isobufsz, uncvtbuf)
 * Args:
 *	isobuf:		Ptr to a buf of iso-2022-kr chars
 *	isobufsz:	Size in bytes of isobuf
 *	obj->jismode:	Ptr to encoding mode, use as arg for next call to
 *		mz_iso2euckr() for rest of current 2022-kr data.  First call should
 *		initialize mode to ASCII (0).					
 *	obj->uncvtbuf:	If entire buffer was converted, uncvtbuf[0] will be nul,
 *		else this points to iso-2022-kr chars that were NOT converted
 *		and mz_iso2euckr() with additional iso-2022-kr chars appended.
 * Return:
 *	Returns NULL on failure, otherwise it returns a pointer to a buffer of
 *	converted EUC-KR characters.  Caller must XP_FREE() this memory.
 *
 * Description:
 *
 *	Allocate destination buffer (for EUC-KR).
 *
 *	Set mode state based upon ESC sequence and SO/SI.
 *
 *  If mode is KSC 5601, set 8th bits of next 2 bytes.
 *
 *	If any other mode, then assume ASCII and strip the 8th bit.
 *
 *	If either 2022-kr buffer does not contain complete char or EUC-KR buffer
 *	is full, then return unconverted 2022-kr to caller.  Caller should
 *	append more data and recall mz_iso2euckr.
 */

int
net_iso2euckr(	CCCDataObject		*obj,
				const unsigned char	*isobuf,	/* 2022-kr buf for conv */
				int32				isobufsz)	/* 2022-kr buf size in bytes */
{
	unsigned char	*tobuf = NULL;

	tobuf = mz_iso2euckr(obj, isobuf, isobufsz);

	if (tobuf) {
		/* CCC_PUTBLOCK macro does a return()	*/
		CCC_PUTBLOCK(obj, tobuf, strlen((char *)tobuf));
	} else {
		return(obj->retval);
	}
}

unsigned char *
mz_iso2euckr(	CCCDataObject		*obj,
			const unsigned char	*isobuf,	/* 2022-kr buffer for conversion */
			int32				isobufsz)	/* 2022-kr buffer size in bytes	*/
{
 	unsigned char			*tobuf = NULL;
 	int32					tobufsz;
 	unsigned char	*tobufp, *isop;		/* current byte in bufs	*/
 	unsigned char	*tobufep, *isoep;	/* end of buffers		*/
 	int32					uncvtlen;

#define euckrbufsz	tobufsz
#define euckrbuf		tobuf
#define euckrp		tobufp
#define euckrep		tobufep
 										/* Allocate a dest buffer:		*/
		/* 2022-kr is usually longer than EUC-KR because of ESC seq.
		 *
		 * In the worst case (all ASCII), converted EUC-KR will be the same
		 * length as the original 2022-kr + 1 for nul byte
		 */
	uncvtlen = strlen((char *)obj->uncvtbuf);
	tobufsz = isobufsz + uncvtlen + 1;

	if (!tobufsz) {
		return NULL;
	}

	if ((tobuf = (unsigned char *)XP_ALLOC(tobufsz)) == (unsigned char *)NULL) {
		obj->retval = MK_OUT_OF_MEMORY;
		return(NULL);
	}
										/* Initialize pointers, etc.	*/
 	isop = (unsigned char *)isobuf;
 	isoep = isop + isobufsz - 1;

#define uncvtp	tobufp	/* use tobufp as temp */ 		 		
							/* If prev. unconverted chars, append unconverted
							 * chars w/new chars and try to process.
							 */
 	if (obj->uncvtbuf[0] != '\0') {
 		uncvtp = obj->uncvtbuf + uncvtlen;
 		while (uncvtp < (obj->uncvtbuf + sizeof(obj->uncvtbuf)) &&
														isop <= isoep)
 			*uncvtp++ = *isop++;
 		*uncvtp = '\0';						/* nul terminate	*/
 		isop = obj->uncvtbuf;				/* process unconverted first */
 		isoep = uncvtp - 1;
 	}
#undef uncvtp
 	
 	tobufp = tobuf;
 	tobufep = tobufp + tobufsz - 2;		/* save space for terminating null */
 	
WHILELOOP: 	
							/* While 2022-kr data && space in EUC-KR buf. */
 	while ((tobufp <= tobufep) && (isop <= isoep)) {
		if (*isop == ESC) {
 			if ((isoep - isop) < 3)	/* Incomplete ESC seq in 2022-kr buf? */
 				break;
			switch (isop[1]) {
				case DOLLAR:
					switch (isop[2]) {
						case ')':
							switch (isop[3]) {
								case 'C':			/* KS C 5601-1987	*/
									obj->jismode = KSC_5601_87;
									isop += 4;	/* remove rest of ESC seq.	*/
									break;
								default:		/* pass thru invalid ESC seq. */
									*tobufp++ = *isop++;
									*tobufp++ = *isop++;
									*tobufp++ = *isop++;
									*tobufp++ = *isop++;
									break;
							}
							break;
						default:				/* pass thru invalid ESC seq. */
							*tobufp++ = *isop++;
							*tobufp++ = *isop++;
							*tobufp++ = *isop++;
					}
					break;
				default:						/* pass thru invalid ESC seq. */
					*tobufp++ = *isop++;
					*tobufp++ = *isop++;
			}
		} else if (*isop == SO) {
			obj->jismode |= SHIFT_OUT;
			isop++;
		} else if (*isop == SI) {
			obj->jismode &= (~SHIFT_OUT);
			isop++;
		} else if (obj->jismode == (KSC_5601_87 | SHIFT_OUT)) {
 			if ((isop+1) > isoep)		/* Incomplete 2Byte char in JIS buf? */
 				break;

			*euckrp++ = *isop++ | 0x80;
			*euckrp++ = *isop++ | 0x80;
		} else {
											/* Unknown type: no conversion	*/
			*tobufp++ = *isop++ & 0x7f;
		}
	}
	
 	if (obj->uncvtbuf[0] != '\0') {
										/* Just processed unconverted chars:
										 * isop pts to 1st unprocessed char in
 										 * isobuf.  Some may have been processed
 										 * while processing unconverted chars,
 										 * so set up ptrs not to process them
 										 * twice.
 										 */
										/* If nothing was converted, this can
										 * only happen if there was not
										 * enough 2022-kr data.  Stop and get
										 * more data.
										 */
		if (isop == obj->uncvtbuf) {	/* Nothing converted */
			*tobufp = '\0';
			return(NULL);
		}
 		isoep = (unsigned char *)isobuf + isobufsz - 1 ;
 		isop = (unsigned char *)isobuf + (isop - obj->uncvtbuf - uncvtlen);
 		obj->uncvtbuf[0] = '\0';			/* No more uncoverted chars.	*/
 		goto WHILELOOP;					/* Process new data				*/
 	}

	*tobufp = '\0';						/* null terminate dest. data */
	obj->len =  tobufp - tobuf;			/* length not counting null	*/

 	if (isop <= isoep) {				/* unconverted 2022-kr?		*/
		tobufp = obj->uncvtbuf;				/* reuse the tobufp as a TEMP */
 		while (isop <= isoep)
 			*tobufp++ = *isop++;
 		*tobufp = '\0';					/* null terminate		*/
 	}
	return(tobuf);
}

#ifdef STANDALONE_TEST
int
main(int argc, char *argv[])
{
 	unsigned char	isobuf[0001];	/* iso-2022-kr buffer for conversion */
 	int32			rdcnt;			/* #bytes from read		*/
    CCCDataObject	object;
 	
 	object.jismode = 0;							/* initially ASCII */
 	object.uncvtbuf[0] = '\0';					/* Init. no unconverted chars */
 	
 	while(rdcnt = read(0, isobuf, sizeof(isobuf))) {
		if (net_iso2euckr(&object, isobuf, rdcnt)) {
		 	fprintf(stderr, "mz_iso2euckr failed\n");
		 	exit(-1);
		}
	}
}
#endif /* STANDALONE_TEST */