/*
 *  codeconv.c -- 文字コードの変換
 *
 *  revision history
 *	0.0: 忘れた (^^;)
 *	2.0: Apr. 22, 1999 by Dai ISHIJIMA
 *	2.1: Sep.  7, 1999 (第二水準のSJIS<->JIS変換のバグ修正)
 *	3.0: Oct. 20, 2010 UTF8対応
 *	4.0: Aug.  1, 2018 for xd2
 */

#include "ucs2jis.h"
#include "codeconv.h"

#define EOS '\0'
#define MAXLINE 1024

/* UTF-8文字列の先頭一文字を16ビットUnicodeに変換してバイト数を返す */
int utf8toucs2(int *utf8, int *ucs2)
{
    int n;
    unsigned char hi, lo, mi;

    n = 0;
    if (*utf8 < 0x80) {
	n = 1;
	*ucs2 = *utf8;
    }
    else if (*utf8 < 0xe0) { /* 110x xxxx */
	n = 2;
	hi = *utf8 & 0x1f;
	lo = *(utf8 + 1) & 0x3f;
	*ucs2 = ((unsigned short)hi << 6) + (unsigned short)lo;
    }
    else {
	n = 3;
	hi = *utf8 & 0x0f;
	mi = *(utf8 + 1) & 0x3f;
	lo = *(utf8 + 2) & 0x3f;
	*ucs2
	    = ((unsigned short)hi << 12)
	    + ((unsigned short)mi << 6)
	    + (unsigned short)lo;
    }
    return(n);
}


int isutf8char(int ch)
{
    return(ch > 0xc0);
}


int utoj(int *buf, int *len)
{
    int ucs2;
    
    *len = utf8toucs2(buf, &ucs2);
    return(ucs2jis(ucs2));
}
	

/*
 * シフトJISエンコーディングの概要
 *
 * ・上位バイト [区] (0x21..0x7e) を (0x81..0x9f), (0xe0..0xef) に割り当てる
 * ・下位バイト [点] (0x21..0x7e) を
 *       奇数区なら (0x40..0x7e), (0x80..0x9e) に割り当てる
 *       偶数区なら (0x9f..0xcf) に割り当てる
 */

#define JIS_START 0x21
#define JIS_END 0x7e
#define DELETE 0x7f
#define SJIS_HS1 0x81
#define SJIS_HE1 0x9f
#define SJIS_HS2 0xe0
#define SJIS_HE2 0xef
#define SJIS_LS1 0x40
#define SJIS_LS2 0x9f


/* シフトJISの第1バイトか? */
int issjis(unsigned char ch)
{
    return(((SJIS_HS1 <= ch) && (ch <= SJIS_HE1))
	   || ((SJIS_HS2 <= ch) && (ch <= SJIS_HE2)));
}


/* JISをシフトJISに変換 */
int jtos(unsigned short ch)
{
    int x, y;
    int hi, lo;

    hi = hibyte(ch);
    lo = lobyte(ch);
    /* 上位バイトの処理 */
    x = (hi - JIS_START) / 2 + SJIS_HS1;
    if (x > SJIS_HE1) {
	x += (SJIS_HS2 - SJIS_HE1 - 1);
    }
    /* 下位バイトの処理 */
    if (hi % 2 == 1) {			/* 奇数区 */
	y = lo - JIS_START + SJIS_LS1;
	if (y >= DELETE) {
	    ++y;
	}
    }
    else {				/* 偶数区 */
	y = lo - JIS_START + SJIS_LS2;
    }
    return(hilo(x, y));
}


/* シフトJISをJISに変換 */
int stoj(unsigned short ch)
{
    int x, y;
    int hi, lo;

    hi = hibyte(ch);
    lo = lobyte(ch);

    if (hi >= SJIS_HS2) {
	hi -= (SJIS_HS2 - SJIS_HE1 - 1);
    }
    if (lo >= SJIS_LS2) {			/* 偶数区 */
	x = (hi - SJIS_HS1) * 2 + JIS_START + 1;
	y = lo - SJIS_LS2 + JIS_START;
    }
    else {					/* 奇数区 */
	x = (hi - SJIS_HS1) * 2 + JIS_START;
	if (lo > DELETE) {
	    --lo;
	}
	y = lo - SJIS_LS1 + JIS_START;
    }
    return(hilo(x, y));
}


/* JISX0208か */
int validjis(unsigned short ch)
{
    int hi, lo;

    if (ch <= 0) {
	return(0);
    }
    hi = hibyte(ch);
    lo = lobyte(ch);
    return(((JIS_START <= hi) && (hi <= JIS_END))
	   && ((JIS_START <= lo) && (lo <= JIS_END)));
}


/* JISX0201カタカナを変換するためのテーブル */
static char kana[] =
"。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゛゜";

#define KANA_KUTEN   161	/* 「。」 */
#define KANA_HANDAKU 223	/* 「゜」 */
#define KANA_START KANA_KUTEN
#define KANA_END KANA_HANDAKU


/* JISX0201カタカナか? */
int iskana(unsigned char ch)
{
    return((KANA_START <= ch) && (ch <= KANA_END));
}


/* JISX0201カタカナをJISX0208へ */
int kanakana(unsigned char ch)
{
    int p;

    if (iskana(ch)) {
	p = (ch - KANA_START) * 2;
	return(hilo(kana[p], kana[p + 1]));
    }
    else {
	return(0);
    }
}


