#include <sys/types.h>
#include <sys/param.h>
#include <sys/sysmacros.h>
#include <sys/systm.h>
#include <sys/debug.h>
#include <sys/kmem.h>
#include <sys/sunddi.h>
#include <sys/byteorder.h>
#include <sys/errno.h>
#include <sys/euc.h>
#include <sys/modctl.h>
#include <sys/kiconv.h>
#include <sys/kiconv_ja.h>
#include <sys/kiconv_ja_jis_to_unicode.h>
#include <sys/kiconv_ja_unicode_to_jis.h>
extern const int8_t u8_number_of_bytes[];
extern const uchar_t u8_masks_tbl[];
extern const uint8_t u8_valid_min_2nd_byte[];
extern const uint8_t u8_valid_max_2nd_byte[];
static kiconv_ja_euc16_t
kiconv_ja_ucs2_to_euc16(kiconv_ja_ucs2_t ucs2)
{
const kiconv_ja_euc16_t *p;
if ((p = kiconv_ja_ucs2_to_euc16_index[ucs2 >> 8]) != NULL)
return (p[ucs2 & 0xff]);
return (KICONV_JA_NODEST);
}
static size_t
utf8_ucs(uint_t *p, uchar_t **pip, size_t *pileft, int *errno)
{
uint_t l;
uchar_t ic;
uchar_t ic1;
uchar_t *ip = *pip;
size_t ileft = *pileft;
size_t rv = 0;
int remaining_bytes;
int u8_size;
KICONV_JA_NGET(ic1);
if (ic1 < 0x80) {
*p = (uint_t)ic1;
goto ret;
}
u8_size = u8_number_of_bytes[ic1];
if (u8_size == U8_ILLEGAL_CHAR) {
KICONV_JA_RETERROR(EILSEQ)
} else if (u8_size == U8_OUT_OF_RANGE_CHAR) {
KICONV_JA_RETERROR(ERANGE)
}
remaining_bytes = u8_size - 1;
if (remaining_bytes != 0) {
l = ic1 & u8_masks_tbl[remaining_bytes];
for (; remaining_bytes > 0; remaining_bytes--) {
KICONV_JA_NGET(ic);
if (ic1 != 0U) {
if ((ic < u8_valid_min_2nd_byte[ic1]) ||
(ic > u8_valid_max_2nd_byte[ic1])) {
KICONV_JA_RETERROR(EILSEQ)
}
ic1 = 0U;
} else {
if ((ic < 0x80) || (ic > 0xbf)) {
KICONV_JA_RETERROR(EILSEQ)
}
}
l = (l << 6) | (ic & 0x3f);
}
*p = l;
} else {
KICONV_JA_RETERROR(EILSEQ)
}
ret:
if (rv == 0) {
rv = *pileft - ileft;
*pip = ip;
*pileft = ileft;
}
return (rv);
}
static size_t
utf8_ucs_replace(uint_t *p, uchar_t **pip, size_t *pileft, size_t *repnum)
{
uint_t l;
uchar_t ic;
uchar_t ic1;
uchar_t *ip = *pip;
size_t ileft = *pileft;
size_t rv = 0;
int remaining_bytes;
int u8_size;
KICONV_JA_NGET_REP_TO_MB(ic1);
if (ic1 < 0x80) {
l = (uint_t)ic1;
goto ret;
}
u8_size = u8_number_of_bytes[ic1];
if (u8_size == U8_ILLEGAL_CHAR || u8_size == U8_OUT_OF_RANGE_CHAR) {
l = KICONV_JA_DEF_SINGLE;
(*repnum)++;
goto ret;
}
remaining_bytes = u8_size - 1;
if (remaining_bytes != 0) {
l = ic1 & u8_masks_tbl[remaining_bytes];
for (; remaining_bytes > 0; remaining_bytes--) {
KICONV_JA_NGET_REP_TO_MB(ic);
if (ic1 != 0U) {
if ((ic < u8_valid_min_2nd_byte[ic1]) ||
(ic > u8_valid_max_2nd_byte[ic1])) {
l = KICONV_JA_DEF_SINGLE;
(*repnum)++;
ileft -= (remaining_bytes - 1);
ip += (remaining_bytes - 1);
break;
}
ic1 = 0U;
} else {
if ((ic < 0x80) || (ic > 0xbf)) {
l = KICONV_JA_DEF_SINGLE;
(*repnum)++;
ileft -= (remaining_bytes - 1);
ip += (remaining_bytes - 1);
break;
}
}
l = (l << 6) | (ic & 0x3f);
}
} else {
l = KICONV_JA_DEF_SINGLE;
(*repnum)++;
}
ret:
*p = l;
rv = *pileft - ileft;
*pip = ip;
*pileft = ileft;
return (rv);
}
static size_t
read_unicode(
uint_t *p,
uchar_t **pip,
size_t *pileft,
int *errno,
int flag,
size_t *rv)
{
if (flag & KICONV_REPLACE_INVALID)
return (utf8_ucs_replace(p, pip, pileft, rv));
else
return (utf8_ucs(p, pip, pileft, errno));
}
static size_t
write_unicode(
uint_t u32,
char **pop,
size_t *poleft,
int *errno)
{
char *op = *pop;
size_t oleft = *poleft;
size_t rv = 0;
if (u32 <= 0x7f) {
KICONV_JA_NPUT((uchar_t)(u32));
rv = 1;
} else if (u32 <= 0x7ff) {
KICONV_JA_NPUT((uchar_t)((((u32)>>6) & 0x1f) | 0xc0));
KICONV_JA_NPUT((uchar_t)(((u32) & 0x3f) | 0x80));
rv = 2;
} else if ((u32 >= 0xd800) && (u32 <= 0xdfff)) {
KICONV_JA_RETERROR(EILSEQ)
} else if (u32 <= 0xffff) {
KICONV_JA_NPUT((uchar_t)((((u32)>>12) & 0x0f) | 0xe0));
KICONV_JA_NPUT((uchar_t)((((u32)>>6) & 0x3f) | 0x80));
KICONV_JA_NPUT((uchar_t)(((u32) & 0x3f) | 0x80));
rv = 3;
} else if (u32 <= 0x10ffff) {
KICONV_JA_NPUT((uchar_t)((((u32)>>18) & 0x07) | 0xf0));
KICONV_JA_NPUT((uchar_t)((((u32)>>12) & 0x3f) | 0x80));
KICONV_JA_NPUT((uchar_t)((((u32)>>6) & 0x3f) | 0x80));
KICONV_JA_NPUT((uchar_t)(((u32) & 0x3f) | 0x80));
rv = 4;
} else {
KICONV_JA_RETERROR(EILSEQ)
}
ret:
if (rv != (size_t)-1) {
*pop = op;
*poleft = oleft;
}
return (rv);
}
static void *
_kiconv_ja_open_unicode(uint8_t id)
{
kiconv_state_t kcd;
kcd = (kiconv_state_t)kmem_alloc(sizeof (kiconv_state_data_t),
KM_SLEEP);
kcd->id = id;
kcd->bom_processed = 0;
return ((void *)kcd);
}
static void *
open_eucjp(void)
{
return (_kiconv_ja_open_unicode(KICONV_JA_TBLID_EUCJP));
}
static void *
open_eucjpms(void)
{
return (_kiconv_ja_open_unicode(KICONV_JA_TBLID_EUCJP_MS));
}
static void *
open_sjis(void)
{
return (_kiconv_ja_open_unicode(KICONV_JA_TBLID_SJIS));
}
static void *
open_cp932(void)
{
return (_kiconv_ja_open_unicode(KICONV_JA_TBLID_CP932));
}
int
close_ja(void *kcd)
{
if (! kcd || kcd == (void *)-1)
return (EBADF);
kmem_free(kcd, sizeof (kiconv_state_data_t));
return (0);
}
static size_t
_do_kiconv_fr_eucjp(void *kcd, char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft, int *errno)
{
uint_t u32;
uint_t index;
uchar_t ic1, ic2, ic3;
size_t rv = 0;
uchar_t *ip;
size_t ileft;
char *op;
size_t oleft;
size_t id = ((kiconv_state_t)kcd)->id;
if ((inbuf == NULL) || (*inbuf == NULL)) {
return (0);
}
ip = (uchar_t *)*inbuf;
ileft = *inbytesleft;
op = *outbuf;
oleft = *outbytesleft;
while (ileft != 0) {
KICONV_JA_NGET(ic1);
if (KICONV_JA_ISASC(ic1)) {
u32 = kiconv_ja_jisx0201roman_to_ucs2[ic1];
KICONV_JA_PUTU(u32);
} else if (KICONV_JA_ISCS1(ic1)) {
KICONV_JA_NGET(ic2);
if (KICONV_JA_ISCS1(ic2)) {
ic1 &= KICONV_JA_CMASK;
ic2 &= KICONV_JA_CMASK;
KICONV_JA_CNV_JISMS_TO_U2(id, u32, ic1, ic2);
if (u32 == KICONV_JA_NODEST) {
index = (ic1 - 0x21) * 94 + ic2 - 0x21;
u32 = kiconv_ja_jisx0208_to_ucs2[index];
}
if (u32 == KICONV_JA_REPLACE)
rv++;
KICONV_JA_PUTU(u32);
} else {
KICONV_JA_RETERROR(EILSEQ)
}
} else if (ic1 == SS2) {
KICONV_JA_NGET(ic2);
if (KICONV_JA_ISCS2(ic2)) {
index = (ic2 - 0xa1);
u32 = kiconv_ja_jisx0201kana_to_ucs2[index];
KICONV_JA_PUTU(u32);
} else {
KICONV_JA_RETERROR(EILSEQ)
}
} else if (ic1 == SS3) {
KICONV_JA_NGET(ic2);
if (KICONV_JA_ISCS3(ic2)) {
KICONV_JA_NGET(ic3);
if (KICONV_JA_ISCS3(ic3)) {
ic2 &= KICONV_JA_CMASK;
ic3 &= KICONV_JA_CMASK;
KICONV_JA_CNV_JIS0212MS_TO_U2(id, u32,
ic2, ic3);
if (u32 == KICONV_JA_NODEST) {
index = ((ic2 - 0x21) * 94 +
(ic3 - 0x21));
u32 = kiconv_ja_jisx0212_to_ucs2
[index];
}
if (u32 == KICONV_JA_REPLACE)
rv++;
KICONV_JA_PUTU(u32);
} else {
KICONV_JA_RETERROR(EILSEQ)
}
} else {
KICONV_JA_RETERROR(EILSEQ)
}
} else if (KICONV_JA_ISC1CTRLEUC(ic1)) {
u32 = ic1;
KICONV_JA_PUTU(u32);
} else {
KICONV_JA_RETERROR(EILSEQ)
}
*inbuf = (char *)ip;
*inbytesleft = ileft;
*outbuf = op;
*outbytesleft = oleft;
}
ret:
return (rv);
}
static size_t
_do_kiconv_to_eucjp(void *kcd, char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft, int *errno)
{
uchar_t ic;
size_t rv = 0;
uint_t ucs4;
ushort_t euc16;
uchar_t *ip;
size_t ileft;
char *op;
size_t oleft;
size_t read_len;
size_t id = ((kiconv_state_t)kcd)->id;
if ((inbuf == NULL) || (*inbuf == NULL)) {
return (0);
}
ip = (uchar_t *)*inbuf;
ileft = *inbytesleft;
op = *outbuf;
oleft = *outbytesleft;
KICONV_JA_CHECK_UTF8_BOM(ip, ileft);
while (ileft != 0) {
KICONV_JA_GETU(&ucs4, 0);
if (ucs4 > 0xffff) {
KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE);
rv++;
goto next;
}
KICONV_JA_CNV_U2_TO_EUCJPMS(id, euc16, ucs4);
if (euc16 == KICONV_JA_NODEST) {
euc16 = kiconv_ja_ucs2_to_euc16((ushort_t)ucs4);
}
if (euc16 == KICONV_JA_NODEST) {
KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE);
rv++;
goto next;
}
switch (euc16 & 0x8080) {
case 0x0000:
ic = (uchar_t)euc16;
KICONV_JA_NPUT(ic);
break;
case 0x8080:
ic = (uchar_t)((euc16 >> 8) & 0xff);
KICONV_JA_NPUT(ic);
ic = (uchar_t)(euc16 & 0xff);
KICONV_JA_NPUT(ic);
break;
case 0x0080:
KICONV_JA_NPUT(SS2);
ic = (uchar_t)euc16;
KICONV_JA_NPUT(ic);
break;
case 0x8000:
KICONV_JA_NPUT(SS3);
ic = (uchar_t)((euc16 >> 8) & 0xff);
KICONV_JA_NPUT(ic);
ic = (uchar_t)(euc16 & KICONV_JA_CMASK);
KICONV_JA_NPUT(ic | KICONV_JA_CMSB);
break;
}
next:
*inbuf = (char *)ip;
*inbytesleft = ileft;
*outbuf = op;
*outbytesleft = oleft;
}
ret:
return (rv);
}
static size_t
_do_kiconvstr_fr_eucjp(char *inbuf, size_t *inbytesleft, char *outbuf,
size_t *outbytesleft, int flag, int *errno, uint8_t id)
{
uint_t u32;
uint_t index;
uchar_t ic1, ic2, ic3;
size_t rv = 0;
uchar_t *ip;
size_t ileft;
char *op;
size_t oleft;
boolean_t do_not_ignore_null;
if ((inbuf == NULL) || (*inbuf == '\0')) {
return (0);
}
ip = (uchar_t *)inbuf;
ileft = *inbytesleft;
op = outbuf;
oleft = *outbytesleft;
do_not_ignore_null = ((flag & KICONV_IGNORE_NULL) == 0);
while (ileft != 0) {
KICONV_JA_NGET(ic1);
if (KICONV_JA_ISASC(ic1)) {
if (ic1 == '\0' && do_not_ignore_null) {
return (0);
}
u32 = kiconv_ja_jisx0201roman_to_ucs2[ic1];
KICONV_JA_PUTU(u32);
} else if (KICONV_JA_ISCS1(ic1)) {
if (flag & KICONV_REPLACE_INVALID) {
KICONV_JA_NGET_REP_FR_MB(ic2);
} else {
KICONV_JA_NGET(ic2);
}
if (KICONV_JA_ISCS1(ic2)) {
ic1 &= KICONV_JA_CMASK;
ic2 &= KICONV_JA_CMASK;
KICONV_JA_CNV_JISMS_TO_U2(id, u32, ic1, ic2);
if (u32 == KICONV_JA_NODEST) {
index = (ic1 - 0x21) * 94 + ic2 - 0x21;
u32 = kiconv_ja_jisx0208_to_ucs2[index];
}
if (u32 == KICONV_JA_REPLACE)
rv++;
KICONV_JA_PUTU(u32);
} else {
if (flag & KICONV_REPLACE_INVALID) {
KICONV_JA_PUTU(KICONV_JA_REPLACE);
rv++;
} else {
KICONV_JA_RETERROR(EILSEQ)
}
}
} else if (ic1 == SS2) {
if (flag & KICONV_REPLACE_INVALID) {
KICONV_JA_NGET_REP_FR_MB(ic2);
} else {
KICONV_JA_NGET(ic2);
}
if (KICONV_JA_ISCS2(ic2)) {
index = (ic2 - 0xa1);
u32 = kiconv_ja_jisx0201kana_to_ucs2[index];
KICONV_JA_PUTU(u32);
} else {
if (flag & KICONV_REPLACE_INVALID) {
KICONV_JA_PUTU(KICONV_JA_REPLACE);
rv++;
} else {
KICONV_JA_RETERROR(EILSEQ)
}
}
} else if (ic1 == SS3) {
if (flag & KICONV_REPLACE_INVALID) {
KICONV_JA_NGET_REP_FR_MB(ic2);
} else {
KICONV_JA_NGET(ic2);
}
if (KICONV_JA_ISCS3(ic2)) {
if (flag & KICONV_REPLACE_INVALID) {
KICONV_JA_NGET_REP_FR_MB(ic3);
} else {
KICONV_JA_NGET(ic3);
}
if (KICONV_JA_ISCS3(ic3)) {
ic2 &= KICONV_JA_CMASK;
ic3 &= KICONV_JA_CMASK;
KICONV_JA_CNV_JIS0212MS_TO_U2(id, u32,
ic2, ic3);
if (u32 == KICONV_JA_NODEST) {
index = ((ic2 - 0x21) * 94 +
(ic3 - 0x21));
u32 = kiconv_ja_jisx0212_to_ucs2
[index];
}
if (u32 == KICONV_JA_REPLACE)
rv++;
KICONV_JA_PUTU(u32);
} else {
if (flag & KICONV_REPLACE_INVALID) {
KICONV_JA_PUTU(
KICONV_JA_REPLACE);
rv++;
} else {
KICONV_JA_RETERROR(EILSEQ)
}
}
} else {
if (flag & KICONV_REPLACE_INVALID) {
KICONV_JA_PUTU(KICONV_JA_REPLACE);
rv++;
} else {
KICONV_JA_RETERROR(EILSEQ)
}
}
} else if (KICONV_JA_ISC1CTRLEUC(ic1)) {
u32 = ic1;
KICONV_JA_PUTU(u32);
} else {
if (flag & KICONV_REPLACE_INVALID) {
KICONV_JA_PUTU(KICONV_JA_REPLACE);
rv++;
} else {
KICONV_JA_RETERROR(EILSEQ)
}
}
next:
*inbytesleft = ileft;
*outbytesleft = oleft;
}
ret:
return (rv);
}
static size_t
_do_kiconvstr_to_eucjp(char *inbuf, size_t *inbytesleft, char *outbuf,
size_t *outbytesleft, int flag, int *errno, uint8_t id)
{
uchar_t ic;
size_t rv = 0;
uint_t ucs4;
ushort_t euc16;
uchar_t *ip;
size_t ileft;
char *op;
size_t oleft;
size_t read_len;
boolean_t do_not_ignore_null;
if ((inbuf == NULL) || (*inbuf == '\0')) {
return (0);
}
ip = (uchar_t *)inbuf;
ileft = *inbytesleft;
op = outbuf;
oleft = *outbytesleft;
KICONV_JA_CHECK_UTF8_BOM_WITHOUT_STATE(ip, ileft);
do_not_ignore_null = ((flag & KICONV_IGNORE_NULL) == 0);
while (ileft != 0) {
KICONV_JA_GETU(&ucs4, flag);
if (ucs4 == 0x0 && do_not_ignore_null) {
return (0);
}
if (ucs4 > 0xffff) {
KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE);
rv++;
goto next;
}
KICONV_JA_CNV_U2_TO_EUCJPMS(id, euc16, ucs4);
if (euc16 == KICONV_JA_NODEST) {
euc16 = kiconv_ja_ucs2_to_euc16((ushort_t)ucs4);
}
if (euc16 == KICONV_JA_NODEST) {
KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE);
rv++;
goto next;
}
switch (euc16 & 0x8080) {
case 0x0000:
ic = (uchar_t)euc16;
KICONV_JA_NPUT(ic);
break;
case 0x8080:
ic = (uchar_t)((euc16 >> 8) & 0xff);
KICONV_JA_NPUT(ic);
ic = (uchar_t)(euc16 & 0xff);
KICONV_JA_NPUT(ic);
break;
case 0x0080:
KICONV_JA_NPUT(SS2);
ic = (uchar_t)euc16;
KICONV_JA_NPUT(ic);
break;
case 0x8000:
KICONV_JA_NPUT(SS3);
ic = (uchar_t)((euc16 >> 8) & 0xff);
KICONV_JA_NPUT(ic);
ic = (uchar_t)(euc16 & KICONV_JA_CMASK);
KICONV_JA_NPUT(ic | KICONV_JA_CMSB);
break;
}
next:
*inbytesleft = ileft;
*outbytesleft = oleft;
}
ret:
return (rv);
}
static size_t
kiconv_fr_eucjp(void *kcd, char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft, int *errno)
{
if (! kcd || kcd == (void *)-1) {
*errno = EBADF;
return ((size_t)-1);
}
return (_do_kiconv_fr_eucjp(kcd, inbuf, inbytesleft,
outbuf, outbytesleft, errno));
}
static size_t
kiconv_to_eucjp(void *kcd, char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft, int *errno)
{
if (! kcd || kcd == (void *)-1) {
*errno = EBADF;
return ((size_t)-1);
}
return (_do_kiconv_to_eucjp(kcd, inbuf, inbytesleft,
outbuf, outbytesleft, errno));
}
static size_t
kiconvstr_fr_eucjp(char *inbuf, size_t *inbytesleft, char *outbuf,
size_t *outbytesleft, int flag, int *errno)
{
return (_do_kiconvstr_fr_eucjp(inbuf, inbytesleft, outbuf,
outbytesleft, flag, errno, KICONV_JA_TBLID_EUCJP));
}
static size_t
kiconvstr_to_eucjp(char *inbuf, size_t *inbytesleft, char *outbuf,
size_t *outbytesleft, int flag, int *errno)
{
return (_do_kiconvstr_to_eucjp(inbuf, inbytesleft, outbuf,
outbytesleft, flag, errno, KICONV_JA_TBLID_EUCJP));
}
static size_t
kiconvstr_fr_eucjpms(char *inbuf, size_t *inbytesleft, char *outbuf,
size_t *outbytesleft, int flag, int *errno)
{
return (_do_kiconvstr_fr_eucjp(inbuf, inbytesleft, outbuf,
outbytesleft, flag, errno, KICONV_JA_TBLID_EUCJP_MS));
}
static size_t
kiconvstr_to_eucjpms(char *inbuf, size_t *inbytesleft, char *outbuf,
size_t *outbytesleft, int flag, int *errno)
{
return (_do_kiconvstr_to_eucjp(inbuf, inbytesleft, outbuf,
outbytesleft, flag, errno, KICONV_JA_TBLID_EUCJP_MS));
}
static size_t
_do_kiconv_fr_sjis(void *kcd, char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft, int *errno)
{
uint_t uni;
uint_t index;
uchar_t ic1, ic2;
size_t rv = 0;
uchar_t *ip;
size_t ileft;
char *op;
size_t oleft;
size_t id = ((kiconv_state_t)kcd)->id;
if ((inbuf == NULL) || (*inbuf == NULL)) {
return (0);
}
ip = (uchar_t *)*inbuf;
ileft = *inbytesleft;
op = *outbuf;
oleft = *outbytesleft;
while (ileft != 0) {
KICONV_JA_NGET(ic1);
if (KICONV_JA_ISASC((int)ic1)) {
uni = kiconv_ja_jisx0201roman_to_ucs2[ic1];
KICONV_JA_PUTU(uni);
} else if (KICONV_JA_ISSJKANA(ic1)) {
uni = kiconv_ja_jisx0201kana_to_ucs2[(ic1 - 0xa1)];
KICONV_JA_PUTU(uni);
} else if (KICONV_JA_ISSJKANJI1(ic1)) {
KICONV_JA_NGET(ic2);
if (KICONV_JA_ISSJKANJI2(ic2)) {
ic1 = kiconv_ja_sjtojis1[(ic1 - 0x80)];
if (ic2 >= 0x9f) {
ic1++;
}
ic2 = kiconv_ja_sjtojis2[ic2];
KICONV_JA_CNV_JISMS_TO_U2(id, uni, ic1, ic2);
if (uni == KICONV_JA_NODEST) {
index = ((ic1 - 0x21) * 94)
+ (ic2 - 0x21);
uni = kiconv_ja_jisx0208_to_ucs2[index];
}
if (uni == KICONV_JA_REPLACE)
rv++;
KICONV_JA_PUTU(uni);
} else {
KICONV_JA_RETERROR(EILSEQ)
}
} else if (KICONV_JA_ISSJSUPKANJI1(ic1)) {
KICONV_JA_NGET(ic2);
if (KICONV_JA_ISSJKANJI2(ic2)) {
ic1 = kiconv_ja_sjtojis1[(ic1 - 0x80)];
if (ic2 >= 0x9f) {
ic1++;
}
index = ((ic1 - 0x21) * 94)
+ (kiconv_ja_sjtojis2[ic2] - 0x21);
uni = kiconv_ja_jisx0212_to_ucs2[index];
if (uni == KICONV_JA_REPLACE)
rv++;
KICONV_JA_PUTU(uni);
} else {
KICONV_JA_RETERROR(EILSEQ)
}
} else if (KICONV_JA_ISSJIBM(ic1) ||
KICONV_JA_ISSJNECIBM(ic1)) {
KICONV_JA_NGET(ic2);
if (KICONV_JA_ISSJKANJI2(ic2)) {
ushort_t dest, upper, lower;
dest = (ic1 << 8) + ic2;
if ((0xed40 <= dest) && (dest <= 0xeffc)) {
KICONV_JA_REMAP_NEC(dest);
if (dest == 0xffff) {
KICONV_JA_RETERROR(EILSEQ)
}
}
if ((dest == 0xfa54) || (dest == 0xfa5b)) {
if (dest == 0xfa54) {
upper = 0x22;
lower = 0x4c;
} else {
upper = 0x22;
lower = 0x68;
}
KICONV_JA_CNV_JISMS_TO_U2(id, uni,
upper, lower);
if (uni == KICONV_JA_NODEST) {
index = (uint_t)((upper - 0x21)
* 94 + (lower - 0x21));
uni = kiconv_ja_jisx0208_to_ucs2
[index];
}
if (uni == KICONV_JA_REPLACE)
rv++;
KICONV_JA_PUTU(uni);
} else {
dest = dest - 0xfa40 -
(((dest>>8) - 0xfa) * 0x40);
dest = kiconv_ja_sjtoibmext[dest];
if (dest == 0xffff) {
KICONV_JA_RETERROR(EILSEQ)
}
upper = (dest >> 8) & KICONV_JA_CMASK;
lower = dest & KICONV_JA_CMASK;
KICONV_JA_CNV_JIS0212MS_TO_U2(id, uni,
upper, lower);
if (uni == KICONV_JA_NODEST) {
index = (uint_t)((upper - 0x21)
* 94 + (lower - 0x21));
uni = kiconv_ja_jisx0212_to_ucs2
[index];
}
if (uni == KICONV_JA_REPLACE)
rv++;
KICONV_JA_PUTU(uni);
}
} else {
KICONV_JA_RETERROR(EILSEQ)
}
} else if ((0xeb <= ic1) && (ic1 <= 0xec)) {
KICONV_JA_NGET(ic2);
if (KICONV_JA_ISSJKANJI2(ic2)) {
uni = 0xfffd;
KICONV_JA_PUTU(uni);
} else {
KICONV_JA_RETERROR(EILSEQ)
}
} else {
KICONV_JA_RETERROR(EILSEQ)
}
*inbuf = (char *)ip;
*inbytesleft = ileft;
*outbuf = op;
*outbytesleft = oleft;
}
ret:
return (rv);
}
static ushort_t
_kiconv_ja_lookuptbl(ushort_t dest)
{
ushort_t tmp;
int i;
int sz = (sizeof (kiconv_ja_sjtoibmext) /
sizeof (kiconv_ja_sjtoibmext[0]));
for (i = 0; i < sz; i++) {
tmp = (kiconv_ja_sjtoibmext[i] & 0x7f7f);
if (tmp == dest)
return ((i + 0xfa40 + ((i / 0xc0) * 0x40)));
}
return (0x3f);
}
static size_t
_do_kiconv_to_sjis(void *kcd, char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft, int *errno)
{
uchar_t ic;
size_t rv = 0;
uint_t ucs4;
ushort_t euc16;
ushort_t dest;
uchar_t *ip;
size_t ileft;
char *op;
size_t oleft;
size_t read_len;
size_t id = ((kiconv_state_t)kcd)->id;
if ((inbuf == NULL) || (*inbuf == NULL)) {
return (0);
}
ip = (uchar_t *)*inbuf;
ileft = *inbytesleft;
op = *outbuf;
oleft = *outbytesleft;
KICONV_JA_CHECK_UTF8_BOM(ip, ileft);
while (ileft != 0) {
KICONV_JA_GETU(&ucs4, 0);
if (ucs4 > 0xffff) {
KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE);
rv++;
goto next;
}
KICONV_JA_CNV_U2_TO_EUCJPMS(id, euc16, ucs4);
if (euc16 == KICONV_JA_NODEST) {
euc16 = kiconv_ja_ucs2_to_euc16((ushort_t)ucs4);
}
if (euc16 == KICONV_JA_NODEST) {
KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE);
rv++;
goto next;
}
switch (euc16 & 0x8080) {
case 0x0000:
if (KICONV_JA_ISC1CTRL((uchar_t)euc16)) {
KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE);
rv++;
} else {
ic = (uchar_t)euc16;
KICONV_JA_NPUT(ic);
}
break;
case 0x8080:
ic = (ushort_t)((euc16 >> 8) & KICONV_JA_CMASK);
KICONV_JA_NPUT(kiconv_ja_jis208tosj1[ic]);
ic = (uchar_t)((euc16 & KICONV_JA_CMASK)
+ (((ic % 2) == 0) ? 0x80 : 0x00));
KICONV_JA_NPUT(kiconv_ja_jistosj2[ic]);
break;
case 0x0080:
ic = (uchar_t)euc16;
KICONV_JA_NPUT(ic);
break;
case 0x8000:
ic = (ushort_t)((euc16 >> 8) & KICONV_JA_CMASK);
if (euc16 == 0xa271) {
KICONV_JA_NPUT(0x87);
KICONV_JA_NPUT(0x82);
} else if (ic < 0x75) {
dest = _kiconv_ja_lookuptbl(euc16 & 0x7f7f);
if (dest == 0xffff) {
KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE);
} else {
if (dest > 0xff) {
KICONV_JA_NPUT(
(dest >> 8) & 0xff);
KICONV_JA_NPUT(dest & 0xff);
} else {
KICONV_JA_NPUT(dest & 0xff);
}
}
} else {
KICONV_JA_NPUT(kiconv_ja_jis212tosj1[ic]);
ic = (ushort_t)((euc16 & KICONV_JA_CMASK)
+ (((ic % 2) == 0) ? 0x80 : 0x00));
KICONV_JA_NPUT(kiconv_ja_jistosj2[ic]);
}
break;
}
next:
*inbuf = (char *)ip;
*inbytesleft = ileft;
*outbuf = op;
*outbytesleft = oleft;
}
ret:
return (rv);
}
static size_t
_do_kiconvstr_fr_sjis(char *inbuf, size_t *inbytesleft, char *outbuf,
size_t *outbytesleft, int flag, int *errno, uint8_t id)
{
uint_t uni;
uint_t index;
uchar_t ic1, ic2;
size_t rv = 0;
uchar_t *ip;
size_t ileft;
char *op;
size_t oleft;
boolean_t do_not_ignore_null;
if ((inbuf == NULL) || (*inbuf == '\0')) {
return (0);
}
ip = (uchar_t *)inbuf;
ileft = *inbytesleft;
op = outbuf;
oleft = *outbytesleft;
do_not_ignore_null = ((flag & KICONV_IGNORE_NULL) == 0);
while (ileft != 0) {
KICONV_JA_NGET(ic1);
if (KICONV_JA_ISASC((int)ic1)) {
if (ic1 == '\0' && do_not_ignore_null) {
return (0);
}
uni = kiconv_ja_jisx0201roman_to_ucs2[ic1];
KICONV_JA_PUTU(uni);
} else if (KICONV_JA_ISSJKANA(ic1)) {
uni = kiconv_ja_jisx0201kana_to_ucs2[(ic1 - 0xa1)];
KICONV_JA_PUTU(uni);
} else if (KICONV_JA_ISSJKANJI1(ic1)) {
if (flag & KICONV_REPLACE_INVALID) {
KICONV_JA_NGET_REP_FR_MB(ic2);
} else {
KICONV_JA_NGET(ic2);
}
if (KICONV_JA_ISSJKANJI2(ic2)) {
ic1 = kiconv_ja_sjtojis1[(ic1 - 0x80)];
if (ic2 >= 0x9f) {
ic1++;
}
ic2 = kiconv_ja_sjtojis2[ic2];
KICONV_JA_CNV_JISMS_TO_U2(id, uni, ic1, ic2);
if (uni == KICONV_JA_NODEST) {
index = ((ic1 - 0x21) * 94)
+ (ic2 - 0x21);
uni = kiconv_ja_jisx0208_to_ucs2[index];
}
if (uni == KICONV_JA_REPLACE)
rv++;
KICONV_JA_PUTU(uni);
} else {
if (flag & KICONV_REPLACE_INVALID) {
KICONV_JA_PUTU(KICONV_JA_REPLACE);
rv++;
} else {
KICONV_JA_RETERROR(EILSEQ)
}
}
} else if (KICONV_JA_ISSJSUPKANJI1(ic1)) {
if (flag & KICONV_REPLACE_INVALID) {
KICONV_JA_NGET_REP_FR_MB(ic2);
} else {
KICONV_JA_NGET(ic2);
}
if (KICONV_JA_ISSJKANJI2(ic2)) {
ic1 = kiconv_ja_sjtojis1[(ic1 - 0x80)];
if (ic2 >= 0x9f) {
ic1++;
}
index = ((ic1 - 0x21) * 94)
+ (kiconv_ja_sjtojis2[ic2] - 0x21);
uni = kiconv_ja_jisx0212_to_ucs2[index];
if (uni == KICONV_JA_REPLACE)
rv++;
KICONV_JA_PUTU(uni);
} else {
if (flag & KICONV_REPLACE_INVALID) {
KICONV_JA_PUTU(KICONV_JA_REPLACE);
rv++;
} else {
KICONV_JA_RETERROR(EILSEQ)
}
}
} else if (KICONV_JA_ISSJIBM(ic1) ||
KICONV_JA_ISSJNECIBM(ic1)) {
if (flag & KICONV_REPLACE_INVALID) {
KICONV_JA_NGET_REP_FR_MB(ic2);
} else {
KICONV_JA_NGET(ic2);
}
if (KICONV_JA_ISSJKANJI2(ic2)) {
ushort_t dest, upper, lower;
dest = (ic1 << 8) + ic2;
if ((0xed40 <= dest) && (dest <= 0xeffc)) {
KICONV_JA_REMAP_NEC(dest);
if (dest == 0xffff) {
if (flag &
KICONV_REPLACE_INVALID) {
KICONV_JA_PUTU(
KICONV_JA_REPLACE);
rv++;
} else {
KICONV_JA_RETERROR(
EILSEQ)
}
}
}
if ((dest == 0xfa54) || (dest == 0xfa5b)) {
if (dest == 0xfa54) {
upper = 0x22;
lower = 0x4c;
} else {
upper = 0x22;
lower = 0x68;
}
KICONV_JA_CNV_JISMS_TO_U2(id, uni,
upper, lower);
if (uni == KICONV_JA_NODEST) {
index = (uint_t)((upper - 0x21)
* 94 + (lower - 0x21));
uni = kiconv_ja_jisx0208_to_ucs2
[index];
}
if (uni == KICONV_JA_REPLACE)
rv++;
KICONV_JA_PUTU(uni);
} else {
dest = dest - 0xfa40 -
(((dest>>8) - 0xfa) * 0x40);
dest = kiconv_ja_sjtoibmext[dest];
if (dest == 0xffff) {
if (flag &
KICONV_REPLACE_INVALID) {
KICONV_JA_PUTU(
KICONV_JA_REPLACE);
rv++;
} else {
KICONV_JA_RETERROR(
EILSEQ)
}
}
upper = (dest >> 8) & KICONV_JA_CMASK;
lower = dest & KICONV_JA_CMASK;
KICONV_JA_CNV_JIS0212MS_TO_U2(id, uni,
upper, lower);
if (uni == KICONV_JA_NODEST) {
index = (uint_t)((upper - 0x21)
* 94 + (lower - 0x21));
uni = kiconv_ja_jisx0212_to_ucs2
[index];
}
if (uni == KICONV_JA_REPLACE)
rv++;
KICONV_JA_PUTU(uni);
}
} else {
if (flag & KICONV_REPLACE_INVALID) {
KICONV_JA_PUTU(KICONV_JA_REPLACE);
rv++;
} else {
KICONV_JA_RETERROR(EILSEQ)
}
}
} else if ((0xeb <= ic1) && (ic1 <= 0xec)) {
if (flag & KICONV_REPLACE_INVALID) {
KICONV_JA_NGET_REP_FR_MB(ic2);
} else {
KICONV_JA_NGET(ic2);
}
if (KICONV_JA_ISSJKANJI2(ic2)) {
uni = 0xfffd;
KICONV_JA_PUTU(uni);
} else {
if (flag & KICONV_REPLACE_INVALID) {
KICONV_JA_PUTU(KICONV_JA_REPLACE);
rv++;
} else {
KICONV_JA_RETERROR(EILSEQ)
}
}
} else {
if (flag & KICONV_REPLACE_INVALID) {
KICONV_JA_PUTU(KICONV_JA_REPLACE);
rv++;
} else {
KICONV_JA_RETERROR(EILSEQ)
}
}
next:
*inbytesleft = ileft;
*outbytesleft = oleft;
}
ret:
return (rv);
}
static size_t
_do_kiconvstr_to_sjis(char *inbuf, size_t *inbytesleft, char *outbuf,
size_t *outbytesleft, int flag, int *errno, uint8_t id)
{
uchar_t ic;
size_t rv = 0;
uint_t ucs4;
ushort_t euc16;
ushort_t dest;
uchar_t *ip;
size_t ileft;
char *op;
size_t oleft;
size_t read_len;
boolean_t do_not_ignore_null;
if ((inbuf == NULL) || (*inbuf == '\0')) {
return (0);
}
ip = (uchar_t *)inbuf;
ileft = *inbytesleft;
op = outbuf;
oleft = *outbytesleft;
KICONV_JA_CHECK_UTF8_BOM_WITHOUT_STATE(ip, ileft);
do_not_ignore_null = ((flag & KICONV_IGNORE_NULL) == 0);
while (ileft != 0) {
KICONV_JA_GETU(&ucs4, flag);
if (ucs4 == 0x0 && do_not_ignore_null) {
return (0);
}
if (ucs4 > 0xffff) {
KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE);
rv++;
goto next;
}
KICONV_JA_CNV_U2_TO_EUCJPMS(id, euc16, ucs4);
if (euc16 == KICONV_JA_NODEST) {
euc16 = kiconv_ja_ucs2_to_euc16((ushort_t)ucs4);
}
if (euc16 == KICONV_JA_NODEST) {
KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE);
rv++;
goto next;
}
switch (euc16 & 0x8080) {
case 0x0000:
if (KICONV_JA_ISC1CTRL((uchar_t)euc16)) {
KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE);
rv++;
} else {
ic = (uchar_t)euc16;
KICONV_JA_NPUT(ic);
}
break;
case 0x8080:
ic = (ushort_t)((euc16 >> 8) & KICONV_JA_CMASK);
KICONV_JA_NPUT(kiconv_ja_jis208tosj1[ic]);
ic = (uchar_t)((euc16 & KICONV_JA_CMASK)
+ (((ic % 2) == 0) ? 0x80 : 0x00));
KICONV_JA_NPUT(kiconv_ja_jistosj2[ic]);
break;
case 0x0080:
ic = (uchar_t)euc16;
KICONV_JA_NPUT(ic);
break;
case 0x8000:
ic = (ushort_t)((euc16 >> 8) & KICONV_JA_CMASK);
if (euc16 == 0xa271) {
KICONV_JA_NPUT(0x87);
KICONV_JA_NPUT(0x82);
} else if (ic < 0x75) {
dest = _kiconv_ja_lookuptbl(euc16 & 0x7f7f);
if (dest == 0xffff) {
KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE);
} else {
if (dest > 0xff) {
KICONV_JA_NPUT(
(dest >> 8) & 0xff);
KICONV_JA_NPUT(dest & 0xff);
} else {
KICONV_JA_NPUT(dest & 0xff);
}
}
} else {
KICONV_JA_NPUT(kiconv_ja_jis212tosj1[ic]);
ic = (ushort_t)((euc16 & KICONV_JA_CMASK)
+ (((ic % 2) == 0) ? 0x80 : 0x00));
KICONV_JA_NPUT(kiconv_ja_jistosj2[ic]);
}
break;
}
next:
*inbytesleft = ileft;
*outbytesleft = oleft;
}
ret:
return (rv);
}
static size_t
kiconv_fr_sjis(void *kcd, char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft, int *errno)
{
if (! kcd || kcd == (void *)-1) {
*errno = EBADF;
return ((size_t)-1);
}
return (_do_kiconv_fr_sjis(kcd, inbuf, inbytesleft,
outbuf, outbytesleft, errno));
}
static size_t
kiconv_to_sjis(void *kcd, char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft, int *errno)
{
if (! kcd || kcd == (void *)-1) {
*errno = EBADF;
return ((size_t)-1);
}
return (_do_kiconv_to_sjis(kcd, inbuf, inbytesleft,
outbuf, outbytesleft, errno));
}
static size_t
kiconvstr_fr_sjis(char *inbuf, size_t *inbytesleft, char *outbuf,
size_t *outbytesleft, int flag, int *errno)
{
return (_do_kiconvstr_fr_sjis(inbuf, inbytesleft, outbuf,
outbytesleft, flag, errno, KICONV_JA_TBLID_SJIS));
}
static size_t
kiconvstr_to_sjis(char *inbuf, size_t *inbytesleft, char *outbuf,
size_t *outbytesleft, int flag, int *errno)
{
return (_do_kiconvstr_to_sjis(inbuf, inbytesleft, outbuf,
outbytesleft, flag, errno, KICONV_JA_TBLID_SJIS));
}
static size_t
kiconvstr_fr_cp932(char *inbuf, size_t *inbytesleft, char *outbuf,
size_t *outbytesleft, int flag, int *errno)
{
return (_do_kiconvstr_fr_sjis(inbuf, inbytesleft, outbuf,
outbytesleft, flag, errno, KICONV_JA_TBLID_CP932));
}
static size_t
kiconvstr_to_cp932(char *inbuf, size_t *inbytesleft, char *outbuf,
size_t *outbytesleft, int flag, int *errno)
{
return (_do_kiconvstr_to_sjis(inbuf, inbytesleft, outbuf,
outbytesleft, flag, errno, KICONV_JA_TBLID_CP932));
}
static kiconv_ops_t kiconv_ja_ops_tbl[] = {
{
"eucjp", "utf-8", open_eucjp,
kiconv_to_eucjp, close_ja, kiconvstr_to_eucjp
},
{
"utf-8", "eucjp", open_eucjp,
kiconv_fr_eucjp, close_ja, kiconvstr_fr_eucjp
},
{
"eucjpms", "utf-8", open_eucjpms,
kiconv_to_eucjp, close_ja, kiconvstr_to_eucjpms
},
{
"utf-8", "eucjpms", open_eucjpms,
kiconv_fr_eucjp, close_ja, kiconvstr_fr_eucjpms
},
{
"sjis", "utf-8", open_sjis,
kiconv_to_sjis, close_ja, kiconvstr_to_sjis
},
{
"utf-8", "sjis", open_sjis,
kiconv_fr_sjis, close_ja, kiconvstr_fr_sjis
},
{
"cp932", "utf-8", open_cp932,
kiconv_to_sjis, close_ja, kiconvstr_to_cp932
},
{
"utf-8", "cp932", open_cp932,
kiconv_fr_sjis, close_ja, kiconvstr_fr_cp932
}
};
static char *kiconv_ja_aliases[] = {"932", "shiftjis", "pck"};
static char *kiconv_ja_canonicals[] = {"cp932", "sjis", "sjis"};
#define KICONV_JA_MAX_JA_OPS \
(sizeof (kiconv_ja_ops_tbl) / sizeof (kiconv_ops_t))
#define KICONV_JA_MAX_JA_ALIAS \
(sizeof (kiconv_ja_aliases) / sizeof (char *))
static kiconv_module_info_t kiconv_ja_info = {
"kiconv_ja",
KICONV_JA_MAX_JA_OPS,
kiconv_ja_ops_tbl,
KICONV_JA_MAX_JA_ALIAS,
kiconv_ja_aliases,
kiconv_ja_canonicals,
0
};
static struct modlkiconv modlkiconv_ja = {
&mod_kiconvops,
"kiconv module for Japanese",
&kiconv_ja_info
};
static struct modlinkage modlinkage = {
MODREV_1,
(void *)&modlkiconv_ja,
NULL
};
int
_init(void)
{
int err;
err = mod_install(&modlinkage);
if (err)
cmn_err(CE_WARN, "kiconv_ja: failed to load kernel module");
return (err);
}
int
_info(struct modinfo *modinfop)
{
return (mod_info(&modlinkage, modinfop));
}
int
_fini(void)
{
int err;
if (kiconv_module_ref_count(KICONV_MODULE_ID_JA))
return (EBUSY);
err = mod_remove(&modlinkage);
if (err)
cmn_err(CE_WARN, "kiconv_ja: failed to remove kernel module");
return (err);
}