<p>Jeff, shouldn&#39;t this be part of eglib as a build time option?</p>
<div class="gmail_quote">On Apr 19, 2011 10:06 PM, &quot;Jeffrey Stedfast (<a href="mailto:fejj@gnome.org">fejj@gnome.org</a>)&quot; &lt;<a href="mailto:mono-patches@lists.ximian.com">mono-patches@lists.ximian.com</a>&gt; wrote:<br type="attribution">
&gt; <br>&gt;    Branch: refs/heads/master<br>&gt;      Home: <a href="https://github.com/mono/moon">https://github.com/mono/moon</a><br>&gt; <br>&gt;    Commit: caef081dc43c17327c37932f65264deec19d8022<br>&gt;    Author: Jeffrey Stedfast &lt;<a href="mailto:fejj@gnome.org">fejj@gnome.org</a>&gt;<br>
&gt;      Date: 04/19/2011 21:05:59<br>&gt;       URL: <a href="https://github.com/mono/moon/commit/caef081dc43c17327c37932f65264deec19d8022">https://github.com/mono/moon/commit/caef081dc43c17327c37932f65264deec19d8022</a><br>
&gt; <br>&gt; Implemented an iconv-like API for unicode conversion<br>&gt; <br>&gt; Changed paths:<br>&gt;  M src/Makefile.am<br>&gt; Added paths:<br>&gt;  A src/miconv.cpp<br>&gt;  A src/miconv.h<br>&gt; <br>&gt; Modified: src/Makefile.am<br>
&gt; ===================================================================<br>&gt; --- a/src/Makefile.am<br>&gt; +++ b/src/Makefile.am<br>&gt; @@ -78,6 +78,7 @@ libmoon_include_headers =         \<br>&gt;          medialog.h                \<br>&gt;          mediaplayer.h                \<br>
&gt;          messaging.h                \<br>&gt; +        miconv.h                \<br>&gt;          moon-curves.h                \<br>&gt;          moonlightconfiguration.h\<br>&gt;          moon-path.h                \<br>&gt; @@ -234,6 +235,7 @@ dist_libmoon_la_SOURCES =                 \<br>&gt;          medialog.cpp                \<br>&gt;          mediaplayer.cpp                \<br>
&gt;          messaging.cpp                \<br>&gt; +        miconv.cpp                \<br>&gt;          moon-curves.c                \<br>&gt;          moonlightconfiguration.cpp        \<br>&gt;          moon-path.c                \<br>&gt; <br>&gt; Added: src/miconv.cpp<br>&gt; ===================================================================<br>
&gt; --- /dev/null<br>&gt; +++ b/src/miconv.cpp<br>&gt; @@ -0,0 +1,344 @@<br>&gt; +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */<br>&gt; +/*<br>&gt; + * miconv.cpp: <br>&gt; + *<br>&gt; + * Contact:<br>
&gt; + *   Moonlight List (<a href="mailto:moonlight-list@lists.ximian.com">moonlight-list@lists.ximian.com</a>)<br>&gt; + *<br>&gt; + * Copyright 2011 Novell, Inc. (<a href="http://www.novell.com">http://www.novell.com</a>)<br>
&gt; + *<br>&gt; + * See the LICENSE file included with the distribution for details.<br>&gt; + */<br>&gt; +<br>&gt; +#include &lt;config.h&gt;<br>&gt; +<br>&gt; +#include &lt;glib.h&gt;<br>&gt; +#include &lt;string.h&gt;<br>
&gt; +#include &lt;errno.h&gt;<br>&gt; +<br>&gt; +#include &quot;miconv.h&quot;<br>&gt; +<br>&gt; +namespace Moonlight {<br>&gt; +<br>&gt; +enum Endian {<br>&gt; +        LittleEndian,<br>&gt; +        BigEndian<br>&gt; +};<br>&gt; +<br>
&gt; +typedef int (* Decoder) (Endian endian, char **inbytes, size_t *inbytesleft, gunichar *outchar);<br>&gt; +typedef int (* Encoder) (gunichar c, char **outbytes, size_t *outbytesleft);<br>&gt; +<br>&gt; +static int decode_utf32 (Endian endian, char **inbytes, size_t *inbytesleft, gunichar *outchar);<br>
&gt; +//static int encode_utf32 (gunichar c, char **outbytes, size_t *outbytesleft);<br>&gt; +<br>&gt; +static int decode_utf16 (Endian endian, char **inbytes, size_t *inbytesleft, gunichar *outchar);<br>&gt; +//static int encode_utf16 (gunichar c, char **outbytes, size_t *outbytesleft);<br>
&gt; +<br>&gt; +static int decode_utf8 (Endian endian, char **inbytes, size_t *inbytesleft, gunichar *outchar);<br>&gt; +static int encode_utf8 (gunichar c, char **outbytes, size_t *outbytesleft);<br>&gt; +<br>&gt; +static struct {<br>
&gt; +        const char *name;<br>&gt; +        Decoder decoder;<br>&gt; +        Encoder encoder;<br>&gt; +        Endian endian;<br>&gt; +} charsets[] = {<br>&gt; +        { &quot;UTF-32BE&quot;, decode_utf32, NULL,         BigEndian    },<br>&gt; +        { &quot;UTF-32LE&quot;, decode_utf32, NULL,         LittleEndian },<br>
&gt; +        { &quot;UTF-16BE&quot;, decode_utf16, NULL,         BigEndian    },<br>&gt; +        { &quot;UTF-16LE&quot;, decode_utf16, NULL,         LittleEndian },<br>&gt; +        { &quot;UTF-8&quot;,    decode_utf8,  encode_utf8,  LittleEndian },<br>
&gt; +};<br>&gt; +<br>&gt; +struct _miconv_t {<br>&gt; +        Decoder decode;<br>&gt; +        Encoder encode;<br>&gt; +        Endian endian;<br>&gt; +        gunichar c;<br>&gt; +};<br>&gt; +<br>&gt; +<br>&gt; +miconv_t<br>&gt; +miconv_open (const char *to, const char *from)<br>
&gt; +{<br>&gt; +        Decoder decoder = NULL;<br>&gt; +        Encoder encoder = NULL;<br>&gt; +        Endian endian;<br>&gt; +        miconv_t cd;<br>&gt; +        guint i;<br>&gt; +        <br>&gt; +        if (!to || !from)<br>&gt; +                return (miconv_t) -1;<br>&gt; +        <br>
&gt; +        for (i = 0; i &lt; G_N_ELEMENTS (charsets); i++) {<br>&gt; +                if (!strcmp (charsets[i].name, from)) {<br>&gt; +                        decoder = charsets[i].decoder;<br>&gt; +                        endian = charsets[i].endian;<br>&gt; +                }<br>&gt; +                <br>
&gt; +                if (!strcmp (charsets[i].name, to))<br>&gt; +                        encoder = charsets[i].encoder;<br>&gt; +        }<br>&gt; +        <br>&gt; +        if (encoder == NULL || decoder == NULL)<br>&gt; +                return (miconv_t) -1;<br>&gt; +        <br>&gt; +        cd = (miconv_t) g_malloc (sizeof (*cd));<br>
&gt; +        cd-&gt;decode = decoder;<br>&gt; +        cd-&gt;encode = encoder;<br>&gt; +        cd-&gt;endian = endian;<br>&gt; +        cd-&gt;c = -1;<br>&gt; +        <br>&gt; +        return cd;<br>&gt; +}<br>&gt; +<br>&gt; +int<br>&gt; +miconv_close (miconv_t cd)<br>
&gt; +{<br>&gt; +        g_free (cd);<br>&gt; +        return 0;<br>&gt; +}<br>&gt; +<br>&gt; +int<br>&gt; +miconv (miconv_t cd, char **inbytes, size_t *inbytesleft,<br>&gt; +        char **outbytes, size_t *outbytesleft)<br>&gt; +{<br>&gt; +        size_t inleft, outleft;<br>
&gt; +        char *inptr, *outptr;<br>&gt; +        gunichar c;<br>&gt; +        int rc = 0;<br>&gt; +        <br>&gt; +        if (outbytes == NULL || outbytesleft == NULL) {<br>&gt; +                /* reset converter */<br>&gt; +                cd-&gt;c = -1;<br>&gt; +                return 0;<br>
&gt; +        }<br>&gt; +        <br>&gt; +        inleft = inbytesleft ? *inbytesleft : 0;<br>&gt; +        inptr = inbytes ? *inbytes : NULL;<br>&gt; +        outleft = *outbytesleft;<br>&gt; +        outptr = *outbytes;<br>&gt; +        c = cd-&gt;c;<br>&gt; +        <br>&gt; +        while (inleft &gt;= 0 &amp;&amp; outleft &gt; 0) {<br>
&gt; +                if (c == (gunichar) -1 &amp;&amp; cd-&gt;decode (cd-&gt;endian, &amp;inptr, &amp;inleft, &amp;c) == -1) {<br>&gt; +                        rc = -1;<br>&gt; +                        break;<br>&gt; +                }<br>&gt; +                <br>&gt; +                if (cd-&gt;encode (c, &amp;outptr, &amp;outleft) == -1) {<br>
&gt; +                        rc = -1;<br>&gt; +                        break;<br>&gt; +                }<br>&gt; +                <br>&gt; +                c = -1;<br>&gt; +        }<br>&gt; +        <br>&gt; +        if (inbytesleft)<br>&gt; +                *inbytesleft = inleft;<br>&gt; +        <br>&gt; +        if (inbytes)<br>&gt; +                *inbytes = inptr;<br>
&gt; +        <br>&gt; +        *outbytesleft = outleft;<br>&gt; +        *outbytes = outptr;<br>&gt; +        cd-&gt;c = c;<br>&gt; +        <br>&gt; +        return rc;<br>&gt; +}<br>&gt; +<br>&gt; +<br>&gt; +static int<br>&gt; +decode_utf32 (Endian endian, char **inbytes, size_t *inbytesleft, gunichar *outchar)<br>
&gt; +{<br>&gt; +        gunichar *inptr = (gunichar *) *inbytes;<br>&gt; +        size_t inleft = *inbytesleft;<br>&gt; +        gunichar c;<br>&gt; +        <br>&gt; +        if (inleft &lt; 4) {<br>&gt; +                errno = EINVAL;<br>&gt; +                return -1;<br>&gt; +        }<br>
&gt; +        <br>&gt; +        if (endian == BigEndian)<br>&gt; +                c = GUINT32_FROM_BE (*inptr);<br>&gt; +        else<br>&gt; +                c = GUINT32_FROM_LE (*inptr);<br>&gt; +        <br>&gt; +        inleft -= 4;<br>&gt; +        inptr++;<br>&gt; +        <br>&gt; +        if (c &gt;= 2147483648UL) {<br>
&gt; +                errno = EILSEQ;<br>&gt; +                return -1;<br>&gt; +        }<br>&gt; +        <br>&gt; +        *inbytes = (char *) inptr;<br>&gt; +        *inbytesleft = inleft;<br>&gt; +        *outchar = c;<br>&gt; +        <br>&gt; +        return 0;<br>&gt; +}<br>&gt; +<br>&gt; +//static int encode_utf32 (gunichar c, char **outbytes, size_t *outbytesleft);<br>
&gt; +<br>&gt; +static int<br>&gt; +decode_utf16 (Endian endian, char **inbytes, size_t *inbytesleft, gunichar *outchar)<br>&gt; +{<br>&gt; +        gunichar2 *inptr = (gunichar2 *) *inbytes;<br>&gt; +        size_t inleft = *inbytesleft;<br>
&gt; +        gunichar2 c;<br>&gt; +        gunichar u;<br>&gt; +        <br>&gt; +        if (inleft &lt; 2) {<br>&gt; +                errno = EINVAL;<br>&gt; +                return -1;<br>&gt; +        }<br>&gt; +        <br>&gt; +        if (endian == BigEndian)<br>&gt; +                u = GUINT16_FROM_BE (*inptr);<br>
&gt; +        else<br>&gt; +                u = GUINT16_FROM_LE (*inptr);<br>&gt; +        <br>&gt; +        inleft -= 2;<br>&gt; +        inptr++;<br>&gt; +        <br>&gt; +        if (u &gt;= 0xdc00 &amp;&amp; u &lt;= 0xdfff) {<br>&gt; +                errno = EILSEQ;<br>&gt; +                return -1;<br>
&gt; +        } else if (u &gt;= 0xd800 &amp;&amp; u &lt;= 0xdbff) {<br>&gt; +                if (inleft &lt; 2) {<br>&gt; +                        errno = EINVAL;<br>&gt; +                        return -1;<br>&gt; +                }<br>&gt; +                <br>&gt; +                if (endian == BigEndian)<br>&gt; +                        c = GUINT16_FROM_BE (*inptr);<br>
&gt; +                else<br>&gt; +                        c = GUINT16_FROM_LE (*inptr);<br>&gt; +                <br>&gt; +                inleft -= 2;<br>&gt; +                inptr++;<br>&gt; +                <br>&gt; +                if (c &lt; 0xdc00 || c &gt; 0xdfff) {<br>&gt; +                        errno = EILSEQ;<br>&gt; +                        return -1;<br>
&gt; +                }<br>&gt; +                <br>&gt; +                u = ((u - 0xd800) &lt;&lt; 10) + (c - 0xdc00) + 0x0010000UL;<br>&gt; +        }<br>&gt; +        <br>&gt; +        *inbytes = (char *) inptr;<br>&gt; +        *inbytesleft = inleft;<br>&gt; +        *outchar = u;<br>&gt; +        <br>
&gt; +        return 0;<br>&gt; +}<br>&gt; +<br>&gt; +//static int encode_utf16 (gunichar c, char **outbytes, size_t *outbytesleft);<br>&gt; +<br>&gt; +static int<br>&gt; +decode_utf8 (Endian endian, char **inbytes, size_t *inbytesleft, gunichar *outchar)<br>
&gt; +{<br>&gt; +        size_t inleft = *inbytesleft;<br>&gt; +        char *inptr = *inbytes;<br>&gt; +        size_t i, len = 0;<br>&gt; +        unsigned char c;<br>&gt; +        gunichar u;<br>&gt; +        <br>&gt; +        c = *inptr++;<br>&gt; +        <br>&gt; +        if (c &lt; 0x80) {<br>
&gt; +                /* simple ascii case */<br>&gt; +                len = 1;<br>&gt; +        } else if ((c &amp; 0xe0) == 0xc0) {<br>&gt; +                c &amp;= 0x1f;<br>&gt; +                len = 2;<br>&gt; +        } else if ((c &amp; 0xf0) == 0xe0) {<br>&gt; +                c &amp;= 0x0f;<br>
&gt; +                len = 3;<br>&gt; +        } else if ((c &amp; 0xf8) == 0xf0) {<br>&gt; +                c &amp;= 0x07;<br>&gt; +                len = 4;<br>&gt; +        } else if ((c &amp; 0xfc) == 0xf8) {<br>&gt; +                c &amp;= 0x03;<br>&gt; +                len = 5;<br>&gt; +        } else if ((c &amp; 0xfe) == 0xfc) {<br>
&gt; +                c &amp;= 0x01;<br>&gt; +                len = 6;<br>&gt; +        } else {<br>&gt; +                errno = EILSEQ;<br>&gt; +                return -1;<br>&gt; +        }<br>&gt; +        <br>&gt; +        if (len &gt; inleft) {<br>&gt; +                errno = EINVAL;<br>&gt; +                return -1;<br>&gt; +        }<br>
&gt; +        <br>&gt; +        u = c;<br>&gt; +        for (i = 1; i &lt; len; i++) {<br>&gt; +                u &lt;&lt;= 6 | ((*inptr) &amp; 0x3f);<br>&gt; +                inptr++;<br>&gt; +        }<br>&gt; +        <br>&gt; +        *inbytesleft = inleft - len;<br>&gt; +        *inbytes = inptr;<br>
&gt; +        *outchar = u;<br>&gt; +        <br>&gt; +        return 0;<br>&gt; +}<br>&gt; +<br>&gt; +static int<br>&gt; +encode_utf8 (gunichar c, char **outbytes, size_t *outbytesleft)<br>&gt; +{<br>&gt; +        size_t outleft = *outbytesleft;<br>
&gt; +        char *outptr = *outbytes;<br>&gt; +        size_t len, i;<br>&gt; +        char base;<br>&gt; +        <br>&gt; +        if (c &lt; 128UL) {<br>&gt; +                base = 0;<br>&gt; +                len = 1;<br>&gt; +        } else if (c &lt; 2048UL) {<br>&gt; +                base = 192;<br>
&gt; +                len = 2;<br>&gt; +        } else if (c &lt; 65536UL) {<br>&gt; +                base = 224;<br>&gt; +                len = 3;<br>&gt; +        } else if (c &lt; 2097152UL) {<br>&gt; +                base = 240;<br>&gt; +                len = 4;<br>&gt; +        } else if (c &lt; 67108864UL) {<br>
&gt; +                base = 248;        <br>&gt; +                len = 5;<br>&gt; +        } else if (c &lt; 2147483648UL) {<br>&gt; +                base = 252;<br>&gt; +                len = 6;<br>&gt; +        } else {<br>&gt; +                errno = EINVAL;<br>&gt; +                return -1;<br>&gt; +        }<br>&gt; +        <br>
&gt; +        if (outleft &lt; len) {<br>&gt; +                errno = E2BIG;<br>&gt; +                return -1;<br>&gt; +        }<br>&gt; +        <br>&gt; +        for (i = len - 1; i &gt; 0; i--) {<br>&gt; +                /* mask off 6 bits worth and add 128 */<br>&gt; +                outptr[i] = 128 + (c &amp; 0x3f);<br>
&gt; +                c &gt;&gt;= 6;<br>&gt; +        }<br>&gt; +        <br>&gt; +        /* first character has a different base */<br>&gt; +        outptr[0] = base + (c &amp; 0x3f);<br>&gt; +        <br>&gt; +        *outbytesleft = outleft - len;<br>&gt; +        *outbytes = outptr + len;<br>
&gt; +        <br>&gt; +        return 0;<br>&gt; +}<br>&gt; +<br>&gt; +};<br>&gt; +<br>&gt; <br>&gt; Added: src/miconv.h<br>&gt; ===================================================================<br>&gt; --- /dev/null<br>&gt; +++ b/src/miconv.h<br>
&gt; @@ -0,0 +1,35 @@<br>&gt; +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */<br>&gt; +/*<br>&gt; + * miconv.h: <br>&gt; + *<br>&gt; + * Contact:<br>&gt; + *   Moonlight List (<a href="mailto:moonlight-list@lists.ximian.com">moonlight-list@lists.ximian.com</a>)<br>
&gt; + *<br>&gt; + * Copyright 2011 Novell, Inc. (<a href="http://www.novell.com">http://www.novell.com</a>)<br>&gt; + *<br>&gt; + * See the LICENSE file included with the distribution for details.<br>&gt; + */<br>&gt; +<br>
&gt; +#ifndef __MICONV_H__<br>&gt; +#define __MICONV_H__<br>&gt; +<br>&gt; +#include &lt;glib.h&gt;<br>&gt; +#include &lt;sys/types.h&gt;<br>&gt; +<br>&gt; +namespace Moonlight {<br>&gt; +<br>&gt; +G_BEGIN_DECLS<br>&gt; +<br>
&gt; +typedef struct _miconv_t *miconv_t;<br>&gt; +<br>&gt; +int miconv (miconv_t cd, char **inbytes, size_t *inbytesleft,<br>&gt; +            char **outbytes, size_t *outbytesleft);<br>&gt; +miconv_t miconv_open (const char *to, const char *from);<br>
&gt; +int miconv_close (miconv_t cd);<br>&gt; +<br>&gt; +G_END_DECLS<br>&gt; +<br>&gt; +};<br>&gt; +<br>&gt; +#endif /* __MICONV_H__ */<br>&gt; +<br>&gt; <br>&gt; <br>&gt; <br>&gt; <br>&gt; <br>&gt; _______________________________________________<br>
&gt; Mono-patches maillist  -  <a href="mailto:Mono-patches@lists.ximian.com">Mono-patches@lists.ximian.com</a><br>&gt; <a href="http://lists.ximian.com/mailman/listinfo/mono-patches">http://lists.ximian.com/mailman/listinfo/mono-patches</a><br>
</div>