/* $Xorg: lcJis.c,v 1.3 2000/08/17 19:45:18 cpqbld Exp $ */
/*
* Copyright 1992, 1993 by TOSHIBA Corp.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of TOSHIBA not be used in advertising
* or publicity pertaining to distribution of the software without specific,
* written prior permission. TOSHIBA make no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* TOSHIBA DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
* TOSHIBA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
* ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
* WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*
* Author: Katsuhisa Yano TOSHIBA Corp.
* mopi@osa.ilab.toshiba.co.jp
*/
/* $XFree86: xc/lib/X11/lcJis.c,v 1.9 2002/04/10 16:20:06 tsi Exp $ */
/*
* A Japanese JIS locale.
* Supports: all locales with codeset JIS7.
* How: Provides converters for JIS.
* Platforms: Only those defining X_LOCALE (only Lynx, Linux-libc5, OS/2).
*/
#ifdef X_LOCALE
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "Xlibint.h"
#include "XlcGeneric.h"
#include <stdio.h>
#if !defined(macII) && !defined(X_LOCALE)
#define STDCVT
#endif
typedef struct _StateRec {
XLCd lcd;
XlcCharSet charset;
XlcCharSet GL_charset;
XlcCharSet GR_charset;
} StateRec, *State;
static void
init_state(
XlcConv conv)
{
State state = (State) conv->state;
XLCdGenericPart *gen = XLC_GENERIC_PART(state->lcd);
CodeSet codeset;
codeset = gen->initial_state_GL;
if (codeset && codeset->charset_list)
state->GL_charset = *codeset->charset_list;
codeset = gen->initial_state_GR;
if (codeset && codeset->charset_list)
state->GR_charset = *codeset->charset_list;
if (state->GL_charset == NULL)
if ((codeset = *gen->codeset_list) != NULL)
state->GL_charset = *codeset->charset_list;
}
static int
compare(
const char *src,
const char *encoding,
int length)
{
const char *start = src;
while (length-- > 0) {
if (*src++ != *encoding++)
return 0;
if (*encoding == '\0')
return src - start;
}
return 0;
}
static int
mbtocs(
XlcConv conv,
XPointer *from,
int *from_left,
XPointer *to,
int *to_left,
XPointer *args,
int num_args)
{
State state = (State) conv->state;
XLCd lcd = state->lcd;
const char *src;
char *dst;
unsigned char *mb_parse_table;
ParseInfo *parse_list, parse_info;
XlcCharSet charset;
int length, number, encoding_len = 0;
int i;
src = *((const char **) from);
dst = *((char **) to);
mb_parse_table = XLC_GENERIC(lcd, mb_parse_table);
if (mb_parse_table != NULL) {
number = mb_parse_table[(unsigned char) *src];
if (number > 0) {
parse_list = XLC_GENERIC(lcd, mb_parse_list) + number - 1;
for ( ; (parse_info = *parse_list) != NULL; parse_list++) {
encoding_len = compare(src, parse_info->encoding, *from_left);
if (encoding_len > 0) {
switch (parse_info->type) {
case E_SS:
src += encoding_len;
charset = *parse_info->codeset->charset_list;
goto found;
case E_LSL:
case E_LSR:
src += encoding_len;
charset = *parse_info->codeset->charset_list;
if (parse_info->type == E_LSL)
state->GL_charset = charset;
else
state->GR_charset = charset;
length = 0;
goto end;
case E_GL:
charset = state->GL_charset;
goto found;
case E_GR:
charset = state->GR_charset;
goto found;
default:
break;
}
}
}
}
}
if ((*src & 0x80) && state->GR_charset)
charset = state->GR_charset;
else
charset = state->GL_charset;
found:
if (charset == NULL ||
(num_args == 2 && (XlcCharSet) args[1] != charset))
return -1;
length = charset->char_size;
if (length > *from_left - encoding_len)
return -1;
if (dst) {
if (length > *to_left)
return -1;
if (charset->side == XlcGL) {
for (i = 0; i < length; i++)
*dst++ = *src++ & 0x7f;
} else if (charset->side == XlcGR) {
for (i = 0; i < length; i++)
*dst++ = *src++ | 0x80;
} else {
for (i = 0; i < length; i++)
*dst++ = *src++;
}
*to = (XPointer) dst;
*to_left -= length;
}
end:
*from = (XPointer) src;
*from_left -= encoding_len + length;
state->charset = charset;
if (num_args == 1)
*((XlcCharSet *) args[0]) = charset;
return 0;
}
static int
mbstocs(
XlcConv conv,
XPointer *from,
int *from_left,
XPointer *to,
int *to_left,
XPointer *args,
int num_args)
{
XlcCharSet charset = NULL;
XPointer tmp_args[2], save_from = *from;
int ret, unconv_num = 0, tmp_num = 1;
tmp_args[0] = (XPointer) &charset;
while (*from_left > 0 && *to_left > 0) {
ret = mbtocs(conv, from, from_left, to, to_left, tmp_args, tmp_num);
if (ret < 0)
break;
unconv_num += ret;
if (tmp_num == 1 && charset) {
tmp_args[1] = (XPointer) charset;
tmp_num = 2;
}
}
if (save_from == *from)
return -1;
if (num_args > 0)
*((XlcCharSet *) args[0]) = charset;
return unconv_num;
}
static CodeSet
wc_parse_codeset(
XLCd lcd,
const wchar_t *wcstr)
{
CodeSet *codeset;
unsigned long wc_encoding;
int num;
wc_encoding = *wcstr & XLC_GENERIC(lcd, wc_encode_mask);
num = XLC_GENERIC(lcd, codeset_num);
codeset = XLC_GENERIC(lcd, codeset_list);
while (num-- > 0) {
if (wc_encoding == (*codeset)->wc_encoding)
return *codeset;
codeset++;
}
return NULL;
}
static int
wcstocs(
XlcConv conv,
XPointer *from,
int *from_left,
XPointer *to,
int *to_left,
XPointer *args,
int num_args)
{
State state = (State) conv->state;
XLCd lcd = state->lcd;
const wchar_t *wcptr;
char *bufptr;
wchar_t wch;
char *tmpptr;
int length;
CodeSet codeset;
unsigned long wc_encoding;
int wcstr_len, buf_len;
if (from == NULL || *from == NULL)
return 0;
wcptr = *((const wchar_t **) from);
bufptr = *((char **) to);
wcstr_len = *from_left;
buf_len = *to_left;
codeset = wc_parse_codeset(lcd, wcptr);
if (codeset == NULL)
return -1;
wc_encoding = codeset->wc_encoding;
if (wcstr_len < buf_len / codeset->length)
buf_len = wcstr_len * codeset->length;
for ( ; wcstr_len > 0 && buf_len > 0; wcptr++, wcstr_len--) {
wch = *wcptr;
if ((wch & XLC_GENERIC(lcd, wc_encode_mask)) != wc_encoding)
break;
length = codeset->length;
buf_len -= length;
bufptr += length;
tmpptr = bufptr - 1;
if ((*codeset->charset_list)->side == XlcGL) {
while (length--) {
*tmpptr-- = (unsigned char) (wch & 0x7f);
wch >>= (wchar_t)XLC_GENERIC(lcd, wc_shift_bits);
}
} else if ((*codeset->charset_list)->side == XlcGR) {
while (length--) {
*tmpptr-- = (unsigned char) (wch | 0x80);
wch >>= (wchar_t)XLC_GENERIC(lcd, wc_shift_bits);
}
} else {
while (length--) {
*tmpptr-- = (unsigned char) wch;
wch >>= (wchar_t)XLC_GENERIC(lcd, wc_shift_bits);
}
}
}
if (num_args > 0)
*((XlcCharSet *) args[0]) = *codeset->charset_list;
*from_left -= wcptr - *((wchar_t **) from);
*from = (XPointer) wcptr;
*to_left -= bufptr - *((char **) to);
*to = bufptr;
return 0;
}
static CodeSet
GetCodeSetFromCharSet(
XLCd lcd,
XlcCharSet charset)
{
CodeSet *codeset = XLC_GENERIC(lcd, codeset_list);
XlcCharSet *charset_list;
int codeset_num, num_charsets;
codeset_num = XLC_GENERIC(lcd, codeset_num);
for ( ; codeset_num-- > 0; codeset++) {
num_charsets = (*codeset)->num_charsets;
charset_list = (*codeset)->charset_list;
for ( ; num_charsets-- > 0; charset_list++)
if (*charset_list == charset)
return *codeset;
}
return (CodeSet) NULL;
}
static int
cstombs(
XlcConv conv,
XPointer *from,
int *from_left,
XPointer *to,
int *to_left,
XPointer *args,
int num_args)
{
State state = (State) conv->state;
const char *csptr;
char *bufptr;
int csstr_len;
int buf_len;
int num, encoding_len = 0;
CodeSet codeset;
XlcCharSet charset;
EncodingType type;
int cvt_length;
csptr = *((const char **) from);
bufptr = *((char **) to);
csstr_len = *from_left;
buf_len = *to_left;
if (num_args < 1)
return -1;
charset = (XlcCharSet) args[0];
codeset = GetCodeSetFromCharSet(state->lcd, charset);
if (codeset == NULL)
return -1;
cvt_length = 0;
if (codeset->parse_info) {
switch (type = codeset->parse_info->type) {
case E_SS:
encoding_len = strlen(codeset->parse_info->encoding);
break;
case E_LSL:
case E_LSR:
if (type == E_LSL) {
if (charset == state->GL_charset)
break;
} else {
if (charset == state->GR_charset)
break;
}
encoding_len = strlen(codeset->parse_info->encoding);
if (encoding_len > buf_len)
return -1;
cvt_length += encoding_len;
if (bufptr) {
strcpy(bufptr, codeset->parse_info->encoding);
bufptr += encoding_len;
}
buf_len -= encoding_len;
encoding_len = 0;
if (type == E_LSL)
state->GL_charset = charset;
else
state->GR_charset = charset;
break;
default:
break;
}
}
csstr_len /= codeset->length;
buf_len /= codeset->length + encoding_len;
if (csstr_len < buf_len)
buf_len = csstr_len;
cvt_length += buf_len * (encoding_len + codeset->length);
if (bufptr) {
while (buf_len--) {
if (encoding_len) {
strcpy(bufptr, codeset->parse_info->encoding);
bufptr += encoding_len;
}
num = codeset->length;
if (codeset->side == XlcGL) {
while (num--)
*bufptr++ = *csptr++ & 0x7f;
} else if (codeset->side == XlcGR) {
while (num--)
*bufptr++ = *csptr++ | 0x80;
} else {
while (num--)
*bufptr++ = *csptr++;
}
}
}
*from_left -= csptr - *((char **) from);
*from = (XPointer) csptr;
if (bufptr)
*to = (XPointer) bufptr;
*to_left -= cvt_length;
return 0;
}
static int
cstowcs(
XlcConv conv,
XPointer *from,
int *from_left,
XPointer *to,
int *to_left,
XPointer *args,
int num_args)
{
State state = (State) conv->state;
XLCd lcd = state->lcd;
const char *csptr;
wchar_t *bufptr;
int csstr_len;
int buf_len;
wchar_t wch;
unsigned long code_mask, wc_encoding;
int num, length, wc_shift_bits;
CodeSet codeset;
csptr = *((const char **) from);
bufptr = *((wchar_t **) to);
csstr_len = *from_left;
buf_len = *to_left;
if (num_args < 1)
return -1;
codeset = GetCodeSetFromCharSet(lcd, (XlcCharSet) args[0]);
if (codeset == NULL)
return -1;
length = codeset->length;
csstr_len /= length;
if (csstr_len < buf_len)
buf_len = csstr_len;
code_mask = ~XLC_GENERIC(lcd, wc_encode_mask);
wc_encoding = codeset->wc_encoding;
wc_shift_bits = XLC_GENERIC(lcd, wc_shift_bits);
*to_left -= buf_len;
if (bufptr) {
while (buf_len--) {
wch = (wchar_t) (*csptr++ & 0x7f);
num = length - 1;
while (num--)
wch = (wch << wc_shift_bits) | (*csptr++ & 0x7f);
*bufptr++ = (wch & code_mask) | wc_encoding;
}
}
*from_left -= csptr - *((char **) from);
*from = (XPointer) csptr;
if (bufptr)
*to = (XPointer) bufptr;
return 0;
}
static void
close_converter(
XlcConv conv)
{
if (conv->state) {
Xfree((char *) conv->state);
}
Xfree((char *) conv);
}
static XlcConv
create_conv(
XLCd lcd,
XlcConvMethods methods)
{
XlcConv conv;
State state;
conv = (XlcConv) Xmalloc(sizeof(XlcConvRec));
if (conv == NULL)
return (XlcConv) NULL;
conv->methods = (XlcConvMethods) Xmalloc(sizeof(XlcConvMethodsRec));
if (conv->methods == NULL)
goto err;
*conv->methods = *methods;
if (XLC_PUBLIC(lcd, is_state_depend))
conv->methods->reset = init_state;
conv->state = (XPointer) Xmalloc(sizeof(StateRec));
if (conv->state == NULL)
goto err;
bzero((char *) conv->state, sizeof(StateRec));
state = (State) conv->state;
state->lcd = lcd;
init_state(conv);
return conv;
err:
close_converter(conv);
return (XlcConv) NULL;
}
static XlcConvMethodsRec mbstocs_methods = {
close_converter,
mbstocs,
NULL
};
static XlcConv
open_mbstocs(
XLCd from_lcd,
const char *from_type,
XLCd to_lcd,
const char *to_type)
{
return create_conv(from_lcd, &mbstocs_methods);
}
static XlcConvMethodsRec wcstocs_methods = {
close_converter,
wcstocs,
NULL
};
static XlcConv
open_wcstocs(
XLCd from_lcd,
const char *from_type,
XLCd to_lcd,
const char *to_type)
{
return create_conv(from_lcd, &wcstocs_methods);
}
static XlcConvMethodsRec mbtocs_methods = {
close_converter,
mbtocs,
NULL
};
static XlcConv
open_mbtocs(
XLCd from_lcd,
const char *from_type,
XLCd to_lcd,
const char *to_type)
{
return create_conv(from_lcd, &mbtocs_methods);
}
static XlcConvMethodsRec cstombs_methods = {
close_converter,
cstombs,
NULL
};
static XlcConv
open_cstombs(
XLCd from_lcd,
const char *from_type,
XLCd to_lcd,
const char *to_type)
{
return create_conv(from_lcd, &cstombs_methods);
}
static XlcConvMethodsRec cstowcs_methods = {
close_converter,
cstowcs,
NULL
};
static XlcConv
open_cstowcs(
XLCd from_lcd,
const char *from_type,
XLCd to_lcd,
const char *to_type)
{
return create_conv(from_lcd, &cstowcs_methods);
}
#ifdef STDCVT
static int
stdc_mbstowcs(
XlcConv conv,
XPointer *from,
int *from_left,
XPointer *to,
int *to_left,
XPointer *args,
int num_args)
{
const char *src = *((const char **) from);
wchar_t *dst = *((wchar_t **) to);
int src_left = *from_left;
int dst_left = *to_left;
int length;
while (src_left > 0 && dst_left > 0) {
length = mbtowc(dst, src, src_left);
if (length < 0)
break;
src += length;
src_left -= length;
if (dst)
dst++;
dst_left--;
if (length == 0) {
src++;
src_left--;
break;
}
}
if (*from_left == src_left)
return -1;
*from = (XPointer) src;
if (dst)
*to = (XPointer) dst;
*from_left = src_left;
*to_left = dst_left;
return 0;
}
static int
stdc_wcstombs(
XlcConv conv,
XPointer *from,
int *from_left,
XPointer *to,
int *to_left,
XPointer *args,
int num_args)
{
const wchar_t *src = *((const wchar_t **) from);
char *dst = *((char **) to);
int src_left = *from_left;
int dst_left = *to_left;
int length;
while (src_left > 0 && dst_left > 0) {
length = wctomb(dst, *src); /* XXX */
if (length < 0 || dst_left < length)
break;
src++;
src_left--;
dst += length;
dst_left -= length;
if (length == 0) {
dst++;
dst_left--;
break;
}
}
if (*from_left == src_left)
return -1;
*from = (XPointer) src;
*to = (XPointer) dst;
*from_left = src_left;
*to_left = dst_left;
return 0;
}
static int
stdc_wcstocs(
XlcConv conv,
XPointer *from,
int *from_left,
XPointer *to,
int *to_left,
XPointer *args,
int num_args)
{
const wchar_t *src = *((const wchar_t **) from);
wchar_t wch;
XlcCharSet charset = NULL;
XPointer tmp_args[2], tmp_from, save_from = *from;
char tmp[32];
int length, ret, src_left = *from_left;
int unconv_num = 0, tmp_num = 1;
tmp_args[0] = (XPointer) &charset;
while (src_left > 0 && *to_left > 0) {
if (wch = *src) {
length = wctomb(tmp, wch);
} else {
length = 1;
*tmp = '\0';
}
if (length < 0)
break;
tmp_from = (XPointer) tmp;
ret = mbtocs(conv, &tmp_from, &length, to, to_left, tmp_args, tmp_num);
if (ret < 0)
break;
unconv_num += ret;
if (tmp_num == 1 && charset) {
tmp_args[1] = (XPointer) charset;
tmp_num = 2;
}
src++;
src_left--;
}
if (save_from == (XPointer) src)
return -1;
*from = (XPointer) src;
*from_left = src_left;
if (num_args > 0)
*((XlcCharSet *) args[0]) = charset;
return unconv_num;
}
#define DefineLocalBuf char local_buf[BUFSIZ]
#define AllocLocalBuf(length) (length > BUFSIZ ? (char*) Xmalloc(length) : local_buf)
#define FreeLocalBuf(ptr) if (ptr != local_buf) Xfree(ptr)
static int
stdc_cstowcs(
XlcConv conv,
XPointer *from,
int *from_left,
XPointer *to,
int *to_left,
XPointer *args,
int num_args)
{
XLCd lcd = ((State) conv->state)->lcd;
DefineLocalBuf;
XPointer buf, save_buf;
int length, left, ret;
left = length = *to_left * XLC_PUBLIC(lcd, mb_cur_max);
buf = save_buf = (XPointer) AllocLocalBuf(length);
if (buf == NULL)
return -1;
ret = cstombs(conv, from, from_left, &buf, &left, args, num_args);
if (ret < 0)
goto err;
buf = save_buf;
length -= left;
if (stdc_mbstowcs(conv, &buf, &length, to, to_left, args, num_args) < 0)
ret = -1;
err:
FreeLocalBuf(save_buf);
return ret;
}
static XlcConvMethodsRec stdc_mbstowcs_methods = {
close_converter,
stdc_mbstowcs,
NULL
};
static XlcConv
open_stdc_mbstowcs(
XLCd from_lcd,
const char *from_type,
XLCd to_lcd,
const char *to_type)
{
return create_conv(from_lcd, &stdc_mbstowcs_methods);
}
static XlcConvMethodsRec stdc_wcstombs_methods = {
close_converter,
stdc_wcstombs,
NULL
};
static XlcConv
open_stdc_wcstombs(
XLCd from_lcd,
const char *from_type,
XLCd to_lcd,
const char *to_type)
{
return create_conv(from_lcd, &stdc_wcstombs_methods);
}
static XlcConvMethodsRec stdc_wcstocs_methods = {
close_converter,
stdc_wcstocs,
NULL
};
static XlcConv
open_stdc_wcstocs(
XLCd from_lcd,
const char *from_type,
XLCd to_lcd,
const char *to_type)
{
return create_conv(from_lcd, &stdc_wcstocs_methods);
}
static XlcConvMethodsRec stdc_cstowcs_methods = {
close_converter,
stdc_cstowcs,
NULL
};
static XlcConv
open_stdc_cstowcs(
XLCd from_lcd,
const char *from_type,
XLCd to_lcd,
const char *to_type)
{
return create_conv(from_lcd, &stdc_cstowcs_methods);
}
#endif /* STDCVT */
XLCd
_XlcJisLoader(
const char *name)
{
XLCd lcd;
#ifdef STDCVT
XLCdGenericPart *gen;
#endif
lcd = _XlcCreateLC(name, _XlcGenericMethods);
if (lcd == NULL)
return lcd;
if (!XLC_PUBLIC_PART(lcd)->codeset ||
(_XlcCompareISOLatin1(XLC_PUBLIC_PART(lcd)->codeset, "JIS7"))) {
_XlcDestroyLC(lcd);
return (XLCd) NULL;
}
_XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNChar, open_mbtocs);
_XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNCharSet, open_mbstocs);
_XlcSetConverter(lcd, XlcNCharSet, lcd, XlcNMultiByte, open_cstombs);
#ifdef STDCVT
gen = XLC_GENERIC_PART(lcd);
if (gen->use_stdc_env == True) {
_XlcSetConverter(lcd,XlcNMultiByte,lcd,XlcNWideChar,open_stdc_mbstowcs);
_XlcSetConverter(lcd,XlcNWideChar,lcd,XlcNMultiByte,open_stdc_wcstombs);
}
if (gen->force_convert_to_mb == True) {
_XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNCharSet,open_stdc_wcstocs);
_XlcSetConverter(lcd, XlcNCharSet, lcd, XlcNWideChar,open_stdc_cstowcs);
} else {
#endif
_XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNCharSet, open_wcstocs);
_XlcSetConverter(lcd, XlcNCharSet, lcd, XlcNWideChar, open_cstowcs);
#ifdef STDCVT
}
#endif
_XlcAddUtf8Converters(lcd);
return lcd;
}
#else
typedef int dummy;
#endif /* X_LOCALE */
|