/**********************************************************************
 
	Copyright (C) 2003 Hirohisa MORI <joshua@nichibun.ac.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	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.

**********************************************************************/


#include	<stdlib.h>
#include	"memory_debug.h"
#include	"long_char.h"

typedef struct sjis_work {
	unsigned char	buf;
} SJIS_WORK;

void * open_sjis();
int close_sjis(unsigned char *,void *);
int sjis2int(L_CHAR *,void*,unsigned char);
int int2sjis(unsigned char *,void*,L_CHAR);

CODE_METHOD sjis_cm = {
	"SHIFT_JIS",
	LCC_Shift_JIS,
	0,
	2,
	0,
	{0,0},
	open_sjis,
	close_sjis,
	sjis2int,
	int2sjis,
	0,
};


void *
open_sjis()
{
SJIS_WORK * ret;
	ret = d_alloc(sizeof(SJIS_WORK),103);
	ret->buf = 0;
	return ret;
}

int
close_sjis(unsigned char * ret,void * work)
{
	d_f_ree(work);
	return 0;
}

int
sjis2int(L_CHAR * ret,void * _work,unsigned char ch)
{
SJIS_WORK * work;
unsigned int h;

	work = (SJIS_WORK*)_work;
	if ( work->buf == 0 ) {
		if ( ch & 0x80 ) {
			work->buf = ch;
			return 0;
		}
		else {
			*ret = ((int)ch)&0x0ff;
			return 1;
		}
	}
	else {
		h = (work->buf <= 0x9f) ?
			work->buf - 0x71 :
			work->buf - 0xb1;
		work->buf = 0;
           	h = (h << 1) + 1;
		if (ch > 0x7f) ch --;
		if (ch >= 0x9e) {
			ch -= 0x7d;
			h ++;
		}
		else ch -= 0x1f;
		*ret = (h<<8)|ch|LCZ_2BC_JISX0208_1990;
		return 1;
	}
}

int
int2sjis(unsigned char * ret,void * _work,L_CHAR ch)
{
SJIS_WORK *work;
unsigned int h,lo;
	work = (SJIS_WORK*)_work;
	if ( (ch&LCZM_1B_TYPE) == LCZ_1BC_ASCII ) {
		if ( ch & 0x80 )
			return 0;
		ret[0] = ch&0xff;
		return 1;
	}
	if ( (ch&LCZM_2B_TYPE) == LCZ_2BC_JISX0208_1990 ) {
		h = (ch >> 8) & 0xff;
		lo = ch & 0xff;
		lo += (h & 1) ? 0x1f : 0x7d;
		if (lo >= 0x7f)
			lo ++;
		h = ((h - 0x21) >> 1) + 0x81;
		if (h > 0x9f)
			h += 0x40;
		ret[0] = h;
		ret[1] = lo;
		return 2;
	}
	return 0;
}
