d14d7d31f2a70b1e0a9c933607d6627f5718980eis/*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * CDDL HEADER START
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * The contents of this file are subject to the terms of the
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * Common Development and Distribution License (the "License").
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * You may not use this file except in compliance with the License.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * or http://www.opensolaris.org/os/licensing.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * See the License for the specific language governing permissions
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * and limitations under the License.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * When distributing Covered Code, include this CDDL HEADER in each
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * If applicable, add the following below this CDDL HEADER, with the
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * fields enclosed by brackets "[]" replaced with your own identifying
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * information: Portions Copyright [yyyy] [name of copyright owner]
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * CDDL HEADER END
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis/*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * Use is subject to license terms.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis#pragma ident "%Z%%M% %I% %E% SMI"
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis/*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * Kernel iconv code conversion functions (PSARC/2007/173).
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * Man pages: kiconv_open(9F), kiconv(9F), kiconv_close(9F), and kiconvstr(9F).
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * Interface stability: Committed.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis#include <sys/types.h>
d14d7d31f2a70b1e0a9c933607d6627f5718980eis#include <sys/param.h>
d14d7d31f2a70b1e0a9c933607d6627f5718980eis#include <sys/sysmacros.h>
d14d7d31f2a70b1e0a9c933607d6627f5718980eis#include <sys/systm.h>
d14d7d31f2a70b1e0a9c933607d6627f5718980eis#include <sys/debug.h>
d14d7d31f2a70b1e0a9c933607d6627f5718980eis#include <sys/kmem.h>
d14d7d31f2a70b1e0a9c933607d6627f5718980eis#include <sys/sunddi.h>
d14d7d31f2a70b1e0a9c933607d6627f5718980eis#include <sys/ksynch.h>
d14d7d31f2a70b1e0a9c933607d6627f5718980eis#include <sys/modctl.h>
d14d7d31f2a70b1e0a9c933607d6627f5718980eis#include <sys/byteorder.h>
d14d7d31f2a70b1e0a9c933607d6627f5718980eis#include <sys/errno.h>
d14d7d31f2a70b1e0a9c933607d6627f5718980eis#include <sys/kiconv.h>
d14d7d31f2a70b1e0a9c933607d6627f5718980eis#include <sys/kiconv_latin1.h>
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis/*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * The following macros indicate ids to the correct code conversion mapping
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * data tables to use. The actual tables are coming from <sys/kiconv_latin1.h>.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis#define KICONV_TBLID_1252 (0x00)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis#define KICONV_TBLID_8859_1 (0x01)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis#define KICONV_TBLID_8859_15 (0x02)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis#define KICONV_TBLID_850 (0x03)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis#define KICONV_MAX_MAPPING_TBLID (0x03)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis/*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * The following tables are coming from u8_textprep.c. We use them to
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * check on validity of UTF-8 characters and their bytes.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eisextern const int8_t u8_number_of_bytes[];
d14d7d31f2a70b1e0a9c933607d6627f5718980eisextern const uint8_t u8_valid_min_2nd_byte[];
d14d7d31f2a70b1e0a9c933607d6627f5718980eisextern const uint8_t u8_valid_max_2nd_byte[];
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis/*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * The following four functions, open_to_1252(), open_to_88591(),
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * open_to_885915(), and open_to_850(), are kiconv_open functions from
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * UTF-8 to corresponding single byte codesets.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic void *
d14d7d31f2a70b1e0a9c933607d6627f5718980eisopen_to_1252()
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis kiconv_state_t s;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis s = (kiconv_state_t)kmem_alloc(sizeof (kiconv_state_data_t), KM_SLEEP);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis s->id = KICONV_TBLID_1252;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis s->bom_processed = 0;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((void *)s);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic void *
d14d7d31f2a70b1e0a9c933607d6627f5718980eisopen_to_88591()
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis kiconv_state_t s;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis s = (kiconv_state_t)kmem_alloc(sizeof (kiconv_state_data_t), KM_SLEEP);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis s->id = KICONV_TBLID_8859_1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis s->bom_processed = 0;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((void *)s);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic void *
d14d7d31f2a70b1e0a9c933607d6627f5718980eisopen_to_885915()
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis kiconv_state_t s;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis s = (kiconv_state_t)kmem_alloc(sizeof (kiconv_state_data_t), KM_SLEEP);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis s->id = KICONV_TBLID_8859_15;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis s->bom_processed = 0;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((void *)s);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic void *
d14d7d31f2a70b1e0a9c933607d6627f5718980eisopen_to_850()
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis kiconv_state_t s;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis s = (kiconv_state_t)kmem_alloc(sizeof (kiconv_state_data_t), KM_SLEEP);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis s->id = KICONV_TBLID_850;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis s->bom_processed = 0;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((void *)s);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis/*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * The following four functions, open_fr_1252(), open_fr_88591(),
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * open_fr_885915(), and open_fr_850(), are kiconv_open functions from
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * corresponding single byte codesets to UTF-8.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic void *
d14d7d31f2a70b1e0a9c933607d6627f5718980eisopen_fr_1252()
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((void *)KICONV_TBLID_1252);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic void *
d14d7d31f2a70b1e0a9c933607d6627f5718980eisopen_fr_88591()
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((void *)KICONV_TBLID_8859_1);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic void *
d14d7d31f2a70b1e0a9c933607d6627f5718980eisopen_fr_885915()
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((void *)KICONV_TBLID_8859_15);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic void *
d14d7d31f2a70b1e0a9c933607d6627f5718980eisopen_fr_850()
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((void *)KICONV_TBLID_850);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis/*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * The following close_to_sb() function is kiconv_close function for
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * the conversions from UTF-8 to single byte codesets. The close_fr_sb()
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * is kiconv_close function for the conversions from single byte codesets to
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * UTF-8.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic int
d14d7d31f2a70b1e0a9c933607d6627f5718980eisclose_to_sb(void *s)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (! s || s == (void *)-1)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (EBADF);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis kmem_free(s, sizeof (kiconv_state_data_t));
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (0);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic int
d14d7d31f2a70b1e0a9c933607d6627f5718980eisclose_fr_sb(void *s)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if ((ulong_t)s > KICONV_MAX_MAPPING_TBLID)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (EBADF);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (0);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis/*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * The following is the common kiconv function for conversions from UTF-8
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * to single byte codesets.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic size_t
d14d7d31f2a70b1e0a9c933607d6627f5718980eiskiconv_to_sb(void *kcd, char **inbuf, size_t *inbytesleft, char **outbuf,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t *outbytesleft, int *errno)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t id;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t ret_val;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis uchar_t *ib;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis uchar_t *oldib;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis uchar_t *ob;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis uchar_t *ibtail;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis uchar_t *obtail;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis uint32_t u8;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t i;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t l;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t h;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t init_h;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis int8_t sz;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis boolean_t second;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /* Check on the kiconv code conversion descriptor. */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (! kcd || kcd == (void *)-1) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *errno = EBADF;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((size_t)-1);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * Get the table id we are going to use for the code conversion
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * and let's double check on it.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis id = ((kiconv_state_t)kcd)->id;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (id > KICONV_MAX_MAPPING_TBLID) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *errno = EBADF;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((size_t)-1);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /* If this is a state reset request, process and return. */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (! inbuf || ! (*inbuf)) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ((kiconv_state_t)kcd)->bom_processed = 0;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((size_t)0);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret_val = 0;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ib = (uchar_t *)*inbuf;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ob = (uchar_t *)*outbuf;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ibtail = ib + *inbytesleft;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis obtail = ob + *outbytesleft;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * The inital high value for the binary search we will be using
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * shortly is a literal constant as of today but to be future proof,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * let's calculate it like the following at here.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis init_h = sizeof (to_sb_tbl[id]) / sizeof (kiconv_to_sb_tbl_comp_t) - 1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * If we haven't checked on the UTF-8 signature BOM character in
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * the beginning of the conversion data stream, we check it and if
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * find one, we skip it since we have no use for it.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (((kiconv_state_t)kcd)->bom_processed == 0 && (ibtail - ib) >= 3 &&
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *ib == 0xef && *(ib + 1) == 0xbb && *(ib + 2) == 0xbf)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ib += 3;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ((kiconv_state_t)kcd)->bom_processed = 1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis while (ib < ibtail) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis sz = u8_number_of_bytes[*ib];
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (sz <= 0) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *errno = EILSEQ;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret_val = (size_t)-1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis break;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * If there is no room to write at the output buffer,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * issue E2BIG error.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (ob >= obtail) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *errno = E2BIG;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret_val = (size_t)-1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis break;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * If it is a 7-bit ASCII character, we don't need to
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * process further and we just copy the character over.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * If not, we collect the character bytes up to four bytes,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * validate the bytes, and binary search for the corresponding
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * single byte codeset character byte. If we find it from
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * the mapping table, we put that into the output buffer;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * otherwise, we put a replacement character instead as
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * a non-identical conversion.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (sz == 1) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *ob++ = *ib++;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis continue;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * Issue EINVAL error if input buffer has an incomplete
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * character at the end of the buffer.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if ((ibtail - ib) < sz) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *errno = EINVAL;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret_val = (size_t)-1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis break;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * We collect UTF-8 character bytes and also check if
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * this is a valid UTF-8 character without any bogus bytes
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * based on the latest UTF-8 binary representation.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis oldib = ib;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis u8 = *ib++;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis second = B_TRUE;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis for (i = 1; i < sz; i++) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (second) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (*ib < u8_valid_min_2nd_byte[u8] ||
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *ib > u8_valid_max_2nd_byte[u8]) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *errno = EILSEQ;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret_val = (size_t)-1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ib = oldib;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis goto TO_SB_ILLEGAL_CHAR_ERR;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis second = B_FALSE;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis } else if (*ib < 0x80 || *ib > 0xbf) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *errno = EILSEQ;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret_val = (size_t)-1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ib = oldib;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis goto TO_SB_ILLEGAL_CHAR_ERR;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis u8 = (u8 << 8) | ((uint32_t)*ib);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ib++;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis i = l = 0;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis h = init_h;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis while (l <= h) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis i = (l + h) / 2;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (to_sb_tbl[id][i].u8 == u8)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis break;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis else if (to_sb_tbl[id][i].u8 < u8)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis l = i + 1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis else
d14d7d31f2a70b1e0a9c933607d6627f5718980eis h = i - 1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (to_sb_tbl[id][i].u8 == u8) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *ob++ = to_sb_tbl[id][i].sb;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis } else {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * If we don't find a character in the target
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * codeset, we insert an ASCII replacement character
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * at the output buffer and indicate such
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * "non-identical" conversion by increasing the
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * return value which is the non-identical conversion
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * counter if bigger than 0.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *ob++ = KICONV_ASCII_REPLACEMENT_CHAR;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret_val++;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eisTO_SB_ILLEGAL_CHAR_ERR:
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *inbuf = (char *)ib;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *inbytesleft = ibtail - ib;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *outbuf = (char *)ob;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *outbytesleft = obtail - ob;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (ret_val);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis/*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * The following is the common kiconv function from single byte codesets to
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * UTF-8.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic size_t
d14d7d31f2a70b1e0a9c933607d6627f5718980eiskiconv_fr_sb(void *kcd, char **inbuf, size_t *inbytesleft, char **outbuf,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t *outbytesleft, int *errno)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t ret_val;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis uchar_t *ib;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis uchar_t *ob;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis uchar_t *ibtail;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis uchar_t *obtail;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t i;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t k;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis int8_t sz;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /* Check on the kiconv code conversion descriptor validity. */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if ((ulong_t)kcd > KICONV_MAX_MAPPING_TBLID) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *errno = EBADF;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((size_t)-1);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * If this is a state reset request, there is nothing to do and so
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * we just return.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (! inbuf || ! (*inbuf))
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((size_t)0);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret_val = 0;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ib = (uchar_t *)*inbuf;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ob = (uchar_t *)*outbuf;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ibtail = ib + *inbytesleft;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis obtail = ob + *outbytesleft;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis while (ib < ibtail) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * If this is a 7-bit ASCII character, we just copy over and
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * that's all we need to do for this character.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (*ib < 0x80) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (ob >= obtail) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *errno = E2BIG;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret_val = (size_t)-1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis break;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *ob++ = *ib++;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis continue;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * Otherwise, we get the corresponding UTF-8 character bytes
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * from the mapping table and copy them over.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * We don't need to worry about if the UTF-8 character bytes
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * at the mapping tables are valid or not since they are good.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis k = *ib - 0x80;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis sz = u8_number_of_bytes[to_u8_tbl[(ulong_t)kcd][k].u8[0]];
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * If sz <= 0, that means we don't have any assigned character
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * at the code point, k + 0x80, of the single byte codeset
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * which is the fromcode. In other words, the input buffer
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * has an illegal character.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (sz <= 0) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *errno = EILSEQ;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret_val = (size_t)-1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis break;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if ((obtail - ob) < sz) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *errno = E2BIG;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret_val = (size_t)-1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis break;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis for (i = 0; i < sz; i++)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *ob++ = to_u8_tbl[(ulong_t)kcd][k].u8[i];
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ib++;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *inbuf = (char *)ib;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *inbytesleft = ibtail - ib;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *outbuf = (char *)ob;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *outbytesleft = obtail - ob;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (ret_val);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis/*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * The following is the common kiconvstr function from UTF-8 to single byte
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * codesets.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic size_t
d14d7d31f2a70b1e0a9c933607d6627f5718980eiskiconvstr_to_sb(size_t id, uchar_t *ib, size_t *inlen, uchar_t *ob,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t *outlen, int flag, int *errno)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t ret_val;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis uchar_t *oldib;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis uchar_t *ibtail;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis uchar_t *obtail;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis uint32_t u8;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t i;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t l;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t h;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t init_h;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis int8_t sz;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis boolean_t second;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis boolean_t do_not_ignore_null;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /* Let's make sure that the table id is within the valid boundary. */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (id > KICONV_MAX_MAPPING_TBLID) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *errno = EBADF;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((size_t)-1);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret_val = 0;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ibtail = ib + *inlen;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis obtail = ob + *outlen;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis do_not_ignore_null = ((flag & KICONV_IGNORE_NULL) == 0);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis init_h = sizeof (to_sb_tbl[id]) / sizeof (kiconv_to_sb_tbl_comp_t) - 1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /* Skip any UTF-8 signature BOM character in the beginning. */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if ((ibtail - ib) >= 3 && *ib == 0xef && *(ib + 1) == 0xbb &&
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *(ib + 2) == 0xbf)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ib += 3;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * Basically this is pretty much the same as kiconv_to_sb() except
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * that we are now accepting two flag values and doing the processing
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * accordingly.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis while (ib < ibtail) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis sz = u8_number_of_bytes[*ib];
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (sz <= 0) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (flag & KICONV_REPLACE_INVALID) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (ob >= obtail) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *errno = E2BIG;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret_val = (size_t)-1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis break;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ib++;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis goto STR_TO_SB_REPLACE_INVALID;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *errno = EILSEQ;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret_val = (size_t)-1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis break;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (*ib == '\0' && do_not_ignore_null)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis break;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (ob >= obtail) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *errno = E2BIG;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret_val = (size_t)-1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis break;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (sz == 1) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *ob++ = *ib++;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis continue;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if ((ibtail - ib) < sz) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (flag & KICONV_REPLACE_INVALID) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ib = ibtail;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis goto STR_TO_SB_REPLACE_INVALID;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *errno = EINVAL;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret_val = (size_t)-1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis break;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis oldib = ib;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis u8 = *ib++;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis second = B_TRUE;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis for (i = 1; i < sz; i++) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (second) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (*ib < u8_valid_min_2nd_byte[u8] ||
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *ib > u8_valid_max_2nd_byte[u8]) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (flag & KICONV_REPLACE_INVALID) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ib = oldib + sz;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis goto STR_TO_SB_REPLACE_INVALID;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *errno = EILSEQ;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret_val = (size_t)-1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ib = oldib;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis goto STR_TO_SB_ILLEGAL_CHAR_ERR;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis second = B_FALSE;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis } else if (*ib < 0x80 || *ib > 0xbf) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (flag & KICONV_REPLACE_INVALID) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ib = oldib + sz;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis goto STR_TO_SB_REPLACE_INVALID;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *errno = EILSEQ;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret_val = (size_t)-1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ib = oldib;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis goto STR_TO_SB_ILLEGAL_CHAR_ERR;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis u8 = (u8 << 8) | ((uint32_t)*ib);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ib++;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis i = l = 0;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis h = init_h;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis while (l <= h) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis i = (l + h) / 2;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (to_sb_tbl[id][i].u8 == u8)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis break;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis else if (to_sb_tbl[id][i].u8 < u8)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis l = i + 1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis else
d14d7d31f2a70b1e0a9c933607d6627f5718980eis h = i - 1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (to_sb_tbl[id][i].u8 == u8) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *ob++ = to_sb_tbl[id][i].sb;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis } else {
d14d7d31f2a70b1e0a9c933607d6627f5718980eisSTR_TO_SB_REPLACE_INVALID:
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *ob++ = KICONV_ASCII_REPLACEMENT_CHAR;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret_val++;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eisSTR_TO_SB_ILLEGAL_CHAR_ERR:
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *inlen = ibtail - ib;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *outlen = obtail - ob;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (ret_val);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis/*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * The following four functions are entry points recorded at the conv_list[]
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * defined at below.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic size_t
d14d7d31f2a70b1e0a9c933607d6627f5718980eiskiconvstr_to_1252(char *inarray, size_t *inlen, char *outarray,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t *outlen, int flag, int *errno)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (kiconvstr_to_sb(KICONV_TBLID_1252, (uchar_t *)inarray,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis inlen, (uchar_t *)outarray, outlen, flag, errno));
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic size_t
d14d7d31f2a70b1e0a9c933607d6627f5718980eiskiconvstr_to_1(char *inarray, size_t *inlen, char *outarray,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t *outlen, int flag, int *errno)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (kiconvstr_to_sb(KICONV_TBLID_8859_1, (uchar_t *)inarray,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis inlen, (uchar_t *)outarray, outlen, flag, errno));
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic size_t
d14d7d31f2a70b1e0a9c933607d6627f5718980eiskiconvstr_to_15(char *inarray, size_t *inlen, char *outarray,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t *outlen, int flag, int *errno)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (kiconvstr_to_sb(KICONV_TBLID_8859_15, (uchar_t *)inarray,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis inlen, (uchar_t *)outarray, outlen, flag, errno));
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic size_t
d14d7d31f2a70b1e0a9c933607d6627f5718980eiskiconvstr_to_850(char *inarray, size_t *inlen, char *outarray,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t *outlen, int flag, int *errno)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (kiconvstr_to_sb(KICONV_TBLID_850, (uchar_t *)inarray,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis inlen, (uchar_t *)outarray, outlen, flag, errno));
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis/*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * The following is the common kiconvstr function for conversions from
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * single byte codesets to UTF-8.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic size_t
d14d7d31f2a70b1e0a9c933607d6627f5718980eiskiconvstr_fr_sb(size_t id, uchar_t *ib, size_t *inlen, uchar_t *ob,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t *outlen, int flag, int *errno)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t ret_val;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis uchar_t *ibtail;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis uchar_t *obtail;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t i;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t k;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis int8_t sz;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis boolean_t do_not_ignore_null;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret_val = 0;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ibtail = ib + *inlen;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis obtail = ob + *outlen;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis do_not_ignore_null = ((flag & KICONV_IGNORE_NULL) == 0);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis while (ib < ibtail) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (*ib == '\0' && do_not_ignore_null)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis break;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (*ib < 0x80) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (ob >= obtail) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *errno = E2BIG;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret_val = (size_t)-1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis break;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *ob++ = *ib++;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis continue;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis k = *ib - 0x80;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis sz = u8_number_of_bytes[to_u8_tbl[id][k].u8[0]];
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (sz <= 0) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (flag & KICONV_REPLACE_INVALID) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if ((obtail - ob) < 3) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *errno = E2BIG;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret_val = (size_t)-1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis break;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /* Save KICONV_UTF8_REPLACEMENT_CHAR. */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *ob++ = 0xef;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *ob++ = 0xbf;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *ob++ = 0xbd;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret_val++;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ib++;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis continue;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *errno = EILSEQ;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret_val = (size_t)-1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis break;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if ((obtail - ob) < sz) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *errno = E2BIG;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret_val = (size_t)-1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis break;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis for (i = 0; i < sz; i++)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *ob++ = to_u8_tbl[id][k].u8[i];
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ib++;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *inlen = ibtail - ib;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *outlen = obtail - ob;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (ret_val);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis/*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * The following four functions are also entry points recorded at
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * the conv_list[] at below.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic size_t
d14d7d31f2a70b1e0a9c933607d6627f5718980eiskiconvstr_fr_1252(char *inarray, size_t *inlen, char *outarray,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t *outlen, int flag, int *errno)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (kiconvstr_fr_sb(KICONV_TBLID_1252, (uchar_t *)inarray,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis inlen, (uchar_t *)outarray, outlen, flag, errno));
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic size_t
d14d7d31f2a70b1e0a9c933607d6627f5718980eiskiconvstr_fr_1(char *inarray, size_t *inlen, char *outarray,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t *outlen, int flag, int *errno)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (kiconvstr_fr_sb(KICONV_TBLID_8859_1, (uchar_t *)inarray,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis inlen, (uchar_t *)outarray, outlen, flag, errno));
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic size_t
d14d7d31f2a70b1e0a9c933607d6627f5718980eiskiconvstr_fr_15(char *inarray, size_t *inlen, char *outarray,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t *outlen, int flag, int *errno)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (kiconvstr_fr_sb(KICONV_TBLID_8859_15, (uchar_t *)inarray,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis inlen, (uchar_t *)outarray, outlen, flag, errno));
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic size_t
d14d7d31f2a70b1e0a9c933607d6627f5718980eiskiconvstr_fr_850(char *inarray, size_t *inlen, char *outarray,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t *outlen, int flag, int *errno)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (kiconvstr_fr_sb(KICONV_TBLID_850, (uchar_t *)inarray,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis inlen, (uchar_t *)outarray, outlen, flag, errno));
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis/*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * The following static vector contains the normalized code names
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * and their corresponding code ids. They are somewhat arbitrarily ordered
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * based on marketing data available. A code id could repeat for aliases.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * The vector was generated by using a small utility program called
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * codeidlistgen.c that you can find from PSARC/2007/173/materials/util/.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * The code ids must be portable, i.e., if needed, you can always generate
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * the code_list[] again with different code ids. You'll also need to
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * update the conv_list[] at below.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis#define KICONV_MAX_CODEID_ENTRY 68
d14d7d31f2a70b1e0a9c933607d6627f5718980eis#define KICONV_MAX_CODEID 42
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic kiconv_code_list_t code_list[KICONV_MAX_CODEID_ENTRY] = {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "utf8", 0 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "cp1252", 1 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "1252", 1 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "iso88591", 2 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "iso885915", 3 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "cp850", 4 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "850", 4 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "eucjp", 5 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "eucjpms", 6 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "cp932", 7 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "932", 7 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "shiftjis", 8 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "pck", 8 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "sjis", 8 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "gb18030", 9 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "gbk", 10 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "cp936", 10 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "936", 10 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "euccn", 11 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "euckr", 12 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "unifiedhangul", 13 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "cp949", 13 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "949", 13 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "big5", 14 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "cp950", 14 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "950", 14 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "big5hkscs", 15 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "euctw", 16 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "cp950hkscs", 17 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "cp1250", 18 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "1250", 18 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "iso88592", 19 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "cp852", 20 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "852", 20 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "cp1251", 21 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "1251", 21 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "iso88595", 22 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "koi8r", 23 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "cp866", 24 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "866", 24 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "cp1253", 25 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "1253", 25 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "iso88597", 26 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "cp737", 27 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "737", 27 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "cp1254", 28 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "1254", 28 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "iso88599", 29 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "cp857", 30 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "857", 30 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "cp1256", 31 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "1256", 31 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "iso88596", 32 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "cp720", 33 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "720", 33 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "cp1255", 34 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "1255", 34 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "iso88598", 35 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "cp862", 36 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "862", 36 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "cp1257", 37 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "1257", 37 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "iso885913", 38 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "iso885910", 39 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "iso885911", 40 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "tis620", 40 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "iso88593", 41 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { "iso88594", 42 },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis};
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis/*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * The list of code conversions supported are grouped together per
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * module which will be loaded as needed.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis#define KICONV_MAX_CONVERSIONS 84
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic kiconv_conv_list_t conv_list[KICONV_MAX_CONVERSIONS] = {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /* Embedded code conversions: */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis 1, 0, KICONV_EMBEDDED,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis open_to_1252, kiconv_to_sb, close_to_sb, kiconvstr_to_1252
d14d7d31f2a70b1e0a9c933607d6627f5718980eis },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis 0, 1, KICONV_EMBEDDED,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis open_fr_1252, kiconv_fr_sb, close_fr_sb, kiconvstr_fr_1252
d14d7d31f2a70b1e0a9c933607d6627f5718980eis },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis 2, 0, KICONV_EMBEDDED,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis open_to_88591, kiconv_to_sb, close_to_sb, kiconvstr_to_1
d14d7d31f2a70b1e0a9c933607d6627f5718980eis },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis 0, 2, KICONV_EMBEDDED,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis open_fr_88591, kiconv_fr_sb, close_fr_sb, kiconvstr_fr_1
d14d7d31f2a70b1e0a9c933607d6627f5718980eis },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis 3, 0, KICONV_EMBEDDED,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis open_to_885915, kiconv_to_sb, close_to_sb, kiconvstr_to_15
d14d7d31f2a70b1e0a9c933607d6627f5718980eis },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis 0, 3, KICONV_EMBEDDED,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis open_fr_885915, kiconv_fr_sb, close_fr_sb, kiconvstr_fr_15
d14d7d31f2a70b1e0a9c933607d6627f5718980eis },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis 4, 0, KICONV_EMBEDDED,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis open_to_850, kiconv_to_sb, close_to_sb, kiconvstr_to_850
d14d7d31f2a70b1e0a9c933607d6627f5718980eis },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis 0, 4, KICONV_EMBEDDED,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis open_fr_850, kiconv_fr_sb, close_fr_sb, kiconvstr_fr_850
d14d7d31f2a70b1e0a9c933607d6627f5718980eis },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /* kiconv_ja module conversions: */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 5, KICONV_MODULE_ID_JA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 5, 0, KICONV_MODULE_ID_JA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 6, KICONV_MODULE_ID_JA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 6, 0, KICONV_MODULE_ID_JA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 7, KICONV_MODULE_ID_JA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 7, 0, KICONV_MODULE_ID_JA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 8, KICONV_MODULE_ID_JA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 8, 0, KICONV_MODULE_ID_JA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /* kiconv_sc module conversions: */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 9, KICONV_MODULE_ID_SC, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 9, 0, KICONV_MODULE_ID_SC, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 10, KICONV_MODULE_ID_SC, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 10, 0, KICONV_MODULE_ID_SC, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 11, KICONV_MODULE_ID_SC, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 11, 0, KICONV_MODULE_ID_SC, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /* kiconv_ko module conversions: */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 12, KICONV_MODULE_ID_KO, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 12, 0, KICONV_MODULE_ID_KO, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 13, KICONV_MODULE_ID_KO, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 13, 0, KICONV_MODULE_ID_KO, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /* kiconv_tc module conversions: */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 14, KICONV_MODULE_ID_TC, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 14, 0, KICONV_MODULE_ID_TC, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 15, KICONV_MODULE_ID_TC, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 15, 0, KICONV_MODULE_ID_TC, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 16, KICONV_MODULE_ID_TC, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 16, 0, KICONV_MODULE_ID_TC, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 17, KICONV_MODULE_ID_TC, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 17, 0, KICONV_MODULE_ID_TC, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /* kiconv_emea module conversions: */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 18, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 18, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 19, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 19, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 20, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 20, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 21, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 21, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 22, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 22, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 23, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 23, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 24, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 24, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 25, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 25, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 26, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 26, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 27, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 27, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 28, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 28, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 29, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 29, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 30, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 30, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 31, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 31, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 32, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 32, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 33, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 33, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 34, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 34, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 35, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 35, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 36, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 36, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 37, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 37, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 38, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 38, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 39, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 39, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 40, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 40, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 41, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 41, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 0, 42, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis { 42, 0, KICONV_MODULE_ID_EMEA, NULL, NULL, NULL, NULL },
d14d7d31f2a70b1e0a9c933607d6627f5718980eis};
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis/* The list of implemeted and supported modules. */
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic kiconv_mod_list_t module_list[KICONV_MAX_MODULE_ID + 1] = {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis "kiconv_embedded", 0,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis "kiconv_ja", 0,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis "kiconv_sc", 0,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis "kiconv_ko", 0,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis "kiconv_tc", 0,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis "kiconv_emea", 0,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis};
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis/*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * We use conv_list_lock to restrict data access of both conv_list[] and
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * module_list[] as they are tightly coupled critical sections that need to be
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * dealt together as a unit.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic kmutex_t conv_list_lock;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eisvoid
d14d7d31f2a70b1e0a9c933607d6627f5718980eiskiconv_init()
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis mutex_init(&conv_list_lock, NULL, MUTEX_DEFAULT, NULL);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis/*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * The following is used to check on whether a kiconv module is being
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * used or not at the _fini() of the module.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eissize_t
d14d7d31f2a70b1e0a9c933607d6627f5718980eiskiconv_module_ref_count(size_t mid)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis int count;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (mid <= 0 || mid > KICONV_MAX_MODULE_ID)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (0);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis mutex_enter(&conv_list_lock);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis count = module_list[mid].refcount;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis mutex_exit(&conv_list_lock);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (count);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis/*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * This function "normalizes" a given code name, n, by not including skippable
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * characters and folding uppercase letters to corresponding lowercase letters.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * We only fold 7-bit ASCII uppercase characters since the names should be in
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * Portable Character Set of 7-bit ASCII.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * By doing this, we will be able to maximize the code name matches.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic size_t
d14d7d31f2a70b1e0a9c933607d6627f5718980eisnormalize_codename(const char *n)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis char s[KICONV_MAX_CODENAME_LEN + 1];
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t i;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (n == NULL)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((size_t)-1);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis for (i = 0; *n; n++) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (KICONV_SKIPPABLE_CHAR(*n))
d14d7d31f2a70b1e0a9c933607d6627f5718980eis continue;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /* If unreasonably lengthy, we don't support such names. */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (i >= KICONV_MAX_CODENAME_LEN)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((size_t)-1);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis s[i++] = (*n >= 'A' && *n <= 'Z') ? *n - 'A' + 'a' : *n;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis s[i] = '\0';
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /* With the normalized name, find the corresponding codeset id. */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis for (i = 0; i < KICONV_MAX_CODEID_ENTRY; i++)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (strcmp(s, code_list[i].name) == 0)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (code_list[i].id);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * In future time, we will also have a few more lines of code at below
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * that will deal with other user-created modules' fromcodes and
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * tocodes including aliases in a different vector. For now, we don't
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * support that but only the known names to this project at this time.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((size_t)-1);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis/*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * This function called from mod_install() registers supplied code
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * conversions. At this point, it does not honor aliases and hence does not
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * use nowait data field from the kiconv module info data structure.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eisint
d14d7d31f2a70b1e0a9c933607d6627f5718980eiskiconv_register_module(kiconv_module_info_t *info)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t mid;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t fid;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t tid;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t i;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t j;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis kiconv_ops_t *op;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /* Validate the given kiconv module info. */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (info == NULL || info->module_name == NULL ||
d14d7d31f2a70b1e0a9c933607d6627f5718980eis info->kiconv_num_convs == 0 || info->kiconv_ops_tbl == NULL)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (EINVAL);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * Check if this is one of the known modules. At this point,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * we do not allow user-defined kiconv modules and that'd be for
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * a future project.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis for (mid = 1; mid <= KICONV_MAX_MODULE_ID; mid++)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (strcmp(module_list[mid].name, info->module_name) == 0)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis break;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (mid > KICONV_MAX_MODULE_ID)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (EINVAL);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /* Let's register the conversions supplied. */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis mutex_enter(&conv_list_lock);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * This is very unlikely situation but by any chance we don't want to
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * register a module that is already in.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (module_list[mid].refcount > 0) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis mutex_exit(&conv_list_lock);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (EAGAIN);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis for (i = 0; i < info->kiconv_num_convs; i++) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis op = &(info->kiconv_ops_tbl[i]);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis fid = normalize_codename(op->fromcode);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis tid = normalize_codename(op->tocode);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * If we find anything wrong in this particular conversion,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * we skip this one and continue to the next one. This include
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * a case where there is a conversion already being assigned
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * into the conv_list[] somehow, i.e., new one never kicks out
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * old one.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (op->kiconv_open == NULL || op->kiconv == NULL ||
d14d7d31f2a70b1e0a9c933607d6627f5718980eis op->kiconv_close == NULL || op->kiconvstr == NULL)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis continue;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis for (j = 0; j < KICONV_MAX_CONVERSIONS; j++) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (conv_list[j].mid == mid &&
d14d7d31f2a70b1e0a9c933607d6627f5718980eis conv_list[j].fid == fid &&
d14d7d31f2a70b1e0a9c933607d6627f5718980eis conv_list[j].tid == tid) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (conv_list[j].open == NULL) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis conv_list[j].open = op->kiconv_open;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis conv_list[j].kiconv = op->kiconv;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis conv_list[j].close = op->kiconv_close;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis conv_list[j].kiconvstr = op->kiconvstr;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis break;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis mutex_exit(&conv_list_lock);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (0);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis/*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * The following function called during mod_remove() will try to unregister,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * i.e., clear up conversion function pointers, from the conv_list[] if it
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * can. If there is any code conversions being used, then, the function will
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * just return EBUSY indicating that the module cannot be unloaded.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eisint
d14d7d31f2a70b1e0a9c933607d6627f5718980eiskiconv_unregister_module(kiconv_module_info_t *info)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t mid;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t i;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (info == NULL || info->module_name == NULL ||
d14d7d31f2a70b1e0a9c933607d6627f5718980eis info->kiconv_num_convs == 0 || info->kiconv_ops_tbl == NULL)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (EINVAL);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis for (mid = 1; mid <= KICONV_MAX_MODULE_ID; mid++)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (strcmp(module_list[mid].name, info->module_name) == 0)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis break;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (mid > KICONV_MAX_MODULE_ID)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (EINVAL);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis mutex_enter(&conv_list_lock);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * If any of the conversions are used, then, this module canont be
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * unloaded.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (module_list[mid].refcount > 0) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis mutex_exit(&conv_list_lock);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (EBUSY);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * Otherwise, we unregister all conversions from this module
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * and be ready for the unloading. At this point, we only care about
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * the conversions we know about with the module.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis for (i = 0; i < KICONV_MAX_CONVERSIONS; i++) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (conv_list[i].mid == mid) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis conv_list[i].open = NULL;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis conv_list[i].kiconv = NULL;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis conv_list[i].close = NULL;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis conv_list[i].kiconvstr = NULL;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis mutex_exit(&conv_list_lock);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (0);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis/*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * The following function check if asked code conversion is available
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * and if necessary, load the corresponding kiconv module that contains
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * the conversion (and others).
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eisstatic kiconv_t
d14d7d31f2a70b1e0a9c933607d6627f5718980eischeck_and_load_conversions(const char *tocode, const char *fromcode)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis kiconv_t kcd;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t tid;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t fid;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t mid;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t i;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /* Normalize the given names and find the corresponding code ids. */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis tid = normalize_codename(tocode);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (tid == (size_t)-1)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((kiconv_t)-1);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis fid = normalize_codename(fromcode);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (fid == (size_t)-1)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((kiconv_t)-1);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * Search the conversion.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * If the conversion isn't supported, just return -1.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * If the conversion is supported but there is no corresponding
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * module loaded, try to load it and if successful, return
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * a kiconv conversion descriptor memory block.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * We maintain a reference counter of uint_t for each module.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis mutex_enter(&conv_list_lock);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis for (i = 0; i < KICONV_MAX_CONVERSIONS; i++)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (conv_list[i].tid == tid && conv_list[i].fid == fid)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis break;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (i >= KICONV_MAX_CONVERSIONS) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis mutex_exit(&conv_list_lock);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((kiconv_t)-1);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis mid = conv_list[i].mid;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (conv_list[i].open == NULL) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis mutex_exit(&conv_list_lock);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (modload("kiconv", module_list[mid].name) < 0)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((kiconv_t)-1);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * Let's double check if something happened right after
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * the modload and/or if the module really has the conversion.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis mutex_enter(&conv_list_lock);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (conv_list[i].open == NULL) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis mutex_exit(&conv_list_lock);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((kiconv_t)-1);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * If we got the conversion, we will use the conversion function
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * in the module and so let's increase the module's refcounter
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * so that the module won't be kicked out. (To be more exact and
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * specific, the "refcount" is thus the reference counter of
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * the module functions being used.)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (module_list[mid].refcount < UINT_MAX)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis module_list[mid].refcount++;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis mutex_exit(&conv_list_lock);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis kcd = (kiconv_t)kmem_alloc(sizeof (kiconv_data_t), KM_SLEEP);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis kcd->handle = (void *)-1;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis kcd->id = i;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (kcd);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis/*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * The following are the four "Committed" interfaces.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eiskiconv_t
d14d7d31f2a70b1e0a9c933607d6627f5718980eiskiconv_open(const char *tocode, const char *fromcode)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis kiconv_t kcd;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t mid;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis kcd = check_and_load_conversions(tocode, fromcode);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (kcd == (kiconv_t)-1)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((kiconv_t)-1);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis kcd->handle = (conv_list[kcd->id].open)();
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (kcd->handle == (void *)-1) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * If the conversion couldn't be opened for some reason,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * then, we unallocate the kcd and, more importantly, before
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * that, we also decrease the module reference counter.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis mid = conv_list[kcd->id].mid;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis mutex_enter(&conv_list_lock);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (module_list[mid].refcount > 0)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis module_list[mid].refcount--;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis mutex_exit(&conv_list_lock);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis kmem_free((void *)kcd, sizeof (kiconv_data_t));
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((kiconv_t)-1);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (kcd);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eissize_t
d14d7d31f2a70b1e0a9c933607d6627f5718980eiskiconv(kiconv_t kcd, char **inbuf, size_t *inbytesleft,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis char **outbuf, size_t *outbytesleft, int *errno)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /* Do some minimum checking on the kiconv conversion descriptor. */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (! kcd || kcd == (kiconv_t)-1 || conv_list[kcd->id].kiconv == NULL) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *errno = EBADF;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((size_t)-1);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((conv_list[kcd->id].kiconv)(kcd->handle, inbuf, inbytesleft,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis outbuf, outbytesleft, errno));
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eisint
d14d7d31f2a70b1e0a9c933607d6627f5718980eiskiconv_close(kiconv_t kcd)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis int ret;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t mid;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (! kcd || kcd == (kiconv_t)-1 || conv_list[kcd->id].close == NULL)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (EBADF);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis mid = conv_list[kcd->id].mid;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret = (conv_list[kcd->id].close)(kcd->handle);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis kmem_free((void *)kcd, sizeof (kiconv_data_t));
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis mutex_enter(&conv_list_lock);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis /*
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * While we maintain reference conter for each module, once loaded,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * we don't modunload from kiconv functions even if the counter
d14d7d31f2a70b1e0a9c933607d6627f5718980eis * reaches back to zero.
d14d7d31f2a70b1e0a9c933607d6627f5718980eis */
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (module_list[mid].refcount > 0)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis module_list[mid].refcount--;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis mutex_exit(&conv_list_lock);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (ret);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eissize_t
d14d7d31f2a70b1e0a9c933607d6627f5718980eiskiconvstr(const char *tocode, const char *fromcode, char *inarray,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t *inlen, char *outarray, size_t *outlen, int flag, int *errno)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis{
d14d7d31f2a70b1e0a9c933607d6627f5718980eis kiconv_t kcd;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t ret;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis size_t mid;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis kcd = check_and_load_conversions(tocode, fromcode);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (kcd == (kiconv_t)-1 || conv_list[kcd->id].kiconvstr == NULL) {
d14d7d31f2a70b1e0a9c933607d6627f5718980eis *errno = EBADF;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return ((size_t)-1);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis }
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis mid = conv_list[kcd->id].mid;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis ret = (conv_list[kcd->id].kiconvstr)(inarray, inlen, outarray, outlen,
d14d7d31f2a70b1e0a9c933607d6627f5718980eis flag, errno);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis kmem_free((void *)kcd, sizeof (kiconv_data_t));
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis mutex_enter(&conv_list_lock);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis if (module_list[mid].refcount > 0)
d14d7d31f2a70b1e0a9c933607d6627f5718980eis module_list[mid].refcount--;
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis mutex_exit(&conv_list_lock);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis
d14d7d31f2a70b1e0a9c933607d6627f5718980eis return (ret);
d14d7d31f2a70b1e0a9c933607d6627f5718980eis}