The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/libkern/iconv.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2000-2001, Boris Popov
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. All advertising materials mentioning features or use of this software
   14  *    must display the following acknowledgement:
   15  *    This product includes software developed by Boris Popov.
   16  * 4. Neither the name of the author nor the names of any co-contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  *
   32  * $FreeBSD: releng/5.1/sys/libkern/iconv.c 111119 2003-02-19 05:47:46Z imp $
   33  */
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/kernel.h>
   37 #include <sys/iconv.h>
   38 #include <sys/malloc.h>
   39 
   40 #include "iconv_converter_if.h"
   41 
   42 SYSCTL_DECL(_kern_iconv);
   43 
   44 SYSCTL_NODE(_kern, OID_AUTO, iconv, CTLFLAG_RW, NULL, "kernel iconv interface");
   45 
   46 MALLOC_DEFINE(M_ICONV, "ICONV", "ICONV structures");
   47 MALLOC_DEFINE(M_ICONVDATA, "ICONV data", "ICONV data");
   48 
   49 MODULE_VERSION(libiconv, 1);
   50 
   51 #ifdef notnow
   52 /*
   53  * iconv converter instance
   54  */
   55 struct iconv_converter {
   56         KOBJ_FIELDS;
   57         void *                  c_data;
   58 };
   59 #endif
   60 
   61 struct sysctl_oid *iconv_oid_hook = &sysctl___kern_iconv;
   62 
   63 /*
   64  * List of loaded converters
   65  */
   66 static TAILQ_HEAD(iconv_converter_list, iconv_converter_class)
   67     iconv_converters = TAILQ_HEAD_INITIALIZER(iconv_converters);
   68 
   69 /*
   70  * List of supported/loaded charsets pairs
   71  */
   72 static TAILQ_HEAD(, iconv_cspair)
   73     iconv_cslist = TAILQ_HEAD_INITIALIZER(iconv_cslist);
   74 static int iconv_csid = 1;
   75 
   76 static char iconv_unicode_string[] = "unicode"; /* save eight bytes when possible */
   77 
   78 static void iconv_unregister_cspair(struct iconv_cspair *csp);
   79 
   80 static int
   81 iconv_mod_unload(void)
   82 {
   83         struct iconv_cspair *csp;
   84 
   85         while ((csp = TAILQ_FIRST(&iconv_cslist)) != NULL) {
   86                 if (csp->cp_refcount)
   87                         return EBUSY;
   88                 iconv_unregister_cspair(csp);
   89         }
   90         return 0;
   91 }
   92 
   93 static int
   94 iconv_mod_handler(module_t mod, int type, void *data)
   95 {
   96         int error;
   97 
   98         switch (type) {
   99             case MOD_LOAD:
  100                 error = 0;
  101                 break;
  102             case MOD_UNLOAD:
  103                 error = iconv_mod_unload();
  104                 break;
  105             default:
  106                 error = EINVAL;
  107         }
  108         return error;
  109 }
  110 
  111 static moduledata_t iconv_mod = {
  112         "iconv", iconv_mod_handler, NULL
  113 };
  114 
  115 DECLARE_MODULE(iconv, iconv_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
  116 
  117 static int
  118 iconv_register_converter(struct iconv_converter_class *dcp)
  119 {
  120         kobj_class_compile((struct kobj_class*)dcp);
  121         dcp->refs++;
  122         TAILQ_INSERT_TAIL(&iconv_converters, dcp, cc_link);
  123         return 0;
  124 }
  125 
  126 static int
  127 iconv_unregister_converter(struct iconv_converter_class *dcp)
  128 {
  129         if (dcp->refs > 1) {
  130                 ICDEBUG("converter have %d referenses left\n", dcp->refs);
  131                 return EBUSY;
  132         }
  133         TAILQ_REMOVE(&iconv_converters, dcp, cc_link);
  134         kobj_class_free((struct kobj_class*)dcp);
  135         return 0;
  136 }
  137 
  138 static int
  139 iconv_lookupconv(const char *name, struct iconv_converter_class **dcpp)
  140 {
  141         struct iconv_converter_class *dcp;
  142 
  143         TAILQ_FOREACH(dcp, &iconv_converters, cc_link) {
  144                 if (name == NULL)
  145                         continue;
  146                 if (strcmp(name, ICONV_CONVERTER_NAME(dcp)) == 0) {
  147                         if (dcpp)
  148                                 *dcpp = dcp;
  149                         return 0;
  150                 }
  151         }
  152         return ENOENT;
  153 }
  154 
  155 static int
  156 iconv_lookupcs(const char *to, const char *from, struct iconv_cspair **cspp)
  157 {
  158         struct iconv_cspair *csp;
  159 
  160         TAILQ_FOREACH(csp, &iconv_cslist, cp_link) {
  161                 if (strcmp(csp->cp_to, to) == 0 &&
  162                     strcmp(csp->cp_from, from) == 0) {
  163                         if (cspp)
  164                                 *cspp = csp;
  165                         return 0;
  166                 }
  167         }
  168         return ENOENT;
  169 }
  170 
  171 static int
  172 iconv_register_cspair(const char *to, const char *from,
  173         struct iconv_converter_class *dcp, void *data,
  174         struct iconv_cspair **cspp)
  175 {
  176         struct iconv_cspair *csp;
  177         char *cp;
  178         int csize, ucsto, ucsfrom;
  179 
  180         if (iconv_lookupcs(to, from, NULL) == 0)
  181                 return EEXIST;
  182         csize = sizeof(*csp);
  183         ucsto = strcmp(to, iconv_unicode_string) == 0;
  184         if (!ucsto)
  185                 csize += strlen(to) + 1;
  186         ucsfrom = strcmp(from, iconv_unicode_string) == 0;
  187         if (!ucsfrom)
  188                 csize += strlen(from) + 1;
  189         csp = malloc(csize, M_ICONV, M_WAITOK);
  190         bzero(csp, csize);
  191         csp->cp_id = iconv_csid++;
  192         csp->cp_dcp = dcp;
  193         cp = (char*)(csp + 1);
  194         if (!ucsto) {
  195                 strcpy(cp, to);
  196                 csp->cp_to = cp;
  197                 cp += strlen(cp) + 1;
  198         } else
  199                 csp->cp_to = iconv_unicode_string;
  200         if (!ucsfrom) {
  201                 strcpy(cp, from);
  202                 csp->cp_from = cp;
  203         } else
  204                 csp->cp_from = iconv_unicode_string;
  205         csp->cp_data = data;
  206 
  207         TAILQ_INSERT_TAIL(&iconv_cslist, csp, cp_link);
  208         *cspp = csp;
  209         return 0;
  210 }
  211 
  212 static void
  213 iconv_unregister_cspair(struct iconv_cspair *csp)
  214 {
  215         TAILQ_REMOVE(&iconv_cslist, csp, cp_link);
  216         if (csp->cp_data)
  217                 free(csp->cp_data, M_ICONVDATA);
  218         free(csp, M_ICONV);
  219 }
  220 
  221 /*
  222  * Lookup and create an instance of converter.
  223  * Currently this layer didn't have associated 'instance' structure
  224  * to avoid unnesessary memory allocation.
  225  */
  226 int
  227 iconv_open(const char *to, const char *from, void **handle)
  228 {
  229         struct iconv_cspair *csp, *cspfrom, *cspto;
  230         struct iconv_converter_class *dcp;
  231         const char *cnvname;
  232         int error;
  233 
  234         /*
  235          * First, lookup fully qualified cspairs
  236          */
  237         error = iconv_lookupcs(to, from, &csp);
  238         if (error == 0)
  239                 return ICONV_CONVERTER_OPEN(csp->cp_dcp, csp, NULL, handle);
  240 
  241         /*
  242          * Well, nothing found. Now try to construct a composite conversion
  243          * ToDo: add a 'capability' field to converter
  244          */
  245         TAILQ_FOREACH(dcp, &iconv_converters, cc_link) {
  246                 cnvname = ICONV_CONVERTER_NAME(dcp);
  247                 if (cnvname == NULL)
  248                         continue;
  249                 error = iconv_lookupcs(cnvname, from, &cspfrom);
  250                 if (error)
  251                         continue;
  252                 error = iconv_lookupcs(to, cnvname, &cspto);
  253                 if (error)
  254                         continue;
  255                 /*
  256                  * Fine, we're found a pair which can be combined together
  257                  */
  258                 return ICONV_CONVERTER_OPEN(dcp, cspto, cspfrom, handle);
  259         }
  260         return ENOENT;
  261 }
  262 
  263 int
  264 iconv_close(void *handle)
  265 {
  266         return ICONV_CONVERTER_CLOSE(handle);
  267 }
  268 
  269 int
  270 iconv_conv(void *handle, const char **inbuf,
  271         size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
  272 {
  273         return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft);
  274 }
  275 
  276 /*
  277  * Give a list of loaded converters. Each name terminated with 0.
  278  * An empty string terminates the list.
  279  */
  280 static int
  281 iconv_sysctl_drvlist(SYSCTL_HANDLER_ARGS)
  282 {
  283         struct iconv_converter_class *dcp;
  284         const char *name;
  285         char spc;
  286         int error;
  287 
  288         error = 0;
  289 
  290         TAILQ_FOREACH(dcp, &iconv_converters, cc_link) {
  291                 name = ICONV_CONVERTER_NAME(dcp);
  292                 if (name == NULL)
  293                         continue;
  294                 error = SYSCTL_OUT(req, name, strlen(name) + 1);
  295                 if (error)
  296                         break;
  297         }
  298         if (error)
  299                 return error;
  300         spc = 0;
  301         error = SYSCTL_OUT(req, &spc, sizeof(spc));
  302         return error;
  303 }
  304 
  305 SYSCTL_PROC(_kern_iconv, OID_AUTO, drvlist, CTLFLAG_RD | CTLTYPE_OPAQUE,
  306             NULL, 0, iconv_sysctl_drvlist, "S,xlat", "registered converters");
  307 
  308 /*
  309  * List all available charset pairs.
  310  */
  311 static int
  312 iconv_sysctl_cslist(SYSCTL_HANDLER_ARGS)
  313 {
  314         struct iconv_cspair *csp;
  315         struct iconv_cspair_info csi;
  316         int error;
  317 
  318         error = 0;
  319         bzero(&csi, sizeof(csi));
  320         csi.cs_version = ICONV_CSPAIR_INFO_VER;
  321 
  322         TAILQ_FOREACH(csp, &iconv_cslist, cp_link) {
  323                 csi.cs_id = csp->cp_id;
  324                 csi.cs_refcount = csp->cp_refcount;
  325                 csi.cs_base = csp->cp_base ? csp->cp_base->cp_id : 0;
  326                 strcpy(csi.cs_to, csp->cp_to);
  327                 strcpy(csi.cs_from, csp->cp_from);
  328                 error = SYSCTL_OUT(req, &csi, sizeof(csi));
  329                 if (error)
  330                         break;
  331         }
  332         return error;
  333 }
  334 
  335 SYSCTL_PROC(_kern_iconv, OID_AUTO, cslist, CTLFLAG_RD | CTLTYPE_OPAQUE,
  336             NULL, 0, iconv_sysctl_cslist, "S,xlat", "registered charset pairs");
  337 
  338 /*
  339  * Add new charset pair
  340  */
  341 static int
  342 iconv_sysctl_add(SYSCTL_HANDLER_ARGS)
  343 {
  344         struct iconv_converter_class *dcp;
  345         struct iconv_cspair *csp;
  346         struct iconv_add_in din;
  347         struct iconv_add_out dout;
  348         int error;
  349 
  350         error = SYSCTL_IN(req, &din, sizeof(din));
  351         if (error)
  352                 return error;
  353         if (din.ia_version != ICONV_ADD_VER)
  354                 return EINVAL;
  355         if (din.ia_datalen > ICONV_CSMAXDATALEN)
  356                 return EINVAL;
  357         if (iconv_lookupconv(din.ia_converter, &dcp) != 0)
  358                 return EINVAL;
  359         error = iconv_register_cspair(din.ia_to, din.ia_from, dcp, NULL, &csp);
  360         if (error)
  361                 return error;
  362         if (din.ia_datalen) {
  363                 csp->cp_data = malloc(din.ia_datalen, M_ICONVDATA, M_WAITOK);
  364                 error = copyin(din.ia_data, csp->cp_data, din.ia_datalen);
  365                 if (error)
  366                         goto bad;
  367         }
  368         dout.ia_csid = csp->cp_id;
  369         error = SYSCTL_OUT(req, &dout, sizeof(dout));
  370         if (error)
  371                 goto bad;
  372         return 0;
  373 bad:
  374         iconv_unregister_cspair(csp);
  375         return error;
  376 }
  377 
  378 SYSCTL_PROC(_kern_iconv, OID_AUTO, add, CTLFLAG_RW | CTLTYPE_OPAQUE,
  379             NULL, 0, iconv_sysctl_add, "S,xlat", "register charset pair");
  380 
  381 /*
  382  * Default stubs for converters
  383  */
  384 int
  385 iconv_converter_initstub(struct iconv_converter_class *dp)
  386 {
  387         return 0;
  388 }
  389 
  390 int
  391 iconv_converter_donestub(struct iconv_converter_class *dp)
  392 {
  393         return 0;
  394 }
  395 
  396 int
  397 iconv_converter_handler(module_t mod, int type, void *data)
  398 {
  399         struct iconv_converter_class *dcp = data;
  400         int error;
  401 
  402         switch (type) {
  403             case MOD_LOAD:
  404                 error = iconv_register_converter(dcp);
  405                 if (error)
  406                         break;
  407                 error = ICONV_CONVERTER_INIT(dcp);
  408                 if (error)
  409                         iconv_unregister_converter(dcp);
  410                 break;
  411             case MOD_UNLOAD:
  412                 ICONV_CONVERTER_DONE(dcp);
  413                 error = iconv_unregister_converter(dcp);
  414                 break;
  415             default:
  416                 error = EINVAL;
  417         }
  418         return error;
  419 }
  420 
  421 /*
  422  * Common used functions
  423  */
  424 char *
  425 iconv_convstr(void *handle, char *dst, const char *src)
  426 {
  427         char *p = dst;
  428         size_t inlen, outlen;
  429         int error;
  430 
  431         if (handle == NULL) {
  432                 strcpy(dst, src);
  433                 return dst;
  434         }
  435         inlen = outlen = strlen(src);
  436         error = iconv_conv(handle, NULL, NULL, &p, &outlen);
  437         if (error)
  438                 return NULL;
  439         error = iconv_conv(handle, &src, &inlen, &p, &outlen);
  440         if (error)
  441                 return NULL;
  442         *p = 0;
  443         return dst;
  444 }
  445 
  446 void *
  447 iconv_convmem(void *handle, void *dst, const void *src, int size)
  448 {
  449         const char *s = src;
  450         char *d = dst;
  451         size_t inlen, outlen;
  452         int error;
  453 
  454         if (size == 0)
  455                 return dst;
  456         if (handle == NULL) {
  457                 memcpy(dst, src, size);
  458                 return dst;
  459         }
  460         inlen = outlen = size;
  461         error = iconv_conv(handle, NULL, NULL, &d, &outlen);
  462         if (error)
  463                 return NULL;
  464         error = iconv_conv(handle, &s, &inlen, &d, &outlen);
  465         if (error)
  466                 return NULL;
  467         return dst;
  468 }
  469 
  470 int
  471 iconv_lookupcp(char **cpp, const char *s)
  472 {
  473         if (cpp == NULL) {
  474                 ICDEBUG("warning a NULL list passed\n", ""); /* XXX ISO variadic                                                                macros cannot
  475                                                                 leave out the
  476                                                                 variadic args */
  477                 return ENOENT;
  478         }
  479         for (; *cpp; cpp++)
  480                 if (strcmp(*cpp, s) == 0)
  481                         return 0;
  482         return ENOENT;
  483 }

Cache object: 1c1379214525053594f0195e1335ba0d


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.