summaryrefslogtreecommitdiffstats
path: root/sys/libkern
diff options
context:
space:
mode:
authorfjoe <fjoe@FreeBSD.org>2003-09-26 20:26:25 +0000
committerfjoe <fjoe@FreeBSD.org>2003-09-26 20:26:25 +0000
commit571ef024e3f3a472116a55a8489d77eb4f5f933e (patch)
tree5e4dbdee80eebe5477ad9c5637bb6b0ee47993d5 /sys/libkern
parent0c8bfb6d004a87cd501c13516a69b3ef59ed6c7c (diff)
downloadFreeBSD-src-571ef024e3f3a472116a55a8489d77eb4f5f933e.zip
FreeBSD-src-571ef024e3f3a472116a55a8489d77eb4f5f933e.tar.gz
- Support for multibyte charsets in LIBICONV.
- CD9660_ICONV, NTFS_ICONV and MSDOSFS_ICONV kernel options (with corresponding modules). - kiconv(3) for loadable charset conversion tables support. Submitted by: Ryuichiro Imura <imura@ryu16.org>
Diffstat (limited to 'sys/libkern')
-rw-r--r--sys/libkern/iconv.c55
-rw-r--r--sys/libkern/iconv_converter_if.m2
-rw-r--r--sys/libkern/iconv_xlat.c14
-rw-r--r--sys/libkern/iconv_xlat16.c242
4 files changed, 304 insertions, 9 deletions
diff --git a/sys/libkern/iconv.c b/sys/libkern/iconv.c
index ad08119..462a2cf 100644
--- a/sys/libkern/iconv.c
+++ b/sys/libkern/iconv.c
@@ -38,6 +38,8 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/iconv.h>
#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/syslog.h>
#include "iconv_converter_if.h"
@@ -48,7 +50,7 @@ SYSCTL_NODE(_kern, OID_AUTO, iconv, CTLFLAG_RW, NULL, "kernel iconv interface");
MALLOC_DEFINE(M_ICONV, "ICONV", "ICONV structures");
MALLOC_DEFINE(M_ICONVDATA, "ICONV data", "ICONV data");
-MODULE_VERSION(libiconv, 1);
+MODULE_VERSION(libiconv, 2);
#ifdef notnow
/*
@@ -272,7 +274,28 @@ int
iconv_conv(void *handle, const char **inbuf,
size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
{
- return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft);
+ return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft, 0, 0);
+}
+
+int
+iconv_conv_case(void *handle, const char **inbuf,
+ size_t *inbytesleft, char **outbuf, size_t *outbytesleft, int casetype)
+{
+ return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft, 0, casetype);
+}
+
+int
+iconv_convchr(void *handle, const char **inbuf,
+ size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
+{
+ return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft, 1, 0);
+}
+
+int
+iconv_convchr_case(void *handle, const char **inbuf,
+ size_t *inbytesleft, char **outbuf, size_t *outbytesleft, int casetype)
+{
+ return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft, 1, casetype);
}
/*
@@ -371,6 +394,7 @@ iconv_sysctl_add(SYSCTL_HANDLER_ARGS)
error = SYSCTL_OUT(req, &dout, sizeof(dout));
if (error)
goto bad;
+ ICDEBUG("%s => %s, %d bytes\n",din.ia_from, din.ia_to, din.ia_datalen);
return 0;
bad:
iconv_unregister_cspair(csp);
@@ -421,7 +445,7 @@ iconv_converter_handler(module_t mod, int type, void *data)
}
/*
- * Common used functions
+ * Common used functions (don't use with unicode)
*/
char *
iconv_convstr(void *handle, char *dst, const char *src)
@@ -434,7 +458,8 @@ iconv_convstr(void *handle, char *dst, const char *src)
strcpy(dst, src);
return dst;
}
- inlen = outlen = strlen(src);
+ inlen = strlen(src);
+ outlen = inlen * 3;
error = iconv_conv(handle, NULL, NULL, &p, &outlen);
if (error)
return NULL;
@@ -459,7 +484,8 @@ iconv_convmem(void *handle, void *dst, const void *src, int size)
memcpy(dst, src, size);
return dst;
}
- inlen = outlen = size;
+ inlen = size;
+ outlen = inlen * 3;
error = iconv_conv(handle, NULL, NULL, &d, &outlen);
if (error)
return NULL;
@@ -483,3 +509,22 @@ iconv_lookupcp(char **cpp, const char *s)
return 0;
return ENOENT;
}
+
+/*
+ * Return if fsname is in use of not
+ */
+int
+iconv_vfs_refcount(const char *fsname)
+{
+ struct vfsconf *vfsp;
+
+ for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) {
+ if (!strcmp(vfsp->vfc_name, fsname)) {
+ if (vfsp->vfc_refcount > 0)
+ return (EBUSY);
+ else
+ return (0);
+ }
+ }
+ return (0);
+}
diff --git a/sys/libkern/iconv_converter_if.m b/sys/libkern/iconv_converter_if.m
index 0b2901c..cc5054f 100644
--- a/sys/libkern/iconv_converter_if.m
+++ b/sys/libkern/iconv_converter_if.m
@@ -53,6 +53,8 @@ METHOD int conv {
size_t *inbytesleft;
char **outbuf;
size_t *outbytesleft;
+ int convchar;
+ int casetype;
};
STATICMETHOD int init {
diff --git a/sys/libkern/iconv_xlat.c b/sys/libkern/iconv_xlat.c
index 7532cb3..8ab4d6c 100644
--- a/sys/libkern/iconv_xlat.c
+++ b/sys/libkern/iconv_xlat.c
@@ -46,7 +46,7 @@ __FBSDID("$FreeBSD$");
*/
#ifdef MODULE_DEPEND
-MODULE_DEPEND(iconv_xlat, libiconv, 1, 1, 1);
+MODULE_DEPEND(iconv_xlat, libiconv, 2, 2, 2);
#endif
/*
@@ -84,7 +84,8 @@ iconv_xlat_close(void *data)
static int
iconv_xlat_conv(void *d2p, const char **inbuf,
- size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
+ size_t *inbytesleft, char **outbuf, size_t *outbytesleft,
+ int convchar, int casetype)
{
struct iconv_xlat *dp = (struct iconv_xlat*)d2p;
const char *src;
@@ -93,14 +94,19 @@ iconv_xlat_conv(void *d2p, const char **inbuf,
if (inbuf == NULL || *inbuf == NULL || outbuf == NULL || *outbuf == NULL)
return 0;
- r = n = min(*inbytesleft, *outbytesleft);
+ if (casetype != 0)
+ return -1;
+ if (convchar == 1)
+ r = n = 1;
+ else
+ r = n = min(*inbytesleft, *outbytesleft);
src = *inbuf;
dst = *outbuf;
while(r--)
*dst++ = dp->d_table[(u_char)*src++];
*inbuf += n;
*outbuf += n;
- *inbytesleft += n;
+ *inbytesleft -= n;
*outbytesleft -= n;
return 0;
}
diff --git a/sys/libkern/iconv_xlat16.c b/sys/libkern/iconv_xlat16.c
new file mode 100644
index 0000000..6793159
--- /dev/null
+++ b/sys/libkern/iconv_xlat16.c
@@ -0,0 +1,242 @@
+/*-
+ * Copyright (c) 2003, Ryuichiro Imura
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/iconv.h>
+
+#include "iconv_converter_if.h"
+
+/*
+ * "XLAT16" converter
+ */
+
+#ifdef MODULE_DEPEND
+MODULE_DEPEND(iconv_xlat16, libiconv, 2, 2, 2);
+#endif
+
+/*
+ * XLAT16 converter instance
+ */
+struct iconv_xlat16 {
+ KOBJ_FIELDS;
+ uint32_t * d_table[0x200];
+ struct iconv_cspair * d_csp;
+};
+
+static int
+iconv_xlat16_open(struct iconv_converter_class *dcp,
+ struct iconv_cspair *csp, struct iconv_cspair *cspf, void **dpp)
+{
+ struct iconv_xlat16 *dp;
+ uint32_t *headp, *idxp, dist = 0;
+ int i;
+
+ dp = (struct iconv_xlat16 *)kobj_create((struct kobj_class*)dcp, M_ICONV, M_WAITOK);
+ headp = idxp = (uint32_t *)csp->cp_data;
+ dist = 0x200;
+ for (i = 0 ; i < 0x200 ; i++) {
+ if (*idxp) {
+ dp->d_table[i] = headp + dist;
+ dist += 0x80;
+ } else {
+ dp->d_table[i] = NULL;
+ }
+ idxp++;
+ }
+ dp->d_csp = csp;
+ csp->cp_refcount++;
+ *dpp = (void*)dp;
+ return (0);
+}
+
+static int
+iconv_xlat16_close(void *data)
+{
+ struct iconv_xlat16 *dp = data;
+
+ dp->d_csp->cp_refcount--;
+ kobj_delete((struct kobj*)data, M_ICONV);
+ return (0);
+}
+
+static int
+iconv_xlat16_conv(void *d2p, const char **inbuf,
+ size_t *inbytesleft, char **outbuf, size_t *outbytesleft,
+ int convchar, int casetype)
+{
+ struct iconv_xlat16 *dp = (struct iconv_xlat16*)d2p;
+ const char *src;
+ char *dst;
+ int ret = 0;
+ size_t in, on, ir, or, inlen;
+ uint32_t code;
+ u_char u, l;
+ u_int16_t c1, c2;
+
+ if (inbuf == NULL || *inbuf == NULL || outbuf == NULL || *outbuf == NULL)
+ return (0);
+ ir = in = *inbytesleft;
+ or = on = *outbytesleft;
+ src = *inbuf;
+ dst = *outbuf;
+
+ while(ir > 0 && or > 0) {
+
+ inlen = 0;
+ code = '\0';
+
+ c1 = ir > 1 ? *(src+1) & 0xff : 0;
+ c2 = *src & 0xff;
+
+ c1 = c2 & 0x80 ? c1 | 0x100 : c1;
+ c2 = c2 & 0x80 ? c2 & 0x7f : c2;
+
+ if (ir > 1 && dp->d_table[c1]) {
+ /*
+ * inbuf char is a double byte char
+ */
+ code = dp->d_table[c1][c2];
+ if (code)
+ inlen = 2;
+ }
+
+ if (inlen == 0) {
+ c1 &= 0xff00;
+ if (!dp->d_table[c1]) {
+ ret = -1;
+ break;
+ }
+ /*
+ * inbuf char is a single byte char
+ */
+ inlen = 1;
+ code = dp->d_table[c1][c2];
+ if (!code) {
+ ret = -1;
+ break;
+ }
+ }
+
+ if ((inlen == 1) && (code & XLAT16_ACCEPT_NULL_IN)) {
+ /*
+ * XLAT16_ACCEPT_NULL_IN requires inbuf has 2byte
+ */
+ ret = -1;
+ break;
+ }
+
+ /*
+ * now start translation
+ */
+ u = (u_char)(code >> 8);
+ l = (u_char)code;
+
+#ifdef XLAT16_ACCEPT_3BYTE_CHR
+ if (code & XLAT16_IS_3BYTE_CHR) {
+ if (or < 3) {
+ ret = -1;
+ break;
+ }
+ *dst++ = u;
+ *dst++ = l;
+ *dst++ = (u_char)(code >> 16);
+ or -= 3;
+ } else
+#endif
+ if (u || code & XLAT16_ACCEPT_NULL_OUT) {
+ if (or < 2) {
+ ret = -1;
+ break;
+ }
+ *dst++ = u;
+ *dst++ = l;
+ or -= 2;
+ } else {
+ if ((casetype == KICONV_LOWER && code & XLAT16_HAS_LOWER_CASE) ||
+ (casetype == KICONV_UPPER && code & XLAT16_HAS_UPPER_CASE))
+ *dst++ = (u_char)(code >> 16);
+ else if ((casetype == KICONV_FROM_LOWER && code & XLAT16_HAS_FROM_LOWER_CASE) ||
+ (casetype == KICONV_FROM_UPPER && code & XLAT16_HAS_FROM_UPPER_CASE))
+ *dst++ = dp->d_table[0][(u_char)(code >> 16)];
+ else
+ *dst++ = l;
+ or--;
+ }
+
+ if (inlen == 2) {
+ /*
+ * there is a case that inbuf char is a single
+ * byte char while inlen == 2
+ */
+ if ((u_char)*(src+1) == 0 &&
+ (code & XLAT16_ACCEPT_NULL_IN) == 0 ) {
+ src++;
+ ir--;
+ } else {
+ src += 2;
+ ir -= 2;
+ }
+ } else {
+ src++;
+ ir--;
+ }
+
+ if (convchar == 1)
+ break;
+ }
+
+ *inbuf += in - ir;
+ *outbuf += on - or;
+ *inbytesleft -= in - ir;
+ *outbytesleft -= on - or;
+ return (ret);
+}
+
+static const char *
+iconv_xlat16_name(struct iconv_converter_class *dcp)
+{
+ return ("xlat16");
+}
+
+static kobj_method_t iconv_xlat16_methods[] = {
+ KOBJMETHOD(iconv_converter_open, iconv_xlat16_open),
+ KOBJMETHOD(iconv_converter_close, iconv_xlat16_close),
+ KOBJMETHOD(iconv_converter_conv, iconv_xlat16_conv),
+#if 0
+ KOBJMETHOD(iconv_converter_init, iconv_xlat16_init),
+ KOBJMETHOD(iconv_converter_done, iconv_xlat16_done),
+#endif
+ KOBJMETHOD(iconv_converter_name, iconv_xlat16_name),
+ {0, 0}
+};
+
+KICONV_CONVERTER(xlat16, sizeof(struct iconv_xlat16));
OpenPOWER on IntegriCloud