#define ETOJMASK 0x7f7f
#define JTOEMASK 0x8080

int iseucchar(int ch)
{
    return(ch > 0xa0);
}


/* EUC-JPをJISに変換 */
int etoj(unsigned short ch)
{
    return(ch & ETOJMASK);	/* 手抜き :-) */
}


/* JISをEUC-JPに変換 */
int jtoe(unsigned short ch)
{
    return(ch | JTOEMASK);	/* 手抜き :-) */
}


/* EUCの第1バイトか? */
int iseuc(unsigned char ch)
{
    return(ch >= 0x80);
}


#define ESCAPE		27
#define SHIFTCODE	'B'
#define TOKANJI		'$'
#define TOASCII		'('
#define ASCII 'a'
#define KANJI 'k'

/* エスケープシーケンスを埋め込む */
void putescape(char *s, int *p, char ch)
{
    s[(*p)++] = ESCAPE;
    s[(*p)++] = ch;
    s[(*p)++] = SHIFTCODE;
}


/* シフトJIS文字列をJIS (ISO-2022-JP) に変換 */
char *sjistojis(char *s)
{
    static char t[MAXLINE];
    int p;
    int mode;
    int code;

    p = 0;
    mode = ASCII;
    while (*s != EOS) {
	if (issjis(*s)) {
	    if (mode != KANJI) {
		putescape(t, &p, TOKANJI);
		mode = KANJI;
	    }
	    code = stoj(hilo(*s, *(s + 1)));
	    ++s;
	    t[p++] = hibyte(code);
	    t[p++] = lobyte(code);
	}
	else if (iskana(*s)) {
	    if (mode != KANJI) {
		putescape(t, &p, TOKANJI);
		mode = KANJI;
	    }
	    code = stoj(kanakana(*s));
	    t[p++] = hibyte(code);
	    t[p++] = lobyte(code);
	}
	else {
	    if (mode != ASCII) {
		putescape(t, &p, TOASCII);
		mode = ASCII;
	    }
	    t[p++] = *s;
	}
	++s;
    }
    if (mode != ASCII) {
	putescape(t, &p, TOASCII);
	mode = ASCII;
    }
    t[p] = EOS;
    return(t);
}


/* JIS (ISO-2022-JP) 文字列をシフトJISに変換 */
char *jistosjis(char *s)
{
    static char t[MAXLINE];
    int p;
    int code;
    int mode;

    p = 0;
    mode = ASCII;
    while (*s != EOS) {
	if ((*s == ESCAPE) && (*(s + 1) == TOKANJI)) {	/* 手抜き :-) */
	    /* && (*(s + 2) == SHIFTCODE)) { */
	    mode = KANJI;
	    s += 3;
	}
	else if ((*s == ESCAPE) && (*(s + 1) == TOASCII)) {  /* 手抜き :-) */
	    /* && (*(s + 2) == SHIFTCODE)) { */
	    mode = ASCII;
	    s += 3;
	}
	else {
	    if (mode == KANJI) {
		code = jtos(hilo(*s, *(s + 1)));
		++s;
		t[p++] = hibyte(code);
		t[p++] = lobyte(code);
	    }
	    else {
		t[p++] = *s;
	    }
	    ++s;
	}
    }
    t[p] = EOS;
    return(t);
}


/* EUC-JP文字列をJIS (ISO-2022-JP) に変換 */
char *euctojis(char *s)
{
    static char t[MAXLINE];
    int p;
    int mode;
    int code;

    p = 0;
    mode = ASCII;
    while (*s != EOS) {
	if (iseuc(*s)) {
	    if (mode != KANJI) {
		putescape(t, &p, TOKANJI);
		mode = KANJI;
	    }
	    code = etoj(hilo(*s, *(s + 1)));
	    ++s;
	    t[p++] = hibyte(code);
	    t[p++] = lobyte(code);
	}
	else {
	    if (mode != ASCII) {
		putescape(t, &p, TOASCII);
		mode = ASCII;
	    }
	    t[p++] = *s;
	}
	++s;
    }
    if (mode != ASCII) {
	putescape(t, &p, TOASCII);
	mode = ASCII;
    }
    t[p] = EOS;
    return(t);
}


/* JIS (ISO-2022-JP) 文字列をEUC-JPに変換 */
char *jistoeuc(char *s)
{
    static char t[MAXLINE];
    int p;
    int code;
    int mode;

    p = 0;
    mode = ASCII;
    while (*s != EOS) {
	if ((*s == ESCAPE) && (*(s + 1) == TOKANJI)) {	/* 手抜き :-) */
	    /* && (*(s + 2) == SHIFTCODE)) { */
	    mode = KANJI;
	    s += 3;
	}
	else if ((*s == ESCAPE) && (*(s + 1) == TOASCII)) { /* 手抜き :-) */
	    /* && (*(s + 2) == SHIFTCODE)) { */
	    mode = ASCII;
	    s += 3;
	}
	else {
	    if (mode == KANJI) {
		code = jtoe(hilo(*s, *(s + 1)));
		++s;
		t[p++] = hibyte(code);
		t[p++] = lobyte(code);
	    }
	    else {
		t[p++] = *s;
	    }
	    ++s;
	}
    }
    t[p] = EOS;
    return(t);
}
