]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
dos2unix a bunch of files
authorMoises Silva <moy@sangoma.com>
Tue, 22 Jul 2014 19:04:28 +0000 (15:04 -0400)
committerMoises Silva <moy@sangoma.com>
Tue, 22 Jul 2014 19:04:28 +0000 (15:04 -0400)
For some reason these files would get marked as modified
just after a fresh clone on Linux

17 files changed:
src/mod/applications/mod_stress/FFTReal.cpp
src/mod/asr_tts/mod_cepstral/WinReadme.txt
src/mod/endpoints/mod_gsmopen/alsa_nogsmlib_nocplusplus/mod_gsmopen/gsmopen_protocol.c
src/mod/endpoints/mod_gsmopen/libctb-0.16/include/ctb-0.16/win32/getopt.h
src/mod/endpoints/mod_gsmopen/libctb-0.16/include/ctb-0.16/win32/gpib-32.h
src/mod/endpoints/mod_gsmopen/win_iconv.c
src/mod/endpoints/mod_gsmopen/win_iconv/iconv.h
src/mod/endpoints/mod_gsmopen/win_iconv/mlang.h
src/mod/endpoints/mod_gsmopen/win_iconv/readme.txt
src/mod/endpoints/mod_gsmopen/win_iconv/win_iconv.c
src/mod/endpoints/mod_gsmopen/win_iconv/win_iconv_test.c
src/mod/endpoints/mod_opal/mod_opal.cpp
src/mod/endpoints/mod_opal/mod_opal.h
src/mod/endpoints/mod_rtmp/libamf/amf-cmake.h.in
src/mod/languages/mod_perl/perlibs.h.in
src/mod/say/mod_say_fa/mod_say_fa.c
src/mod/say/mod_say_pt/mod_say_pt.c

index e1a77b465e8e36ea3d68f4a677b17a275e6c3686..3c82fc075262ac6a48e916bbb401ebe288b681cf 100644 (file)
-/*****************************************************************************\r
-*                                                                            *\r
-*       DIGITAL SIGNAL PROCESSING TOOLS                                      *\r
-*       Version 1.03, 2001/06/15                                             *\r
-*       (c) 1999 - Laurent de Soras                                          *\r
-*                                                                            *\r
-*       FFTReal.cpp                                                          *\r
-*       Fourier transformation of real number arrays.                        *\r
-*       Portable ISO C++                                                     *\r
-*                                                                            *\r
-* Tab = 3                                                                    *\r
-*****************************************************************************/\r
-\r
-\r
-\r
-/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/\r
-\r
-#include       "FFTReal.h"\r
-\r
-#include       <cassert>\r
-#include       <cmath>\r
-\r
-\r
-\r
-#if defined (_MSC_VER)\r
-#pragma pack (push, 8)\r
-#endif // _MSC_VER\r
-\r
-\r
-\r
-/*\\\ PUBLIC MEMBER FUNCTIONS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/\r
-\r
-\r
-\r
-/*==========================================================================*/\r
-/*      Name: Constructor                                                   */\r
-/*      Input parameters:                                                   */\r
-/*        - length: length of the array on which we want to do a FFT.       */\r
-/*                  Range: power of 2 only, > 0.                            */\r
-/*      Throws: std::bad_alloc, anything                                    */\r
-/*==========================================================================*/\r
-\r
-FFTReal::FFTReal (const long length)\r
-:      _length (length)\r
-,      _nbr_bits (int (floor (log (length) / log (2) + 0.5)))\r
-,      _bit_rev_lut (int (floor (log (length) / log (2) + 0.5)))\r
-,      _trigo_lut (int (floor (log (length) / log (2) + 0.5)))\r
-,      _sqrt2_2 (flt_t (sqrt (2) * 0.5))\r
-{\r
-       assert ((1L << _nbr_bits) == length);\r
-\r
-       _buffer_ptr = 0;\r
-       if (_nbr_bits > 2)\r
-       {\r
-               _buffer_ptr = new flt_t [_length];\r
-       }\r
-}\r
-\r
-\r
-\r
-/*==========================================================================*/\r
-/*      Name: Destructor                                                    */\r
-/*==========================================================================*/\r
-\r
-FFTReal::~FFTReal (void)\r
-{\r
-       delete [] _buffer_ptr;\r
-       _buffer_ptr = 0;\r
-}\r
-\r
-\r
-\r
-/*==========================================================================*/\r
-/*      Name: do_fft                                                        */\r
-/*      Description: Compute the FFT of the array.                          */\r
-/*      Input parameters:                                                   */\r
-/*        - x: pointer on the source array (time).                          */\r
-/*      Output parameters:                                                  */\r
-/*        - f: pointer on the destination array (frequencies).              */\r
-/*             f [0...length(x)/2] = real values,                           */\r
-/*             f [length(x)/2+1...length(x)-1] = imaginary values of        */\r
-/*               coefficents 1...length(x)/2-1.                             */\r
-/*      Throws: Nothing                                                     */\r
-/*==========================================================================*/\r
-\r
-void   FFTReal::do_fft (flt_t f [], const flt_t x []) const\r
-{\r
-\r
-/*______________________________________________\r
- *\r
- * General case\r
- *______________________________________________\r
- */\r
-\r
-       if (_nbr_bits > 2)\r
-       {\r
-               flt_t *                 sf;\r
-               flt_t *                 df;\r
-\r
-               if (_nbr_bits & 1)\r
-               {\r
-                       df = _buffer_ptr;\r
-                       sf = f;\r
-               }\r
-               else\r
-               {\r
-                       df = f;\r
-                       sf = _buffer_ptr;\r
-               }\r
-\r
-               /* Do the transformation in several pass */\r
-               {\r
-                       int             pass;\r
-                       long            nbr_coef;\r
-                       long            h_nbr_coef;\r
-                       long            d_nbr_coef;\r
-                       long            coef_index;\r
-\r
-                       /* First and second pass at once */\r
-                       {\r
-                               const long * const      bit_rev_lut_ptr = _bit_rev_lut.get_ptr ();\r
-                               coef_index = 0;\r
-                               do\r
-                               {\r
-                                       const long              rev_index_0 = bit_rev_lut_ptr [coef_index];\r
-                                       const long              rev_index_1 = bit_rev_lut_ptr [coef_index + 1];\r
-                                       const long              rev_index_2 = bit_rev_lut_ptr [coef_index + 2];\r
-                                       const long              rev_index_3 = bit_rev_lut_ptr [coef_index + 3];\r
-\r
-                                       flt_t   * const df2 = df + coef_index;\r
-                                       df2 [1] = x [rev_index_0] - x [rev_index_1];\r
-                                       df2 [3] = x [rev_index_2] - x [rev_index_3];\r
-\r
-                                       const flt_t             sf_0 = x [rev_index_0] + x [rev_index_1];\r
-                                       const flt_t             sf_2 = x [rev_index_2] + x [rev_index_3];\r
-\r
-                                       df2 [0] = sf_0 + sf_2;\r
-                                       df2 [2] = sf_0 - sf_2;\r
-                                       \r
-                                       coef_index += 4;\r
-                               }\r
-                               while (coef_index < _length);\r
-                       }\r
-\r
-                       /* Third pass */\r
-                       {\r
-                               coef_index = 0;\r
-                               const flt_t             sqrt2_2 = _sqrt2_2;\r
-                               do\r
-                               {\r
-                                       flt_t                           v;\r
-\r
-                                       sf [coef_index] = df [coef_index] + df [coef_index + 4];\r
-                                       sf [coef_index + 4] = df [coef_index] - df [coef_index + 4];\r
-                                       sf [coef_index + 2] = df [coef_index + 2];\r
-                                       sf [coef_index + 6] = df [coef_index + 6];\r
-\r
-                                       v = (df [coef_index + 5] - df [coef_index + 7]) * sqrt2_2;\r
-                                       sf [coef_index + 1] = df [coef_index + 1] + v;\r
-                                       sf [coef_index + 3] = df [coef_index + 1] - v;\r
-\r
-                                       v = (df [coef_index + 5] + df [coef_index + 7]) * sqrt2_2;\r
-                                       sf [coef_index + 5] = v + df [coef_index + 3];\r
-                                       sf [coef_index + 7] = v - df [coef_index + 3];\r
-\r
-                                       coef_index += 8;\r
-                               }\r
-                               while (coef_index < _length);\r
-                       }\r
-\r
-                       /* Next pass */\r
-                       for (pass = 3; pass < _nbr_bits; ++pass)\r
-                       {\r
-                               coef_index = 0;\r
-                               nbr_coef = 1 << pass;\r
-                               h_nbr_coef = nbr_coef >> 1;\r
-                               d_nbr_coef = nbr_coef << 1;\r
-                               const flt_t     * const cos_ptr = _trigo_lut.get_ptr (pass);\r
-                               do\r
-                               {\r
-                                       long                            i;\r
-                                       const flt_t     *       const sf1r = sf + coef_index;\r
-                                       const flt_t     *       const sf2r = sf1r + nbr_coef;\r
-                                       flt_t *                 const dfr = df + coef_index;\r
-                                       flt_t *                 const dfi = dfr + nbr_coef;\r
-\r
-                                       /* Extreme coefficients are always real */\r
-                                       dfr [0] = sf1r [0] + sf2r [0];\r
-                                       dfi [0] = sf1r [0] - sf2r [0];  // dfr [nbr_coef] =\r
-                                       dfr [h_nbr_coef] = sf1r [h_nbr_coef];\r
-                                       dfi [h_nbr_coef] = sf2r [h_nbr_coef];\r
-\r
-                                       /* Others are conjugate complex numbers */\r
-                                       const flt_t     * const sf1i = sf1r + h_nbr_coef;\r
-                                       const flt_t     * const sf2i = sf1i + nbr_coef;\r
-                                       for (i = 1; i < h_nbr_coef; ++ i)\r
-                                       {\r
-                                               const flt_t             c = cos_ptr [i];                                        // cos (i*PI/nbr_coef);\r
-                                               const flt_t             s = cos_ptr [h_nbr_coef - i];   // sin (i*PI/nbr_coef);\r
-                                               flt_t                           v;\r
-\r
-                                               v = sf2r [i] * c - sf2i [i] * s;\r
-                                               dfr [i] = sf1r [i] + v;\r
-                                               dfi [-i] = sf1r [i] - v;        // dfr [nbr_coef - i] =\r
-\r
-                                               v = sf2r [i] * s + sf2i [i] * c;\r
-                                               dfi [i] = v + sf1i [i];\r
-                                               dfi [nbr_coef - i] = v - sf1i [i];\r
-                                       }\r
-\r
-                                       coef_index += d_nbr_coef;\r
-                               }\r
-                               while (coef_index < _length);\r
-\r
-                               /* Prepare to the next pass */\r
-                               {\r
-                                       flt_t   * const         temp_ptr = df;\r
-                                       df = sf;\r
-                                       sf = temp_ptr;\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-/*______________________________________________\r
- *\r
- * Special cases\r
- *______________________________________________\r
- */\r
-\r
-       /* 4-point FFT */\r
-       else if (_nbr_bits == 2)\r
-       {\r
-               f [1] = x [0] - x [2];\r
-               f [3] = x [1] - x [3];\r
-\r
-               const flt_t                     b_0 = x [0] + x [2];\r
-               const flt_t                     b_2 = x [1] + x [3];\r
-               \r
-               f [0] = b_0 + b_2;\r
-               f [2] = b_0 - b_2;\r
-       }\r
-\r
-       /* 2-point FFT */\r
-       else if (_nbr_bits == 1)\r
-       {\r
-               f [0] = x [0] + x [1];\r
-               f [1] = x [0] - x [1];\r
-       }\r
-\r
-       /* 1-point FFT */\r
-       else\r
-       {\r
-               f [0] = x [0];\r
-       }\r
-}\r
-\r
-\r
-\r
-/*==========================================================================*/\r
-/*      Name: do_ifft                                                       */\r
-/*      Description: Compute the inverse FFT of the array. Notice that      */\r
-/*                   IFFT (FFT (x)) = x * length (x). Data must be          */\r
-/*                   post-scaled.                                           */\r
-/*      Input parameters:                                                   */\r
-/*        - f: pointer on the source array (frequencies).                   */\r
-/*             f [0...length(x)/2] = real values,                           */\r
-/*             f [length(x)/2+1...length(x)] = imaginary values of          */\r
-/*               coefficents 1...length(x)-1.                               */\r
-/*      Output parameters:                                                  */\r
-/*        - x: pointer on the destination array (time).                     */\r
-/*      Throws: Nothing                                                     */\r
-/*==========================================================================*/\r
-\r
-void   FFTReal::do_ifft (const flt_t f [], flt_t x []) const\r
-{\r
-\r
-/*______________________________________________\r
- *\r
- * General case\r
- *______________________________________________\r
- */\r
-\r
-       if (_nbr_bits > 2)\r
-       {\r
-               flt_t *                 sf = const_cast <flt_t *> (f);\r
-               flt_t *                 df;\r
-               flt_t *                 df_temp;\r
-\r
-               if (_nbr_bits & 1)\r
-               {\r
-                       df = _buffer_ptr;\r
-                       df_temp = x;\r
-               }\r
-               else\r
-               {\r
-                       df = x;\r
-                       df_temp = _buffer_ptr;\r
-               }\r
-\r
-               /* Do the transformation in several pass */\r
-               {\r
-                       int                     pass;\r
-                       long                    nbr_coef;\r
-                       long                    h_nbr_coef;\r
-                       long                    d_nbr_coef;\r
-                       long                    coef_index;\r
-\r
-                       /* First pass */\r
-                       for (pass = _nbr_bits - 1; pass >= 3; --pass)\r
-                       {\r
-                               coef_index = 0;\r
-                               nbr_coef = 1 << pass;\r
-                               h_nbr_coef = nbr_coef >> 1;\r
-                               d_nbr_coef = nbr_coef << 1;\r
-                               const flt_t     *const cos_ptr = _trigo_lut.get_ptr (pass);\r
-                               do\r
-                               {\r
-                                       long                            i;\r
-                                       const flt_t     *       const sfr = sf + coef_index;\r
-                                       const flt_t     *       const sfi = sfr + nbr_coef;\r
-                                       flt_t *                 const df1r = df + coef_index;\r
-                                       flt_t *                 const df2r = df1r + nbr_coef;\r
-\r
-                                       /* Extreme coefficients are always real */\r
-                                       df1r [0] = sfr [0] + sfi [0];           // + sfr [nbr_coef]\r
-                                       df2r [0] = sfr [0] - sfi [0];           // - sfr [nbr_coef]\r
-                                       df1r [h_nbr_coef] = sfr [h_nbr_coef] * 2;\r
-                                       df2r [h_nbr_coef] = sfi [h_nbr_coef] * 2;\r
-\r
-                                       /* Others are conjugate complex numbers */\r
-                                       flt_t * const   df1i = df1r + h_nbr_coef;\r
-                                       flt_t * const   df2i = df1i + nbr_coef;\r
-                                       for (i = 1; i < h_nbr_coef; ++ i)\r
-                                       {\r
-                                               df1r [i] = sfr [i] + sfi [-i];          // + sfr [nbr_coef - i]\r
-                                               df1i [i] = sfi [i] - sfi [nbr_coef - i];\r
-\r
-                                               const flt_t             c = cos_ptr [i];                                        // cos (i*PI/nbr_coef);\r
-                                               const flt_t             s = cos_ptr [h_nbr_coef - i];   // sin (i*PI/nbr_coef);\r
-                                               const flt_t             vr = sfr [i] - sfi [-i];                // - sfr [nbr_coef - i]\r
-                                               const flt_t             vi = sfi [i] + sfi [nbr_coef - i];\r
-\r
-                                               df2r [i] = vr * c + vi * s;\r
-                                               df2i [i] = vi * c - vr * s;\r
-                                       }\r
-\r
-                                       coef_index += d_nbr_coef;\r
-                               }\r
-                               while (coef_index < _length);\r
-\r
-                               /* Prepare to the next pass */\r
-                               if (pass < _nbr_bits - 1)\r
-                               {\r
-                                       flt_t   * const temp_ptr = df;\r
-                                       df = sf;\r
-                                       sf = temp_ptr;\r
-                               }\r
-                               else\r
-                               {\r
-                                       sf = df;\r
-                                       df = df_temp;\r
-                               }\r
-                       }\r
-\r
-                       /* Antepenultimate pass */\r
-                       {\r
-                               const flt_t             sqrt2_2 = _sqrt2_2;\r
-                               coef_index = 0;\r
-                               do\r
-                               {\r
-                                       df [coef_index] = sf [coef_index] + sf [coef_index + 4];\r
-                                       df [coef_index + 4] = sf [coef_index] - sf [coef_index + 4];\r
-                                       df [coef_index + 2] = sf [coef_index + 2] * 2;\r
-                                       df [coef_index + 6] = sf [coef_index + 6] * 2;\r
-\r
-                                       df [coef_index + 1] = sf [coef_index + 1] + sf [coef_index + 3];\r
-                                       df [coef_index + 3] = sf [coef_index + 5] - sf [coef_index + 7];\r
-\r
-                                       const flt_t             vr = sf [coef_index + 1] - sf [coef_index + 3];\r
-                                       const flt_t             vi = sf [coef_index + 5] + sf [coef_index + 7];\r
-\r
-                                       df [coef_index + 5] = (vr + vi) * sqrt2_2;\r
-                                       df [coef_index + 7] = (vi - vr) * sqrt2_2;\r
-\r
-                                       coef_index += 8;\r
-                               }\r
-                               while (coef_index < _length);\r
-                       }\r
-\r
-                       /* Penultimate and last pass at once */\r
-                       {\r
-                               coef_index = 0;\r
-                               const long *    bit_rev_lut_ptr = _bit_rev_lut.get_ptr ();\r
-                               const flt_t     *       sf2 = df;\r
-                               do\r
-                               {\r
-                                       {\r
-                                               const flt_t             b_0 = sf2 [0] + sf2 [2];\r
-                                               const flt_t             b_2 = sf2 [0] - sf2 [2];\r
-                                               const flt_t             b_1 = sf2 [1] * 2;\r
-                                               const flt_t             b_3 = sf2 [3] * 2;\r
-\r
-                                               x [bit_rev_lut_ptr [0]] = b_0 + b_1;\r
-                                               x [bit_rev_lut_ptr [1]] = b_0 - b_1;\r
-                                               x [bit_rev_lut_ptr [2]] = b_2 + b_3;\r
-                                               x [bit_rev_lut_ptr [3]] = b_2 - b_3;\r
-                                       }\r
-                                       {\r
-                                               const flt_t             b_0 = sf2 [4] + sf2 [6];\r
-                                               const flt_t             b_2 = sf2 [4] - sf2 [6];\r
-                                               const flt_t             b_1 = sf2 [5] * 2;\r
-                                               const flt_t             b_3 = sf2 [7] * 2;\r
-\r
-                                               x [bit_rev_lut_ptr [4]] = b_0 + b_1;\r
-                                               x [bit_rev_lut_ptr [5]] = b_0 - b_1;\r
-                                               x [bit_rev_lut_ptr [6]] = b_2 + b_3;\r
-                                               x [bit_rev_lut_ptr [7]] = b_2 - b_3;\r
-                                       }\r
-\r
-                                       sf2 += 8;\r
-                                       coef_index += 8;\r
-                                       bit_rev_lut_ptr += 8;\r
-                               }\r
-                               while (coef_index < _length);\r
-                       }\r
-               }\r
-       }\r
-\r
-/*______________________________________________\r
- *\r
- * Special cases\r
- *______________________________________________\r
- */\r
-\r
-       /* 4-point IFFT */\r
-       else if (_nbr_bits == 2)\r
-       {\r
-               const flt_t             b_0 = f [0] + f [2];\r
-               const flt_t             b_2 = f [0] - f [2];\r
-\r
-               x [0] = b_0 + f [1] * 2;\r
-               x [2] = b_0 - f [1] * 2;\r
-               x [1] = b_2 + f [3] * 2;\r
-               x [3] = b_2 - f [3] * 2;\r
-       }\r
-\r
-       /* 2-point IFFT */\r
-       else if (_nbr_bits == 1)\r
-       {\r
-               x [0] = f [0] + f [1];\r
-               x [1] = f [0] - f [1];\r
-       }\r
-\r
-       /* 1-point IFFT */\r
-       else\r
-       {\r
-               x [0] = f [0];\r
-       }\r
-}\r
-\r
-\r
-\r
-/*==========================================================================*/\r
-/*      Name: rescale                                                       */\r
-/*      Description: Scale an array by divide each element by its length.   */\r
-/*                   This function should be called after FFT + IFFT.       */\r
-/*      Input/Output parameters:                                            */\r
-/*        - x: pointer on array to rescale (time or frequency).             */\r
-/*      Throws: Nothing                                                     */\r
-/*==========================================================================*/\r
-\r
-void   FFTReal::rescale (flt_t x []) const\r
-{\r
-       const flt_t             mul = flt_t (1.0 / _length);\r
-       long                            i = _length - 1;\r
-\r
-       do\r
-       {\r
-               x [i] *= mul;\r
-               --i;\r
-       }\r
-       while (i >= 0);\r
-}\r
-\r
-\r
-\r
-/*\\\ NESTED CLASS MEMBER FUNCTIONS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/\r
-\r
-\r
-\r
-/*==========================================================================*/\r
-/*      Name: Constructor                                                   */\r
-/*      Input parameters:                                                   */\r
-/*        - nbr_bits: number of bits of the array on which we want to do a  */\r
-/*                    FFT. Range: > 0                                       */\r
-/*      Throws: std::bad_alloc                                              */\r
-/*==========================================================================*/\r
-\r
-FFTReal::BitReversedLUT::BitReversedLUT (const int nbr_bits)\r
-{\r
-       long                            length;\r
-       long                            cnt;\r
-       long                            br_index;\r
-       long                            bit;\r
-\r
-       length = 1L << nbr_bits;\r
-       _ptr = new long [length];\r
-\r
-       br_index = 0;\r
-       _ptr [0] = 0;\r
-       for (cnt = 1; cnt < length; ++cnt)\r
-       {\r
-               /* ++br_index (bit reversed) */\r
-               bit = length >> 1;\r
-               while (((br_index ^= bit) & bit) == 0)\r
-               {\r
-                       bit >>= 1;\r
-               }\r
-\r
-               _ptr [cnt] = br_index;\r
-       }\r
-}\r
-\r
-\r
-\r
-/*==========================================================================*/\r
-/*      Name: Destructor                                                    */\r
-/*==========================================================================*/\r
-\r
-FFTReal::BitReversedLUT::~BitReversedLUT (void)\r
-{\r
-       delete [] _ptr;\r
-       _ptr = 0;\r
-}\r
-\r
-\r
-\r
-/*==========================================================================*/\r
-/*      Name: Constructor                                                   */\r
-/*      Input parameters:                                                   */\r
-/*        - nbr_bits: number of bits of the array on which we want to do a  */\r
-/*                    FFT. Range: > 0                                       */\r
-/*      Throws: std::bad_alloc, anything                                    */\r
-/*==========================================================================*/\r
-\r
-FFTReal::TrigoLUT::TrigoLUT (const int nbr_bits)\r
-{\r
-       long            total_len;\r
-\r
-       _ptr = 0;\r
-       if (nbr_bits > 3)\r
-       {\r
-               total_len = (1L << (nbr_bits - 1)) - 4;\r
-               _ptr = new flt_t [total_len];\r
-\r
-               const double    PI = atan (1) * 4;\r
-               for (int level = 3; level < nbr_bits; ++level)\r
-               {\r
-                       const long              level_len = 1L << (level - 1);\r
-                       flt_t   * const level_ptr = const_cast<flt_t *> (get_ptr (level));\r
-                       const double    mul = PI / (level_len << 1);\r
-\r
-                       for (long i = 0; i < level_len; ++ i)\r
-                       {\r
-                               level_ptr [i] = (flt_t) cos (i * mul);\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-\r
-\r
-/*==========================================================================*/\r
-/*      Name: Destructor                                                    */\r
-/*==========================================================================*/\r
-\r
-FFTReal::TrigoLUT::~TrigoLUT (void)\r
-{\r
-       delete [] _ptr;\r
-       _ptr = 0;\r
-}\r
-\r
-\r
-\r
-#if defined (_MSC_VER)\r
-#pragma pack (pop)\r
-#endif // _MSC_VER\r
-\r
-\r
-\r
-/*****************************************************************************\r
-\r
-       LEGAL\r
-\r
-       Source code may be freely used for any purpose, including commercial\r
-       applications. Programs must display in their "About" dialog-box (or\r
-       documentation) a text telling they use these routines by Laurent de Soras.\r
-       Modified source code can be distributed, but modifications must be clearly\r
-       indicated.\r
-\r
-       CONTACT\r
-\r
-       Laurent de Soras\r
-       92 avenue Albert 1er\r
-       92500 Rueil-Malmaison\r
-       France\r
-\r
-       ldesoras@club-internet.fr\r
-\r
-*****************************************************************************/\r
-\r
-\r
-\r
-/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/\r
+/*****************************************************************************
+*                                                                            *
+*       DIGITAL SIGNAL PROCESSING TOOLS                                      *
+*       Version 1.03, 2001/06/15                                             *
+*       (c) 1999 - Laurent de Soras                                          *
+*                                                                            *
+*       FFTReal.cpp                                                          *
+*       Fourier transformation of real number arrays.                        *
+*       Portable ISO C++                                                     *
+*                                                                            *
+* Tab = 3                                                                    *
+*****************************************************************************/
+
+
+
+/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
+
+#include       "FFTReal.h"
+
+#include       <cassert>
+#include       <cmath>
+
+
+
+#if defined (_MSC_VER)
+#pragma pack (push, 8)
+#endif // _MSC_VER
+
+
+
+/*\\\ PUBLIC MEMBER FUNCTIONS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
+
+
+
+/*==========================================================================*/
+/*      Name: Constructor                                                   */
+/*      Input parameters:                                                   */
+/*        - length: length of the array on which we want to do a FFT.       */
+/*                  Range: power of 2 only, > 0.                            */
+/*      Throws: std::bad_alloc, anything                                    */
+/*==========================================================================*/
+
+FFTReal::FFTReal (const long length)
+:      _length (length)
+,      _nbr_bits (int (floor (log (length) / log (2) + 0.5)))
+,      _bit_rev_lut (int (floor (log (length) / log (2) + 0.5)))
+,      _trigo_lut (int (floor (log (length) / log (2) + 0.5)))
+,      _sqrt2_2 (flt_t (sqrt (2) * 0.5))
+{
+       assert ((1L << _nbr_bits) == length);
+
+       _buffer_ptr = 0;
+       if (_nbr_bits > 2)
+       {
+               _buffer_ptr = new flt_t [_length];
+       }
+}
+
+
+
+/*==========================================================================*/
+/*      Name: Destructor                                                    */
+/*==========================================================================*/
+
+FFTReal::~FFTReal (void)
+{
+       delete [] _buffer_ptr;
+       _buffer_ptr = 0;
+}
+
+
+
+/*==========================================================================*/
+/*      Name: do_fft                                                        */
+/*      Description: Compute the FFT of the array.                          */
+/*      Input parameters:                                                   */
+/*        - x: pointer on the source array (time).                          */
+/*      Output parameters:                                                  */
+/*        - f: pointer on the destination array (frequencies).              */
+/*             f [0...length(x)/2] = real values,                           */
+/*             f [length(x)/2+1...length(x)-1] = imaginary values of        */
+/*               coefficents 1...length(x)/2-1.                             */
+/*      Throws: Nothing                                                     */
+/*==========================================================================*/
+
+void   FFTReal::do_fft (flt_t f [], const flt_t x []) const
+{
+
+/*______________________________________________
+ *
+ * General case
+ *______________________________________________
+ */
+
+       if (_nbr_bits > 2)
+       {
+               flt_t *                 sf;
+               flt_t *                 df;
+
+               if (_nbr_bits & 1)
+               {
+                       df = _buffer_ptr;
+                       sf = f;
+               }
+               else
+               {
+                       df = f;
+                       sf = _buffer_ptr;
+               }
+
+               /* Do the transformation in several pass */
+               {
+                       int             pass;
+                       long            nbr_coef;
+                       long            h_nbr_coef;
+                       long            d_nbr_coef;
+                       long            coef_index;
+
+                       /* First and second pass at once */
+                       {
+                               const long * const      bit_rev_lut_ptr = _bit_rev_lut.get_ptr ();
+                               coef_index = 0;
+                               do
+                               {
+                                       const long              rev_index_0 = bit_rev_lut_ptr [coef_index];
+                                       const long              rev_index_1 = bit_rev_lut_ptr [coef_index + 1];
+                                       const long              rev_index_2 = bit_rev_lut_ptr [coef_index + 2];
+                                       const long              rev_index_3 = bit_rev_lut_ptr [coef_index + 3];
+
+                                       flt_t   * const df2 = df + coef_index;
+                                       df2 [1] = x [rev_index_0] - x [rev_index_1];
+                                       df2 [3] = x [rev_index_2] - x [rev_index_3];
+
+                                       const flt_t             sf_0 = x [rev_index_0] + x [rev_index_1];
+                                       const flt_t             sf_2 = x [rev_index_2] + x [rev_index_3];
+
+                                       df2 [0] = sf_0 + sf_2;
+                                       df2 [2] = sf_0 - sf_2;
+                                       
+                                       coef_index += 4;
+                               }
+                               while (coef_index < _length);
+                       }
+
+                       /* Third pass */
+                       {
+                               coef_index = 0;
+                               const flt_t             sqrt2_2 = _sqrt2_2;
+                               do
+                               {
+                                       flt_t                           v;
+
+                                       sf [coef_index] = df [coef_index] + df [coef_index + 4];
+                                       sf [coef_index + 4] = df [coef_index] - df [coef_index + 4];
+                                       sf [coef_index + 2] = df [coef_index + 2];
+                                       sf [coef_index + 6] = df [coef_index + 6];
+
+                                       v = (df [coef_index + 5] - df [coef_index + 7]) * sqrt2_2;
+                                       sf [coef_index + 1] = df [coef_index + 1] + v;
+                                       sf [coef_index + 3] = df [coef_index + 1] - v;
+
+                                       v = (df [coef_index + 5] + df [coef_index + 7]) * sqrt2_2;
+                                       sf [coef_index + 5] = v + df [coef_index + 3];
+                                       sf [coef_index + 7] = v - df [coef_index + 3];
+
+                                       coef_index += 8;
+                               }
+                               while (coef_index < _length);
+                       }
+
+                       /* Next pass */
+                       for (pass = 3; pass < _nbr_bits; ++pass)
+                       {
+                               coef_index = 0;
+                               nbr_coef = 1 << pass;
+                               h_nbr_coef = nbr_coef >> 1;
+                               d_nbr_coef = nbr_coef << 1;
+                               const flt_t     * const cos_ptr = _trigo_lut.get_ptr (pass);
+                               do
+                               {
+                                       long                            i;
+                                       const flt_t     *       const sf1r = sf + coef_index;
+                                       const flt_t     *       const sf2r = sf1r + nbr_coef;
+                                       flt_t *                 const dfr = df + coef_index;
+                                       flt_t *                 const dfi = dfr + nbr_coef;
+
+                                       /* Extreme coefficients are always real */
+                                       dfr [0] = sf1r [0] + sf2r [0];
+                                       dfi [0] = sf1r [0] - sf2r [0];  // dfr [nbr_coef] =
+                                       dfr [h_nbr_coef] = sf1r [h_nbr_coef];
+                                       dfi [h_nbr_coef] = sf2r [h_nbr_coef];
+
+                                       /* Others are conjugate complex numbers */
+                                       const flt_t     * const sf1i = sf1r + h_nbr_coef;
+                                       const flt_t     * const sf2i = sf1i + nbr_coef;
+                                       for (i = 1; i < h_nbr_coef; ++ i)
+                                       {
+                                               const flt_t             c = cos_ptr [i];                                        // cos (i*PI/nbr_coef);
+                                               const flt_t             s = cos_ptr [h_nbr_coef - i];   // sin (i*PI/nbr_coef);
+                                               flt_t                           v;
+
+                                               v = sf2r [i] * c - sf2i [i] * s;
+                                               dfr [i] = sf1r [i] + v;
+                                               dfi [-i] = sf1r [i] - v;        // dfr [nbr_coef - i] =
+
+                                               v = sf2r [i] * s + sf2i [i] * c;
+                                               dfi [i] = v + sf1i [i];
+                                               dfi [nbr_coef - i] = v - sf1i [i];
+                                       }
+
+                                       coef_index += d_nbr_coef;
+                               }
+                               while (coef_index < _length);
+
+                               /* Prepare to the next pass */
+                               {
+                                       flt_t   * const         temp_ptr = df;
+                                       df = sf;
+                                       sf = temp_ptr;
+                               }
+                       }
+               }
+       }
+
+/*______________________________________________
+ *
+ * Special cases
+ *______________________________________________
+ */
+
+       /* 4-point FFT */
+       else if (_nbr_bits == 2)
+       {
+               f [1] = x [0] - x [2];
+               f [3] = x [1] - x [3];
+
+               const flt_t                     b_0 = x [0] + x [2];
+               const flt_t                     b_2 = x [1] + x [3];
+               
+               f [0] = b_0 + b_2;
+               f [2] = b_0 - b_2;
+       }
+
+       /* 2-point FFT */
+       else if (_nbr_bits == 1)
+       {
+               f [0] = x [0] + x [1];
+               f [1] = x [0] - x [1];
+       }
+
+       /* 1-point FFT */
+       else
+       {
+               f [0] = x [0];
+       }
+}
+
+
+
+/*==========================================================================*/
+/*      Name: do_ifft                                                       */
+/*      Description: Compute the inverse FFT of the array. Notice that      */
+/*                   IFFT (FFT (x)) = x * length (x). Data must be          */
+/*                   post-scaled.                                           */
+/*      Input parameters:                                                   */
+/*        - f: pointer on the source array (frequencies).                   */
+/*             f [0...length(x)/2] = real values,                           */
+/*             f [length(x)/2+1...length(x)] = imaginary values of          */
+/*               coefficents 1...length(x)-1.                               */
+/*      Output parameters:                                                  */
+/*        - x: pointer on the destination array (time).                     */
+/*      Throws: Nothing                                                     */
+/*==========================================================================*/
+
+void   FFTReal::do_ifft (const flt_t f [], flt_t x []) const
+{
+
+/*______________________________________________
+ *
+ * General case
+ *______________________________________________
+ */
+
+       if (_nbr_bits > 2)
+       {
+               flt_t *                 sf = const_cast <flt_t *> (f);
+               flt_t *                 df;
+               flt_t *                 df_temp;
+
+               if (_nbr_bits & 1)
+               {
+                       df = _buffer_ptr;
+                       df_temp = x;
+               }
+               else
+               {
+                       df = x;
+                       df_temp = _buffer_ptr;
+               }
+
+               /* Do the transformation in several pass */
+               {
+                       int                     pass;
+                       long                    nbr_coef;
+                       long                    h_nbr_coef;
+                       long                    d_nbr_coef;
+                       long                    coef_index;
+
+                       /* First pass */
+                       for (pass = _nbr_bits - 1; pass >= 3; --pass)
+                       {
+                               coef_index = 0;
+                               nbr_coef = 1 << pass;
+                               h_nbr_coef = nbr_coef >> 1;
+                               d_nbr_coef = nbr_coef << 1;
+                               const flt_t     *const cos_ptr = _trigo_lut.get_ptr (pass);
+                               do
+                               {
+                                       long                            i;
+                                       const flt_t     *       const sfr = sf + coef_index;
+                                       const flt_t     *       const sfi = sfr + nbr_coef;
+                                       flt_t *                 const df1r = df + coef_index;
+                                       flt_t *                 const df2r = df1r + nbr_coef;
+
+                                       /* Extreme coefficients are always real */
+                                       df1r [0] = sfr [0] + sfi [0];           // + sfr [nbr_coef]
+                                       df2r [0] = sfr [0] - sfi [0];           // - sfr [nbr_coef]
+                                       df1r [h_nbr_coef] = sfr [h_nbr_coef] * 2;
+                                       df2r [h_nbr_coef] = sfi [h_nbr_coef] * 2;
+
+                                       /* Others are conjugate complex numbers */
+                                       flt_t * const   df1i = df1r + h_nbr_coef;
+                                       flt_t * const   df2i = df1i + nbr_coef;
+                                       for (i = 1; i < h_nbr_coef; ++ i)
+                                       {
+                                               df1r [i] = sfr [i] + sfi [-i];          // + sfr [nbr_coef - i]
+                                               df1i [i] = sfi [i] - sfi [nbr_coef - i];
+
+                                               const flt_t             c = cos_ptr [i];                                        // cos (i*PI/nbr_coef);
+                                               const flt_t             s = cos_ptr [h_nbr_coef - i];   // sin (i*PI/nbr_coef);
+                                               const flt_t             vr = sfr [i] - sfi [-i];                // - sfr [nbr_coef - i]
+                                               const flt_t             vi = sfi [i] + sfi [nbr_coef - i];
+
+                                               df2r [i] = vr * c + vi * s;
+                                               df2i [i] = vi * c - vr * s;
+                                       }
+
+                                       coef_index += d_nbr_coef;
+                               }
+                               while (coef_index < _length);
+
+                               /* Prepare to the next pass */
+                               if (pass < _nbr_bits - 1)
+                               {
+                                       flt_t   * const temp_ptr = df;
+                                       df = sf;
+                                       sf = temp_ptr;
+                               }
+                               else
+                               {
+                                       sf = df;
+                                       df = df_temp;
+                               }
+                       }
+
+                       /* Antepenultimate pass */
+                       {
+                               const flt_t             sqrt2_2 = _sqrt2_2;
+                               coef_index = 0;
+                               do
+                               {
+                                       df [coef_index] = sf [coef_index] + sf [coef_index + 4];
+                                       df [coef_index + 4] = sf [coef_index] - sf [coef_index + 4];
+                                       df [coef_index + 2] = sf [coef_index + 2] * 2;
+                                       df [coef_index + 6] = sf [coef_index + 6] * 2;
+
+                                       df [coef_index + 1] = sf [coef_index + 1] + sf [coef_index + 3];
+                                       df [coef_index + 3] = sf [coef_index + 5] - sf [coef_index + 7];
+
+                                       const flt_t             vr = sf [coef_index + 1] - sf [coef_index + 3];
+                                       const flt_t             vi = sf [coef_index + 5] + sf [coef_index + 7];
+
+                                       df [coef_index + 5] = (vr + vi) * sqrt2_2;
+                                       df [coef_index + 7] = (vi - vr) * sqrt2_2;
+
+                                       coef_index += 8;
+                               }
+                               while (coef_index < _length);
+                       }
+
+                       /* Penultimate and last pass at once */
+                       {
+                               coef_index = 0;
+                               const long *    bit_rev_lut_ptr = _bit_rev_lut.get_ptr ();
+                               const flt_t     *       sf2 = df;
+                               do
+                               {
+                                       {
+                                               const flt_t             b_0 = sf2 [0] + sf2 [2];
+                                               const flt_t             b_2 = sf2 [0] - sf2 [2];
+                                               const flt_t             b_1 = sf2 [1] * 2;
+                                               const flt_t             b_3 = sf2 [3] * 2;
+
+                                               x [bit_rev_lut_ptr [0]] = b_0 + b_1;
+                                               x [bit_rev_lut_ptr [1]] = b_0 - b_1;
+                                               x [bit_rev_lut_ptr [2]] = b_2 + b_3;
+                                               x [bit_rev_lut_ptr [3]] = b_2 - b_3;
+                                       }
+                                       {
+                                               const flt_t             b_0 = sf2 [4] + sf2 [6];
+                                               const flt_t             b_2 = sf2 [4] - sf2 [6];
+                                               const flt_t             b_1 = sf2 [5] * 2;
+                                               const flt_t             b_3 = sf2 [7] * 2;
+
+                                               x [bit_rev_lut_ptr [4]] = b_0 + b_1;
+                                               x [bit_rev_lut_ptr [5]] = b_0 - b_1;
+                                               x [bit_rev_lut_ptr [6]] = b_2 + b_3;
+                                               x [bit_rev_lut_ptr [7]] = b_2 - b_3;
+                                       }
+
+                                       sf2 += 8;
+                                       coef_index += 8;
+                                       bit_rev_lut_ptr += 8;
+                               }
+                               while (coef_index < _length);
+                       }
+               }
+       }
+
+/*______________________________________________
+ *
+ * Special cases
+ *______________________________________________
+ */
+
+       /* 4-point IFFT */
+       else if (_nbr_bits == 2)
+       {
+               const flt_t             b_0 = f [0] + f [2];
+               const flt_t             b_2 = f [0] - f [2];
+
+               x [0] = b_0 + f [1] * 2;
+               x [2] = b_0 - f [1] * 2;
+               x [1] = b_2 + f [3] * 2;
+               x [3] = b_2 - f [3] * 2;
+       }
+
+       /* 2-point IFFT */
+       else if (_nbr_bits == 1)
+       {
+               x [0] = f [0] + f [1];
+               x [1] = f [0] - f [1];
+       }
+
+       /* 1-point IFFT */
+       else
+       {
+               x [0] = f [0];
+       }
+}
+
+
+
+/*==========================================================================*/
+/*      Name: rescale                                                       */
+/*      Description: Scale an array by divide each element by its length.   */
+/*                   This function should be called after FFT + IFFT.       */
+/*      Input/Output parameters:                                            */
+/*        - x: pointer on array to rescale (time or frequency).             */
+/*      Throws: Nothing                                                     */
+/*==========================================================================*/
+
+void   FFTReal::rescale (flt_t x []) const
+{
+       const flt_t             mul = flt_t (1.0 / _length);
+       long                            i = _length - 1;
+
+       do
+       {
+               x [i] *= mul;
+               --i;
+       }
+       while (i >= 0);
+}
+
+
+
+/*\\\ NESTED CLASS MEMBER FUNCTIONS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
+
+
+
+/*==========================================================================*/
+/*      Name: Constructor                                                   */
+/*      Input parameters:                                                   */
+/*        - nbr_bits: number of bits of the array on which we want to do a  */
+/*                    FFT. Range: > 0                                       */
+/*      Throws: std::bad_alloc                                              */
+/*==========================================================================*/
+
+FFTReal::BitReversedLUT::BitReversedLUT (const int nbr_bits)
+{
+       long                            length;
+       long                            cnt;
+       long                            br_index;
+       long                            bit;
+
+       length = 1L << nbr_bits;
+       _ptr = new long [length];
+
+       br_index = 0;
+       _ptr [0] = 0;
+       for (cnt = 1; cnt < length; ++cnt)
+       {
+               /* ++br_index (bit reversed) */
+               bit = length >> 1;
+               while (((br_index ^= bit) & bit) == 0)
+               {
+                       bit >>= 1;
+               }
+
+               _ptr [cnt] = br_index;
+       }
+}
+
+
+
+/*==========================================================================*/
+/*      Name: Destructor                                                    */
+/*==========================================================================*/
+
+FFTReal::BitReversedLUT::~BitReversedLUT (void)
+{
+       delete [] _ptr;
+       _ptr = 0;
+}
+
+
+
+/*==========================================================================*/
+/*      Name: Constructor                                                   */
+/*      Input parameters:                                                   */
+/*        - nbr_bits: number of bits of the array on which we want to do a  */
+/*                    FFT. Range: > 0                                       */
+/*      Throws: std::bad_alloc, anything                                    */
+/*==========================================================================*/
+
+FFTReal::TrigoLUT::TrigoLUT (const int nbr_bits)
+{
+       long            total_len;
+
+       _ptr = 0;
+       if (nbr_bits > 3)
+       {
+               total_len = (1L << (nbr_bits - 1)) - 4;
+               _ptr = new flt_t [total_len];
+
+               const double    PI = atan (1) * 4;
+               for (int level = 3; level < nbr_bits; ++level)
+               {
+                       const long              level_len = 1L << (level - 1);
+                       flt_t   * const level_ptr = const_cast<flt_t *> (get_ptr (level));
+                       const double    mul = PI / (level_len << 1);
+
+                       for (long i = 0; i < level_len; ++ i)
+                       {
+                               level_ptr [i] = (flt_t) cos (i * mul);
+                       }
+               }
+       }
+}
+
+
+
+/*==========================================================================*/
+/*      Name: Destructor                                                    */
+/*==========================================================================*/
+
+FFTReal::TrigoLUT::~TrigoLUT (void)
+{
+       delete [] _ptr;
+       _ptr = 0;
+}
+
+
+
+#if defined (_MSC_VER)
+#pragma pack (pop)
+#endif // _MSC_VER
+
+
+
+/*****************************************************************************
+
+       LEGAL
+
+       Source code may be freely used for any purpose, including commercial
+       applications. Programs must display in their "About" dialog-box (or
+       documentation) a text telling they use these routines by Laurent de Soras.
+       Modified source code can be distributed, but modifications must be clearly
+       indicated.
+
+       CONTACT
+
+       Laurent de Soras
+       92 avenue Albert 1er
+       92500 Rueil-Malmaison
+       France
+
+       ldesoras@club-internet.fr
+
+*****************************************************************************/
+
+
+
+/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
index 56b4e79a39929c146366083fc0776aa98480bd20..50ca93d3f833893e8c9ba59cd1718612a90cca75 100644 (file)
@@ -1,4 +1,4 @@
-The Cepstral SDK for Windows should be placed in c:\dev\cepstral\r
-ex. C:\dev\cepstral\sdk\include\r
-This SDK can be obtained from http://cepstral.com/\r
+The Cepstral SDK for Windows should be placed in c:\dev\cepstral
+ex. C:\dev\cepstral\sdk\include
+This SDK can be obtained from http://cepstral.com/
 If you want a prebuilt version you may download one from http://files.freeswitch.org/windows/installer/
\ No newline at end of file
index d8eb66aecc211035f1c530746a2597ce7e8363e7..5a97ffa87330f26d32ed26dfd730da237f5b935a 100644 (file)
@@ -537,11 +537,11 @@ int gsmopen_serial_init(private_t * tech_pvt, speed_t controldevice_speed)
                NOTICA("SMS=\n%s\n", GSMOPEN_P_LOG, sms->toString().c_str());
 
 #if 0
-            size = MultiByteToWideChar(CP_OEMCP, 0, username, strlen(username)+1, UserName, 0);\r
-            UserName=(wchar_t*)GlobalAlloc(GME­ M_ZEROINIT, size);\r
-            ret = MultiByteToWideChar(CP_OEMCP, 0, username, strlen(username)+1, UserName, size);\r
-            if(ret == 0)\r
-                getError(GetLastError());\r
+            size = MultiByteToWideChar(CP_OEMCP, 0, username, strlen(username)+1, UserName, 0);
+            UserName=(wchar_t*)GlobalAlloc(GME­ M_ZEROINIT, size);
+            ret = MultiByteToWideChar(CP_OEMCP, 0, username, strlen(username)+1, UserName, size);
+            if(ret == 0)
+                getError(GetLastError());
 #endif //0
        return (-1);
 }
index afa50d456776ea192e2cd1549835b19d52ca5d01..d2a909fd7364687c5b173a76a12cde32a31014bc 100644 (file)
@@ -1,17 +1,17 @@
-#ifndef LIBCTB_WIN32_GETOPT_H_INCLUDED_\r
-#define LIBCTB_WIN32_GETOPT_H_INCLUDED_\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// Name:        win32/getopt.h\r
-// Purpose:\r
-// Author:      Joachim Buermann\r
-// Copyright:   (c) 2010 Joachim Buermann\r
-// Licence:     wxWindows licence\r
-/////////////////////////////////////////////////////////////////////////////\r
-\r
-extern char* optarg;\r
-extern int optind;\r
-\r
-int getopt(int argc, char* argv[], char* optstring);\r
-\r
-#endif\r
+#ifndef LIBCTB_WIN32_GETOPT_H_INCLUDED_
+#define LIBCTB_WIN32_GETOPT_H_INCLUDED_
+
+/////////////////////////////////////////////////////////////////////////////
+// Name:        win32/getopt.h
+// Purpose:
+// Author:      Joachim Buermann
+// Copyright:   (c) 2010 Joachim Buermann
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+extern char* optarg;
+extern int optind;
+
+int getopt(int argc, char* argv[], char* optstring);
+
+#endif
index 627b30acfa51156e08472703c600d8992432089a..307c6ce001c573e93b38adb41f138decb71f10e4 100644 (file)
-/*\r
- *\r
- *\r
- *                     Win32 include file\r
- *          for accessing the 32-bit GPIB DLL (gpib-32.dll)\r
- *\r
- *\r
- *         Contains user variables (ibsta, iberr, ibcnt, ibcntl),\r
- *         function prototypes and useful defined constants for\r
- *         calling NI-488 and NI-488.2 routines from a Microsoft\r
- *         C/C++ Win32 application.\r
- *\r
- *\r
- *            Copyright 1998 National Instruments Corporation\r
- *\r
- */\r
-\r
-#ifndef DECL_32_H       // ensure we are only included once\r
-#define DECL_32_H\r
-\r
-#include "windows.h"\r
-\r
-#ifdef __cplusplus\r
-extern "C" {\r
-#endif\r
-\r
-\r
-/***************************************************************************/\r
-/*    HANDY CONSTANTS FOR USE BY APPLICATION PROGRAMS ...                  */\r
-/***************************************************************************/\r
-#define UNL  0x3f  /* GPIB unlisten command                */\r
-#define UNT  0x5f  /* GPIB untalk command                  */\r
-#define GTL  0x01  /* GPIB go to local                     */\r
-#define SDC  0x04  /* GPIB selected device clear           */\r
-#define PPC  0x05  /* GPIB parallel poll configure         */\r
-#define GET  0x08  /* GPIB group execute trigger           */\r
-#define TCT  0x09  /* GPIB take control                    */\r
-#define LLO  0x11  /* GPIB local lock out                  */\r
-#define DCL  0x14  /* GPIB device clear                    */\r
-#define PPU  0.16  /* GPIB parallel poll unconfigure       */\r
-#define SPE  0x18  /* GPIB serial poll enable              */\r
-#define SPD  0x19  /* GPIB serial poll disable             */\r
-#define PPE  0x60  /* GPIB parallel poll enable            */\r
-#define PPD  0x70  /* GPIB parallel poll disable           */\r
-\r
-/* GPIB status bit vector :                                */\r
-/*       global variable ibsta and wait mask               */\r
-\r
-#define ERR     (1<<15) /* Error detected                  */\r
-#define TIMO    (1<<14) /* Timeout                         */\r
-#define END     (1<<13) /* EOI or EOS detected             */\r
-#define SRQI    (1<<12) /* SRQ detected by CIC             */\r
-#define RQS     (1<<11) /* Device needs service            */\r
-#define CMPL    (1<<8)  /* I/O completed                   */\r
-#define LOK     (1<<7)  /* Local lockout state             */\r
-#define REM     (1<<6)  /* Remote state                    */\r
-#define CIC     (1<<5)  /* Controller-in-Charge            */\r
-#define ATN     (1<<4)  /* Attention asserted              */\r
-#define TACS    (1<<3)  /* Talker active                   */\r
-#define LACS    (1<<2)  /* Listener active                 */\r
-#define DTAS    (1<<1)  /* Device trigger state            */\r
-#define DCAS    (1<<0)  /* Device clear state              */\r
-\r
-/* Error messages returned in global variable iberr        */\r
-\r
-#define EDVR  0  /* System error                           */\r
-#define ECIC  1  /* Function requires GPIB board to be CIC */\r
-#define ENOL  2  /* Write function detected no Listeners   */\r
-#define EADR  3  /* Interface board not addressed correctly*/\r
-#define EARG  4  /* Invalid argument to function call      */\r
-#define ESAC  5  /* Function requires GPIB board to be SAC */\r
-#define EABO  6  /* I/O operation aborted                  */\r
-#define ENEB  7  /* Non-existent interface board           */\r
-#define EDMA  8  /* Error performing DMA                   */\r
-#define EOIP 10  /* I/O operation started before previous  */\r
-                 /* operation completed                    */\r
-#define ECAP 11  /* No capability for intended operation   */\r
-#define EFSO 12  /* File system operation error            */\r
-#define EBUS 14  /* Command error during device call       */\r
-#define ESTB 15  /* Serial poll status byte lost           */\r
-#define ESRQ 16  /* SRQ remains asserted                   */\r
-#define ETAB 20  /* The return buffer is full.             */\r
-#define ELCK 21  /* Address or board is locked.            */\r
-\r
-/* EOS mode bits                                           */\r
-\r
-#define BIN  (1<<12) /* Eight bit compare                  */\r
-#define XEOS (1<<11) /* Send END with EOS byte             */\r
-#define REOS (1<<10) /* Terminate read on EOS              */\r
-\r
-/* Timeout values and meanings                             */\r
-\r
-#define TNONE    0   /* Infinite timeout (disabled)        */\r
-#define T10us    1   /* Timeout of 10 us (ideal)           */\r
-#define T30us    2   /* Timeout of 30 us (ideal)           */\r
-#define T100us   3   /* Timeout of 100 us (ideal)          */\r
-#define T300us   4   /* Timeout of 300 us (ideal)          */\r
-#define T1ms     5   /* Timeout of 1 ms (ideal)            */\r
-#define T3ms     6   /* Timeout of 3 ms (ideal)            */\r
-#define T10ms    7   /* Timeout of 10 ms (ideal)           */\r
-#define T30ms    8   /* Timeout of 30 ms (ideal)           */\r
-#define T100ms   9   /* Timeout of 100 ms (ideal)          */\r
-#define T300ms  10   /* Timeout of 300 ms (ideal)          */\r
-#define T1s     11   /* Timeout of 1 s (ideal)             */\r
-#define T3s     12   /* Timeout of 3 s (ideal)             */\r
-#define T10s    13   /* Timeout of 10 s (ideal)            */\r
-#define T30s    14   /* Timeout of 30 s (ideal)            */\r
-#define T100s   15   /* Timeout of 100 s (ideal)           */\r
-#define T300s   16   /* Timeout of 300 s (ideal)           */\r
-#define T1000s  17   /* Timeout of 1000 s (ideal)          */\r
-\r
-\r
-/*  IBLN Constants                                         */\r
-#define NO_SAD   0\r
-#define ALL_SAD -1\r
-\r
-\r
-/*  The following constants are used for the second parameter of the\r
- *  ibconfig function.  They are the "option" selection codes.\r
- */\r
-#define  IbcPAD        0x0001      /* Primary Address                      */\r
-#define  IbcSAD        0x0002      /* Secondary Address                    */\r
-#define  IbcTMO        0x0003      /* Timeout Value                        */\r
-#define  IbcEOT        0x0004      /* Send EOI with last data byte?        */\r
-#define  IbcPPC        0x0005      /* Parallel Poll Configure              */\r
-#define  IbcREADDR     0x0006      /* Repeat Addressing                    */\r
-#define  IbcAUTOPOLL   0x0007      /* Disable Auto Serial Polling          */\r
-#define  IbcCICPROT    0x0008      /* Use the CIC Protocol?                */\r
-#define  IbcIRQ        0x0009      /* Use PIO for I/O                      */\r
-#define  IbcSC         0x000A      /* Board is System Controller?          */\r
-#define  IbcSRE        0x000B      /* Assert SRE on device calls?          */\r
-#define  IbcEOSrd      0x000C      /* Terminate reads on EOS               */\r
-#define  IbcEOSwrt     0x000D      /* Send EOI with EOS character          */\r
-#define  IbcEOScmp     0x000E      /* Use 7 or 8-bit EOS compare           */\r
-#define  IbcEOSchar    0x000F      /* The EOS character.                   */\r
-#define  IbcPP2        0x0010      /* Use Parallel Poll Mode 2.            */\r
-#define  IbcTIMING     0x0011      /* NORMAL, HIGH, or VERY_HIGH timing.   */\r
-#define  IbcDMA        0x0012      /* Use DMA for I/O                      */\r
-#define  IbcReadAdjust 0x0013      /* Swap bytes during an ibrd.           */\r
-#define  IbcWriteAdjust 0x014      /* Swap bytes during an ibwrt.          */\r
-#define  IbcSendLLO    0x0017      /* Enable/disable the sending of LLO.      */\r
-#define  IbcSPollTime  0x0018      /* Set the timeout value for serial polls. */\r
-#define  IbcPPollTime  0x0019      /* Set the parallel poll length period.    */\r
-#define  IbcEndBitIsNormal 0x001A  /* Remove EOS from END bit of IBSTA.       */\r
-#define  IbcUnAddr         0x001B  /* Enable/disable device unaddressing.     */\r
-#define  IbcSignalNumber   0x001C  /* Set UNIX signal number - unsupported */\r
-#define  IbcBlockIfLocked  0x001D   /* Enable/disable blocking for locked boards/devices         */\r
-#define  IbcHSCableLength  0x001F  /* Length of cable specified for high speed timing.*/\r
-#define  IbcIst        0x0020      /* Set the IST bit.                     */\r
-#define  IbcRsv        0x0021      /* Set the RSV byte.                    */\r
-\r
-/*\r
- *    Constants that can be used (in addition to the ibconfig constants)\r
- *    when calling the ibask() function.\r
- */\r
-\r
-#define  IbaPAD            IbcPAD\r
-#define  IbaSAD            IbcSAD\r
-#define  IbaTMO            IbcTMO\r
-#define  IbaEOT            IbcEOT\r
-#define  IbaPPC            IbcPPC\r
-#define  IbaREADDR         IbcREADDR\r
-#define  IbaAUTOPOLL       IbcAUTOPOLL\r
-#define  IbaCICPROT        IbcCICPROT\r
-#define  IbaIRQ            IbcIRQ\r
-#define  IbaSC             IbcSC\r
-#define  IbaSRE            IbcSRE\r
-#define  IbaEOSrd          IbcEOSrd\r
-#define  IbaEOSwrt         IbcEOSwrt\r
-#define  IbaEOScmp         IbcEOScmp\r
-#define  IbaEOSchar        IbcEOSchar\r
-#define  IbaPP2            IbcPP2\r
-#define  IbaTIMING         IbcTIMING\r
-#define  IbaDMA            IbcDMA\r
-#define  IbaReadAdjust     IbcReadAdjust\r
-#define  IbaWriteAdjust    IbcWriteAdjust\r
-#define  IbaSendLLO        IbcSendLLO\r
-#define  IbaSPollTime      IbcSPollTime\r
-#define  IbaPPollTime      IbcPPollTime\r
-#define  IbaEndBitIsNormal IbcEndBitIsNormal\r
-#define  IbaUnAddr         IbcUnAddr\r
-#define  IbaSignalNumber   IbcSignalNumber\r
-#define  IbaBlockIfLocked  IbcBlockIfLocked\r
-#define  IbaHSCableLength  IbcHSCableLength\r
-#define  IbaIst            IbcIst\r
-#define  IbaRsv            IbcRsv\r
-\r
-#define  IbaBNA            0x0200   /* A device's access board.                  */\r
-\r
-\r
-/* Values used by the Send 488.2 command. */\r
-#define  NULLend 0x00  /* Do nothing at the end of a transfer.*/\r
-#define  NLend   0x01  /* Send NL with EOI after a transfer.  */\r
-#define  DABend  0x02  /* Send EOI with the last DAB.         */\r
-\r
-/* Value used by the 488.2 Receive command.\r
- */\r
-#define  STOPend     0x0100\r
-\r
-\r
-/* Address type (for 488.2 calls) */\r
-\r
-typedef short Addr4882_t;       /* System dependent: must be 16 bits */\r
-\r
-/*\r
- *  This macro can be used to easily create an entry in address list\r
- *  that is required by many of the 488.2 functions. The primary address goes in the\r
- *  lower 8-bits and the secondary address goes in the upper 8-bits.\r
- */\r
-#define  MakeAddr(pad, sad)   ((Addr4882_t)(((pad)&0xFF) | ((sad)<<8)))\r
-\r
-/*\r
- *  This value is used to terminate an address list.  It should be\r
- *  assigned to the last entry.\r
- */\r
-#ifndef NOADDR\r
-#define  NOADDR    (Addr4882_t)((unsigned short)0xFFFF)\r
-#endif\r
-\r
-/*\r
- *  The following two macros are used to "break apart" an address list\r
- *  entry.  They take an unsigned integer and return either the primary\r
- *  or secondary address stored in the integer.\r
- */\r
-#define  GetPAD(val)    ((val) & 0xFF)\r
-#define  GetSAD(val)    (((val) >> 8) & 0xFF)\r
-\r
-/* iblines constants */\r
-\r
-#define  ValidEOI   (short)0x0080\r
-#define  ValidATN   (short)0x0040\r
-#define  ValidSRQ   (short)0x0020\r
-#define  ValidREN   (short)0x0010\r
-#define  ValidIFC   (short)0x0008\r
-#define  ValidNRFD  (short)0x0004\r
-#define  ValidNDAC  (short)0x0002\r
-#define  ValidDAV   (short)0x0001\r
-#define  BusEOI     (short)0x8000\r
-#define  BusATN     (short)0x4000\r
-#define  BusSRQ     (short)0x2000\r
-#define  BusREN     (short)0x1000\r
-#define  BusIFC     (short)0x0800\r
-#define  BusNRFD    (short)0x0400\r
-#define  BusNDAC    (short)0x0200\r
-#define  BusDAV     (short)0x0100\r
-\r
-/****\r
- **** typedef for ibnotify callback ****\r
- ****/\r
-typedef int (__stdcall * GpibNotifyCallback_t)(int, int, int, long, PVOID);\r
-\r
-#define IBNOTIFY_REARM_FAILED    0xE00A003F\r
-\r
-\r
-/*************************************************************************/\r
-/*                                                                       */\r
-/*  iblockx and ibunlockx definitions --- for use with GPIB-ENET only !! */\r
-/*                                                                       */\r
-/*************************************************************************/\r
-#define  TIMMEDIATE                 -1\r
-#define  TINFINITE                  -2\r
-#define  MAX_LOCKSHARENAME_LENGTH   64\r
-\r
-#if defined(UNICODE)\r
-   #define iblockx iblockxW\r
-#else\r
-   #define iblockx iblockxA\r
-#endif\r
-\r
-extern int __stdcall iblockxA (int ud, int LockWaitTime, PCHAR LockShareName);\r
-extern int __stdcall iblockxW (int ud, int LockWaitTime, PWCHAR LockShareName);\r
-extern int __stdcall ibunlockx (int ud);\r
-\r
-\r
-/***************************************************************************/\r
-/*         IBSTA, IBERR, IBCNT, IBCNTL and FUNCTION PROTOTYPES             */\r
-/*      ( only included if not accessing the 32-bit DLL directly )         */\r
-/***************************************************************************/\r
-#if !defined(GPIB_DIRECT_ACCESS)\r
-\r
-/*\r
- *  Set up access to the user variables (ibsta, iberr, ibcnt, ibcntl).\r
- *  These are declared and exported by the 32-bit DLL.  Separate copies\r
- *  exist for each process that accesses the DLL.  They are shared by\r
- *  multiple threads of a single process.\r
- */\r
-\r
-extern int  ibsta;\r
-extern int  iberr;\r
-extern int  ibcnt;\r
-extern long ibcntl;\r
-\r
-\r
-#if defined(UNICODE)\r
-   #define ibbna  ibbnaW\r
-   #define ibfind ibfindW\r
-   #define ibrdf  ibrdfW\r
-   #define ibwrtf ibwrtfW\r
-#else\r
-   #define ibbna  ibbnaA\r
-   #define ibfind ibfindA\r
-   #define ibrdf  ibrdfA\r
-   #define ibwrtf ibwrtfA\r
-#endif\r
-\r
-/*\r
- *  Extern 32-bit GPIB DLL functions\r
- */\r
-\r
-/*  NI-488 Function Prototypes  */\r
-extern int __stdcall ibfindA   (LPCSTR udname);\r
-extern int __stdcall ibbnaA    (int ud, LPCSTR udname);\r
-extern int __stdcall ibrdfA    (int ud, LPCSTR filename);\r
-extern int __stdcall ibwrtfA   (int ud, LPCSTR filename);\r
-\r
-extern int __stdcall ibfindW   (LPCWSTR udname);\r
-extern int __stdcall ibbnaW    (int ud, LPCWSTR udname);\r
-extern int __stdcall ibrdfW    (int ud, LPCWSTR filename);\r
-extern int __stdcall ibwrtfW   (int ud, LPCWSTR filename);\r
-\r
-extern int __stdcall ibask    (int ud, int option, PINT v);\r
-extern int __stdcall ibcac    (int ud, int v);\r
-extern int __stdcall ibclr    (int ud);\r
-extern int __stdcall ibcmd    (int ud, PVOID buf, long cnt);\r
-extern int __stdcall ibcmda   (int ud, PVOID buf, long cnt);\r
-extern int __stdcall ibconfig (int ud, int option, int v);\r
-extern int __stdcall ibdev    (int boardID, int pad, int sad, int tmo, int eot, int eos);\r
-extern int __stdcall ibdiag   (int ud, PVOID buf, long cnt);\r
-extern int __stdcall ibdma    (int ud, int v);\r
-extern int __stdcall ibeos    (int ud, int v);\r
-extern int __stdcall ibeot    (int ud, int v);\r
-extern int __stdcall ibgts    (int ud, int v);\r
-extern int __stdcall ibist    (int ud, int v);\r
-extern int __stdcall iblines  (int ud, PSHORT result);\r
-extern int __stdcall ibln     (int ud, int pad, int sad, PSHORT listen);\r
-extern int __stdcall ibloc    (int ud);\r
-extern int __stdcall ibnotify (int ud, int mask, GpibNotifyCallback_t Callback, PVOID RefData);\r
-extern int __stdcall ibonl    (int ud, int v);\r
-extern int __stdcall ibpad    (int ud, int v);\r
-extern int __stdcall ibpct    (int ud);\r
-extern int __stdcall ibpoke   (int ud, long option, long v);\r
-extern int __stdcall ibppc    (int ud, int v);\r
-extern int __stdcall ibrd     (int ud, PVOID buf, long cnt);\r
-extern int __stdcall ibrda    (int ud, PVOID buf, long cnt);\r
-extern int __stdcall ibrpp    (int ud, PCHAR ppr);\r
-extern int __stdcall ibrsc    (int ud, int v);\r
-extern int __stdcall ibrsp    (int ud, PCHAR spr);\r
-extern int __stdcall ibrsv    (int ud, int v);\r
-extern int __stdcall ibsad    (int ud, int v);\r
-extern int __stdcall ibsic    (int ud);\r
-extern int __stdcall ibsre    (int ud, int v);\r
-extern int __stdcall ibstop   (int ud);\r
-extern int __stdcall ibtmo    (int ud, int v);\r
-extern int __stdcall ibtrg    (int ud);\r
-extern int __stdcall ibwait   (int ud, int mask);\r
-extern int __stdcall ibwrt    (int ud, PVOID buf, long cnt);\r
-extern int __stdcall ibwrta   (int ud, PVOID buf, long cnt);\r
-\r
-// GPIB-ENET only functions to support locking across machines\r
-extern int __stdcall iblock   (int ud);\r
-extern int __stdcall ibunlock (int ud);\r
-\r
-/**************************************************************************/\r
-/*  Functions to access Thread-Specific copies of the GPIB global vars */\r
-\r
-extern int  __stdcall ThreadIbsta (void);\r
-extern int  __stdcall ThreadIberr (void);\r
-extern int  __stdcall ThreadIbcnt (void);\r
-extern long __stdcall ThreadIbcntl (void);\r
-\r
-\r
-/**************************************************************************/\r
-/*  NI-488.2 Function Prototypes  */\r
-\r
-extern void __stdcall AllSpoll      (int boardID, Addr4882_t * addrlist, PSHORT results);\r
-extern void __stdcall DevClear      (int boardID, Addr4882_t addr);\r
-extern void __stdcall DevClearList  (int boardID, Addr4882_t * addrlist);\r
-extern void __stdcall EnableLocal   (int boardID, Addr4882_t * addrlist);\r
-extern void __stdcall EnableRemote  (int boardID, Addr4882_t * addrlist);\r
-extern void __stdcall FindLstn      (int boardID, Addr4882_t * addrlist, Addr4882_t * results, int limit);\r
-extern void __stdcall FindRQS       (int boardID, Addr4882_t * addrlist, PSHORT dev_stat);\r
-extern void __stdcall PPoll         (int boardID, PSHORT result);\r
-extern void __stdcall PPollConfig   (int boardID, Addr4882_t addr, int dataLine, int lineSense);\r
-extern void __stdcall PPollUnconfig (int boardID, Addr4882_t * addrlist);\r
-extern void __stdcall PassControl   (int boardID, Addr4882_t addr);\r
-extern void __stdcall RcvRespMsg    (int boardID, PVOID buffer, long cnt, int Termination);\r
-extern void __stdcall ReadStatusByte(int boardID, Addr4882_t addr, PSHORT result);\r
-extern void __stdcall Receive       (int boardID, Addr4882_t addr, PVOID buffer, long cnt, int Termination);\r
-extern void __stdcall ReceiveSetup  (int boardID, Addr4882_t addr);\r
-extern void __stdcall ResetSys      (int boardID, Addr4882_t * addrlist);\r
-extern void __stdcall Send          (int boardID, Addr4882_t addr, PVOID databuf, long datacnt, int eotMode);\r
-extern void __stdcall SendCmds      (int boardID, PVOID buffer, long cnt);\r
-extern void __stdcall SendDataBytes (int boardID, PVOID buffer, long cnt, int eot_mode);\r
-extern void __stdcall SendIFC       (int boardID);\r
-extern void __stdcall SendLLO       (int boardID);\r
-extern void __stdcall SendList      (int boardID, Addr4882_t * addrlist, PVOID databuf, long datacnt, int eotMode);\r
-extern void __stdcall SendSetup     (int boardID, Addr4882_t * addrlist);\r
-extern void __stdcall SetRWLS       (int boardID, Addr4882_t * addrlist);\r
-extern void __stdcall TestSRQ       (int boardID, PSHORT result);\r
-extern void __stdcall TestSys       (int boardID, Addr4882_t * addrlist, PSHORT results);\r
-extern void __stdcall Trigger       (int boardID, Addr4882_t addr);\r
-extern void __stdcall TriggerList   (int boardID, Addr4882_t * addrlist);\r
-extern void __stdcall WaitSRQ       (int boardID, PSHORT result);\r
-\r
-#endif\r
-\r
-\r
-#ifdef __cplusplus\r
-}\r
-#endif\r
-\r
-\r
-#endif   // DECL_32_H\r
-\r
+/*
+ *
+ *
+ *                     Win32 include file
+ *          for accessing the 32-bit GPIB DLL (gpib-32.dll)
+ *
+ *
+ *         Contains user variables (ibsta, iberr, ibcnt, ibcntl),
+ *         function prototypes and useful defined constants for
+ *         calling NI-488 and NI-488.2 routines from a Microsoft
+ *         C/C++ Win32 application.
+ *
+ *
+ *            Copyright 1998 National Instruments Corporation
+ *
+ */
+
+#ifndef DECL_32_H       // ensure we are only included once
+#define DECL_32_H
+
+#include "windows.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/***************************************************************************/
+/*    HANDY CONSTANTS FOR USE BY APPLICATION PROGRAMS ...                  */
+/***************************************************************************/
+#define UNL  0x3f  /* GPIB unlisten command                */
+#define UNT  0x5f  /* GPIB untalk command                  */
+#define GTL  0x01  /* GPIB go to local                     */
+#define SDC  0x04  /* GPIB selected device clear           */
+#define PPC  0x05  /* GPIB parallel poll configure         */
+#define GET  0x08  /* GPIB group execute trigger           */
+#define TCT  0x09  /* GPIB take control                    */
+#define LLO  0x11  /* GPIB local lock out                  */
+#define DCL  0x14  /* GPIB device clear                    */
+#define PPU  0.16  /* GPIB parallel poll unconfigure       */
+#define SPE  0x18  /* GPIB serial poll enable              */
+#define SPD  0x19  /* GPIB serial poll disable             */
+#define PPE  0x60  /* GPIB parallel poll enable            */
+#define PPD  0x70  /* GPIB parallel poll disable           */
+
+/* GPIB status bit vector :                                */
+/*       global variable ibsta and wait mask               */
+
+#define ERR     (1<<15) /* Error detected                  */
+#define TIMO    (1<<14) /* Timeout                         */
+#define END     (1<<13) /* EOI or EOS detected             */
+#define SRQI    (1<<12) /* SRQ detected by CIC             */
+#define RQS     (1<<11) /* Device needs service            */
+#define CMPL    (1<<8)  /* I/O completed                   */
+#define LOK     (1<<7)  /* Local lockout state             */
+#define REM     (1<<6)  /* Remote state                    */
+#define CIC     (1<<5)  /* Controller-in-Charge            */
+#define ATN     (1<<4)  /* Attention asserted              */
+#define TACS    (1<<3)  /* Talker active                   */
+#define LACS    (1<<2)  /* Listener active                 */
+#define DTAS    (1<<1)  /* Device trigger state            */
+#define DCAS    (1<<0)  /* Device clear state              */
+
+/* Error messages returned in global variable iberr        */
+
+#define EDVR  0  /* System error                           */
+#define ECIC  1  /* Function requires GPIB board to be CIC */
+#define ENOL  2  /* Write function detected no Listeners   */
+#define EADR  3  /* Interface board not addressed correctly*/
+#define EARG  4  /* Invalid argument to function call      */
+#define ESAC  5  /* Function requires GPIB board to be SAC */
+#define EABO  6  /* I/O operation aborted                  */
+#define ENEB  7  /* Non-existent interface board           */
+#define EDMA  8  /* Error performing DMA                   */
+#define EOIP 10  /* I/O operation started before previous  */
+                 /* operation completed                    */
+#define ECAP 11  /* No capability for intended operation   */
+#define EFSO 12  /* File system operation error            */
+#define EBUS 14  /* Command error during device call       */
+#define ESTB 15  /* Serial poll status byte lost           */
+#define ESRQ 16  /* SRQ remains asserted                   */
+#define ETAB 20  /* The return buffer is full.             */
+#define ELCK 21  /* Address or board is locked.            */
+
+/* EOS mode bits                                           */
+
+#define BIN  (1<<12) /* Eight bit compare                  */
+#define XEOS (1<<11) /* Send END with EOS byte             */
+#define REOS (1<<10) /* Terminate read on EOS              */
+
+/* Timeout values and meanings                             */
+
+#define TNONE    0   /* Infinite timeout (disabled)        */
+#define T10us    1   /* Timeout of 10 us (ideal)           */
+#define T30us    2   /* Timeout of 30 us (ideal)           */
+#define T100us   3   /* Timeout of 100 us (ideal)          */
+#define T300us   4   /* Timeout of 300 us (ideal)          */
+#define T1ms     5   /* Timeout of 1 ms (ideal)            */
+#define T3ms     6   /* Timeout of 3 ms (ideal)            */
+#define T10ms    7   /* Timeout of 10 ms (ideal)           */
+#define T30ms    8   /* Timeout of 30 ms (ideal)           */
+#define T100ms   9   /* Timeout of 100 ms (ideal)          */
+#define T300ms  10   /* Timeout of 300 ms (ideal)          */
+#define T1s     11   /* Timeout of 1 s (ideal)             */
+#define T3s     12   /* Timeout of 3 s (ideal)             */
+#define T10s    13   /* Timeout of 10 s (ideal)            */
+#define T30s    14   /* Timeout of 30 s (ideal)            */
+#define T100s   15   /* Timeout of 100 s (ideal)           */
+#define T300s   16   /* Timeout of 300 s (ideal)           */
+#define T1000s  17   /* Timeout of 1000 s (ideal)          */
+
+
+/*  IBLN Constants                                         */
+#define NO_SAD   0
+#define ALL_SAD -1
+
+
+/*  The following constants are used for the second parameter of the
+ *  ibconfig function.  They are the "option" selection codes.
+ */
+#define  IbcPAD        0x0001      /* Primary Address                      */
+#define  IbcSAD        0x0002      /* Secondary Address                    */
+#define  IbcTMO        0x0003      /* Timeout Value                        */
+#define  IbcEOT        0x0004      /* Send EOI with last data byte?        */
+#define  IbcPPC        0x0005      /* Parallel Poll Configure              */
+#define  IbcREADDR     0x0006      /* Repeat Addressing                    */
+#define  IbcAUTOPOLL   0x0007      /* Disable Auto Serial Polling          */
+#define  IbcCICPROT    0x0008      /* Use the CIC Protocol?                */
+#define  IbcIRQ        0x0009      /* Use PIO for I/O                      */
+#define  IbcSC         0x000A      /* Board is System Controller?          */
+#define  IbcSRE        0x000B      /* Assert SRE on device calls?          */
+#define  IbcEOSrd      0x000C      /* Terminate reads on EOS               */
+#define  IbcEOSwrt     0x000D      /* Send EOI with EOS character          */
+#define  IbcEOScmp     0x000E      /* Use 7 or 8-bit EOS compare           */
+#define  IbcEOSchar    0x000F      /* The EOS character.                   */
+#define  IbcPP2        0x0010      /* Use Parallel Poll Mode 2.            */
+#define  IbcTIMING     0x0011      /* NORMAL, HIGH, or VERY_HIGH timing.   */
+#define  IbcDMA        0x0012      /* Use DMA for I/O                      */
+#define  IbcReadAdjust 0x0013      /* Swap bytes during an ibrd.           */
+#define  IbcWriteAdjust 0x014      /* Swap bytes during an ibwrt.          */
+#define  IbcSendLLO    0x0017      /* Enable/disable the sending of LLO.      */
+#define  IbcSPollTime  0x0018      /* Set the timeout value for serial polls. */
+#define  IbcPPollTime  0x0019      /* Set the parallel poll length period.    */
+#define  IbcEndBitIsNormal 0x001A  /* Remove EOS from END bit of IBSTA.       */
+#define  IbcUnAddr         0x001B  /* Enable/disable device unaddressing.     */
+#define  IbcSignalNumber   0x001C  /* Set UNIX signal number - unsupported */
+#define  IbcBlockIfLocked  0x001D   /* Enable/disable blocking for locked boards/devices         */
+#define  IbcHSCableLength  0x001F  /* Length of cable specified for high speed timing.*/
+#define  IbcIst        0x0020      /* Set the IST bit.                     */
+#define  IbcRsv        0x0021      /* Set the RSV byte.                    */
+
+/*
+ *    Constants that can be used (in addition to the ibconfig constants)
+ *    when calling the ibask() function.
+ */
+
+#define  IbaPAD            IbcPAD
+#define  IbaSAD            IbcSAD
+#define  IbaTMO            IbcTMO
+#define  IbaEOT            IbcEOT
+#define  IbaPPC            IbcPPC
+#define  IbaREADDR         IbcREADDR
+#define  IbaAUTOPOLL       IbcAUTOPOLL
+#define  IbaCICPROT        IbcCICPROT
+#define  IbaIRQ            IbcIRQ
+#define  IbaSC             IbcSC
+#define  IbaSRE            IbcSRE
+#define  IbaEOSrd          IbcEOSrd
+#define  IbaEOSwrt         IbcEOSwrt
+#define  IbaEOScmp         IbcEOScmp
+#define  IbaEOSchar        IbcEOSchar
+#define  IbaPP2            IbcPP2
+#define  IbaTIMING         IbcTIMING
+#define  IbaDMA            IbcDMA
+#define  IbaReadAdjust     IbcReadAdjust
+#define  IbaWriteAdjust    IbcWriteAdjust
+#define  IbaSendLLO        IbcSendLLO
+#define  IbaSPollTime      IbcSPollTime
+#define  IbaPPollTime      IbcPPollTime
+#define  IbaEndBitIsNormal IbcEndBitIsNormal
+#define  IbaUnAddr         IbcUnAddr
+#define  IbaSignalNumber   IbcSignalNumber
+#define  IbaBlockIfLocked  IbcBlockIfLocked
+#define  IbaHSCableLength  IbcHSCableLength
+#define  IbaIst            IbcIst
+#define  IbaRsv            IbcRsv
+
+#define  IbaBNA            0x0200   /* A device's access board.                  */
+
+
+/* Values used by the Send 488.2 command. */
+#define  NULLend 0x00  /* Do nothing at the end of a transfer.*/
+#define  NLend   0x01  /* Send NL with EOI after a transfer.  */
+#define  DABend  0x02  /* Send EOI with the last DAB.         */
+
+/* Value used by the 488.2 Receive command.
+ */
+#define  STOPend     0x0100
+
+
+/* Address type (for 488.2 calls) */
+
+typedef short Addr4882_t;       /* System dependent: must be 16 bits */
+
+/*
+ *  This macro can be used to easily create an entry in address list
+ *  that is required by many of the 488.2 functions. The primary address goes in the
+ *  lower 8-bits and the secondary address goes in the upper 8-bits.
+ */
+#define  MakeAddr(pad, sad)   ((Addr4882_t)(((pad)&0xFF) | ((sad)<<8)))
+
+/*
+ *  This value is used to terminate an address list.  It should be
+ *  assigned to the last entry.
+ */
+#ifndef NOADDR
+#define  NOADDR    (Addr4882_t)((unsigned short)0xFFFF)
+#endif
+
+/*
+ *  The following two macros are used to "break apart" an address list
+ *  entry.  They take an unsigned integer and return either the primary
+ *  or secondary address stored in the integer.
+ */
+#define  GetPAD(val)    ((val) & 0xFF)
+#define  GetSAD(val)    (((val) >> 8) & 0xFF)
+
+/* iblines constants */
+
+#define  ValidEOI   (short)0x0080
+#define  ValidATN   (short)0x0040
+#define  ValidSRQ   (short)0x0020
+#define  ValidREN   (short)0x0010
+#define  ValidIFC   (short)0x0008
+#define  ValidNRFD  (short)0x0004
+#define  ValidNDAC  (short)0x0002
+#define  ValidDAV   (short)0x0001
+#define  BusEOI     (short)0x8000
+#define  BusATN     (short)0x4000
+#define  BusSRQ     (short)0x2000
+#define  BusREN     (short)0x1000
+#define  BusIFC     (short)0x0800
+#define  BusNRFD    (short)0x0400
+#define  BusNDAC    (short)0x0200
+#define  BusDAV     (short)0x0100
+
+/****
+ **** typedef for ibnotify callback ****
+ ****/
+typedef int (__stdcall * GpibNotifyCallback_t)(int, int, int, long, PVOID);
+
+#define IBNOTIFY_REARM_FAILED    0xE00A003F
+
+
+/*************************************************************************/
+/*                                                                       */
+/*  iblockx and ibunlockx definitions --- for use with GPIB-ENET only !! */
+/*                                                                       */
+/*************************************************************************/
+#define  TIMMEDIATE                 -1
+#define  TINFINITE                  -2
+#define  MAX_LOCKSHARENAME_LENGTH   64
+
+#if defined(UNICODE)
+   #define iblockx iblockxW
+#else
+   #define iblockx iblockxA
+#endif
+
+extern int __stdcall iblockxA (int ud, int LockWaitTime, PCHAR LockShareName);
+extern int __stdcall iblockxW (int ud, int LockWaitTime, PWCHAR LockShareName);
+extern int __stdcall ibunlockx (int ud);
+
+
+/***************************************************************************/
+/*         IBSTA, IBERR, IBCNT, IBCNTL and FUNCTION PROTOTYPES             */
+/*      ( only included if not accessing the 32-bit DLL directly )         */
+/***************************************************************************/
+#if !defined(GPIB_DIRECT_ACCESS)
+
+/*
+ *  Set up access to the user variables (ibsta, iberr, ibcnt, ibcntl).
+ *  These are declared and exported by the 32-bit DLL.  Separate copies
+ *  exist for each process that accesses the DLL.  They are shared by
+ *  multiple threads of a single process.
+ */
+
+extern int  ibsta;
+extern int  iberr;
+extern int  ibcnt;
+extern long ibcntl;
+
+
+#if defined(UNICODE)
+   #define ibbna  ibbnaW
+   #define ibfind ibfindW
+   #define ibrdf  ibrdfW
+   #define ibwrtf ibwrtfW
+#else
+   #define ibbna  ibbnaA
+   #define ibfind ibfindA
+   #define ibrdf  ibrdfA
+   #define ibwrtf ibwrtfA
+#endif
+
+/*
+ *  Extern 32-bit GPIB DLL functions
+ */
+
+/*  NI-488 Function Prototypes  */
+extern int __stdcall ibfindA   (LPCSTR udname);
+extern int __stdcall ibbnaA    (int ud, LPCSTR udname);
+extern int __stdcall ibrdfA    (int ud, LPCSTR filename);
+extern int __stdcall ibwrtfA   (int ud, LPCSTR filename);
+
+extern int __stdcall ibfindW   (LPCWSTR udname);
+extern int __stdcall ibbnaW    (int ud, LPCWSTR udname);
+extern int __stdcall ibrdfW    (int ud, LPCWSTR filename);
+extern int __stdcall ibwrtfW   (int ud, LPCWSTR filename);
+
+extern int __stdcall ibask    (int ud, int option, PINT v);
+extern int __stdcall ibcac    (int ud, int v);
+extern int __stdcall ibclr    (int ud);
+extern int __stdcall ibcmd    (int ud, PVOID buf, long cnt);
+extern int __stdcall ibcmda   (int ud, PVOID buf, long cnt);
+extern int __stdcall ibconfig (int ud, int option, int v);
+extern int __stdcall ibdev    (int boardID, int pad, int sad, int tmo, int eot, int eos);
+extern int __stdcall ibdiag   (int ud, PVOID buf, long cnt);
+extern int __stdcall ibdma    (int ud, int v);
+extern int __stdcall ibeos    (int ud, int v);
+extern int __stdcall ibeot    (int ud, int v);
+extern int __stdcall ibgts    (int ud, int v);
+extern int __stdcall ibist    (int ud, int v);
+extern int __stdcall iblines  (int ud, PSHORT result);
+extern int __stdcall ibln     (int ud, int pad, int sad, PSHORT listen);
+extern int __stdcall ibloc    (int ud);
+extern int __stdcall ibnotify (int ud, int mask, GpibNotifyCallback_t Callback, PVOID RefData);
+extern int __stdcall ibonl    (int ud, int v);
+extern int __stdcall ibpad    (int ud, int v);
+extern int __stdcall ibpct    (int ud);
+extern int __stdcall ibpoke   (int ud, long option, long v);
+extern int __stdcall ibppc    (int ud, int v);
+extern int __stdcall ibrd     (int ud, PVOID buf, long cnt);
+extern int __stdcall ibrda    (int ud, PVOID buf, long cnt);
+extern int __stdcall ibrpp    (int ud, PCHAR ppr);
+extern int __stdcall ibrsc    (int ud, int v);
+extern int __stdcall ibrsp    (int ud, PCHAR spr);
+extern int __stdcall ibrsv    (int ud, int v);
+extern int __stdcall ibsad    (int ud, int v);
+extern int __stdcall ibsic    (int ud);
+extern int __stdcall ibsre    (int ud, int v);
+extern int __stdcall ibstop   (int ud);
+extern int __stdcall ibtmo    (int ud, int v);
+extern int __stdcall ibtrg    (int ud);
+extern int __stdcall ibwait   (int ud, int mask);
+extern int __stdcall ibwrt    (int ud, PVOID buf, long cnt);
+extern int __stdcall ibwrta   (int ud, PVOID buf, long cnt);
+
+// GPIB-ENET only functions to support locking across machines
+extern int __stdcall iblock   (int ud);
+extern int __stdcall ibunlock (int ud);
+
+/**************************************************************************/
+/*  Functions to access Thread-Specific copies of the GPIB global vars */
+
+extern int  __stdcall ThreadIbsta (void);
+extern int  __stdcall ThreadIberr (void);
+extern int  __stdcall ThreadIbcnt (void);
+extern long __stdcall ThreadIbcntl (void);
+
+
+/**************************************************************************/
+/*  NI-488.2 Function Prototypes  */
+
+extern void __stdcall AllSpoll      (int boardID, Addr4882_t * addrlist, PSHORT results);
+extern void __stdcall DevClear      (int boardID, Addr4882_t addr);
+extern void __stdcall DevClearList  (int boardID, Addr4882_t * addrlist);
+extern void __stdcall EnableLocal   (int boardID, Addr4882_t * addrlist);
+extern void __stdcall EnableRemote  (int boardID, Addr4882_t * addrlist);
+extern void __stdcall FindLstn      (int boardID, Addr4882_t * addrlist, Addr4882_t * results, int limit);
+extern void __stdcall FindRQS       (int boardID, Addr4882_t * addrlist, PSHORT dev_stat);
+extern void __stdcall PPoll         (int boardID, PSHORT result);
+extern void __stdcall PPollConfig   (int boardID, Addr4882_t addr, int dataLine, int lineSense);
+extern void __stdcall PPollUnconfig (int boardID, Addr4882_t * addrlist);
+extern void __stdcall PassControl   (int boardID, Addr4882_t addr);
+extern void __stdcall RcvRespMsg    (int boardID, PVOID buffer, long cnt, int Termination);
+extern void __stdcall ReadStatusByte(int boardID, Addr4882_t addr, PSHORT result);
+extern void __stdcall Receive       (int boardID, Addr4882_t addr, PVOID buffer, long cnt, int Termination);
+extern void __stdcall ReceiveSetup  (int boardID, Addr4882_t addr);
+extern void __stdcall ResetSys      (int boardID, Addr4882_t * addrlist);
+extern void __stdcall Send          (int boardID, Addr4882_t addr, PVOID databuf, long datacnt, int eotMode);
+extern void __stdcall SendCmds      (int boardID, PVOID buffer, long cnt);
+extern void __stdcall SendDataBytes (int boardID, PVOID buffer, long cnt, int eot_mode);
+extern void __stdcall SendIFC       (int boardID);
+extern void __stdcall SendLLO       (int boardID);
+extern void __stdcall SendList      (int boardID, Addr4882_t * addrlist, PVOID databuf, long datacnt, int eotMode);
+extern void __stdcall SendSetup     (int boardID, Addr4882_t * addrlist);
+extern void __stdcall SetRWLS       (int boardID, Addr4882_t * addrlist);
+extern void __stdcall TestSRQ       (int boardID, PSHORT result);
+extern void __stdcall TestSys       (int boardID, Addr4882_t * addrlist, PSHORT results);
+extern void __stdcall Trigger       (int boardID, Addr4882_t addr);
+extern void __stdcall TriggerList   (int boardID, Addr4882_t * addrlist);
+extern void __stdcall WaitSRQ       (int boardID, PSHORT result);
+
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif   // DECL_32_H
+
index 4eb5433196dd00e001e972a66edefcacd86a3655..e60f714889de364a3fed2274b42b806e645c3a21 100644 (file)
-/*\r
- * iconv library using Win32 API to conversion.\r
- *\r
- * This file is placed in the public domain.\r
- *\r
- * Last Change: 2009-07-06\r
- *\r
- * ENVIRONMENT VARIABLE:\r
- *     WINICONV_LIBICONV_DLL\r
- *         If $WINICONV_LIBICONV_DLL is set, win_iconv uses the DLL.  If\r
- *         loading the DLL or iconv_open() failed, falls back to internal\r
- *         conversion.  If a few DLL are specified as comma separated list,\r
- *         the first loadable DLL is used.  The DLL should have iconv_open(),\r
- *         iconv_close() and iconv().  Or libiconv_open(), libiconv_close()\r
- *         and libiconv().\r
- *         (only available when USE_LIBICONV_DLL is defined at compile time)\r
- *\r
- * Win32 API does not support strict encoding conversion for some\r
- * codepage.  And MLang function drop or replace invalid bytes and does\r
- * not return useful error status as iconv.  This implementation cannot\r
- * be used for encoding validation purpose.\r
- */\r
-\r
-/* for WC_NO_BEST_FIT_CHARS */\r
-#ifndef WINVER\r
-# define WINVER 0x0500\r
-#endif\r
-\r
-#include <windows.h>\r
-#include <errno.h>\r
-#include <string.h>\r
-#include <stdlib.h>\r
-\r
-#if 0\r
-# define MAKE_EXE\r
-# define MAKE_DLL\r
-# define USE_LIBICONV_DLL\r
-#endif\r
-\r
-#if !defined(DEFAULT_LIBICONV_DLL)\r
-# define DEFAULT_LIBICONV_DLL ""\r
-#endif\r
-\r
-#define MB_CHAR_MAX 16\r
-\r
-#define UNICODE_MODE_BOM_DONE   1\r
-#define UNICODE_MODE_SWAPPED    2\r
-\r
-#define FLAG_USE_BOM            1\r
-#define FLAG_TRANSLIT           2 /* //TRANSLIT */\r
-#define FLAG_IGNORE             4 /* //IGNORE (not implemented) */\r
-\r
-typedef unsigned char uchar;\r
-typedef unsigned short ushort;\r
-typedef unsigned int uint;\r
-\r
-typedef void* iconv_t;\r
-\r
-iconv_t iconv_open(const char *tocode, const char *fromcode);\r
-int iconv_close(iconv_t cd);\r
-size_t iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);\r
-\r
-/* libiconv interface for vim */\r
-#if defined(MAKE_DLL)\r
-int\r
-iconvctl (iconv_t cd, int request, void* argument)\r
-{\r
-    /* not supported */\r
-    return 0;\r
-}\r
-#endif\r
-\r
-typedef struct compat_t compat_t;\r
-typedef struct csconv_t csconv_t;\r
-typedef struct rec_iconv_t rec_iconv_t;\r
-\r
-typedef iconv_t (*f_iconv_open)(const char *tocode, const char *fromcode);\r
-typedef int (*f_iconv_close)(iconv_t cd);\r
-typedef size_t (*f_iconv)(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);\r
-typedef int* (*f_errno)(void);\r
-typedef int (*f_mbtowc)(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);\r
-typedef int (*f_wctomb)(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);\r
-typedef int (*f_mblen)(csconv_t *cv, const uchar *buf, int bufsize);\r
-typedef int (*f_flush)(csconv_t *cv, uchar *buf, int bufsize);\r
-\r
-#define COMPAT_IN   1\r
-#define COMPAT_OUT  2\r
-\r
-/* unicode mapping for compatibility with other conversion table. */\r
-struct compat_t {\r
-    uint in;\r
-    uint out;\r
-    uint flag;\r
-};\r
-\r
-struct csconv_t {\r
-    int codepage;\r
-    int flags;\r
-    f_mbtowc mbtowc;\r
-    f_wctomb wctomb;\r
-    f_mblen mblen;\r
-    f_flush flush;\r
-    DWORD mode;\r
-    compat_t *compat;\r
-};\r
-\r
-struct rec_iconv_t {\r
-    iconv_t cd;\r
-    f_iconv_close iconv_close;\r
-    f_iconv iconv;\r
-    f_errno _errno;\r
-    csconv_t from;\r
-    csconv_t to;\r
-#if defined(USE_LIBICONV_DLL)\r
-    HMODULE hlibiconv;\r
-#endif\r
-};\r
-\r
-static int win_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode);\r
-static int win_iconv_close(iconv_t cd);\r
-static size_t win_iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);\r
-\r
-static int load_mlang();\r
-static int make_csconv(const char *name, csconv_t *cv);\r
-static int name_to_codepage(const char *name);\r
-static uint utf16_to_ucs4(const ushort *wbuf);\r
-static void ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize);\r
-static int mbtowc_flags(int codepage);\r
-static int must_use_null_useddefaultchar(int codepage);\r
-static char *strrstr(const char *str, const char *token);\r
-static char *xstrndup(const char *s, size_t n);\r
-static int seterror(int err);\r
-\r
-#if defined(USE_LIBICONV_DLL)\r
-static int libiconv_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode);\r
-static PVOID MyImageDirectoryEntryToData(LPVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size);\r
-static HMODULE find_imported_module_by_funcname(HMODULE hModule, const char *funcname);\r
-\r
-static HMODULE hwiniconv;\r
-#endif\r
-\r
-static int sbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);\r
-static int dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);\r
-static int mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);\r
-static int utf8_mblen(csconv_t *cv, const uchar *buf, int bufsize);\r
-static int eucjp_mblen(csconv_t *cv, const uchar *buf, int bufsize);\r
-\r
-static int kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);\r
-static int kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);\r
-static int mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);\r
-static int mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);\r
-static int utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);\r
-static int utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);\r
-static int utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);\r
-static int utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);\r
-static int iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);\r
-static int iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);\r
-static int iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize);\r
-\r
-static struct {\r
-    int codepage;\r
-    const char *name;\r
-} codepage_alias[] = {\r
-    {65001, "CP65001"},\r
-    {65001, "UTF8"},\r
-    {65001, "UTF-8"},\r
-\r
-    {1200, "CP1200"},\r
-    {1200, "UTF16LE"},\r
-    {1200, "UTF-16LE"},\r
-    {1200, "UCS-2LE"},\r
-\r
-    {1201, "CP1201"},\r
-    {1201, "UTF16BE"},\r
-    {1201, "UTF-16BE"},\r
-    {1201, "UCS-2BE"},\r
-    {1201, "unicodeFFFE"},\r
-\r
-    {12000, "CP12000"},\r
-    {12000, "UTF32LE"},\r
-    {12000, "UTF-32LE"},\r
-\r
-    {12001, "CP12001"},\r
-    {12001, "UTF32BE"},\r
-    {12001, "UTF-32BE"},\r
-\r
-#ifndef GLIB_COMPILATION\r
-    /*\r
-     * Default is big endian.\r
-     * See rfc2781 4.3 Interpreting text labelled as UTF-16.\r
-     */\r
-    {1201, "UTF16"},\r
-    {1201, "UTF-16"},\r
-    {12001, "UTF32"},\r
-    {12001, "UTF-32"},\r
-#else\r
-    /* Default is little endian, because the platform is */\r
-    {1200, "UTF16"},\r
-    {1200, "UTF-16"},\r
-    {1200, "UCS-2"},\r
-    {12000, "UTF32"},\r
-    {12000, "UTF-32"},\r
-#endif\r
-\r
-    /* copy from libiconv `iconv -l` */\r
-    /* !IsValidCodePage(367) */\r
-    {20127, "ANSI_X3.4-1968"},\r
-    {20127, "ANSI_X3.4-1986"},\r
-    {20127, "ASCII"},\r
-    {20127, "CP367"},\r
-    {20127, "IBM367"},\r
-    {20127, "ISO-IR-6"},\r
-    {20127, "ISO646-US"},\r
-    {20127, "ISO_646.IRV:1991"},\r
-    {20127, "US"},\r
-    {20127, "US-ASCII"},\r
-    {20127, "CSASCII"},\r
-\r
-    /* !IsValidCodePage(819) */\r
-    {1252, "CP819"},\r
-    {1252, "IBM819"},\r
-    {28591, "ISO-8859-1"},\r
-    {28591, "ISO-IR-100"},\r
-    {28591, "ISO8859-1"},\r
-    {28591, "ISO_8859-1"},\r
-    {28591, "ISO_8859-1:1987"},\r
-    {28591, "L1"},\r
-    {28591, "LATIN1"},\r
-    {28591, "CSISOLATIN1"},\r
-\r
-    {1250, "CP1250"},\r
-    {1250, "MS-EE"},\r
-    {1250, "WINDOWS-1250"},\r
-\r
-    {1251, "CP1251"},\r
-    {1251, "MS-CYRL"},\r
-    {1251, "WINDOWS-1251"},\r
-\r
-    {1252, "CP1252"},\r
-    {1252, "MS-ANSI"},\r
-    {1252, "WINDOWS-1252"},\r
-\r
-    {1253, "CP1253"},\r
-    {1253, "MS-GREEK"},\r
-    {1253, "WINDOWS-1253"},\r
-\r
-    {1254, "CP1254"},\r
-    {1254, "MS-TURK"},\r
-    {1254, "WINDOWS-1254"},\r
-\r
-    {1255, "CP1255"},\r
-    {1255, "MS-HEBR"},\r
-    {1255, "WINDOWS-1255"},\r
-\r
-    {1256, "CP1256"},\r
-    {1256, "MS-ARAB"},\r
-    {1256, "WINDOWS-1256"},\r
-\r
-    {1257, "CP1257"},\r
-    {1257, "WINBALTRIM"},\r
-    {1257, "WINDOWS-1257"},\r
-\r
-    {1258, "CP1258"},\r
-    {1258, "WINDOWS-1258"},\r
-\r
-    {850, "850"},\r
-    {850, "CP850"},\r
-    {850, "IBM850"},\r
-    {850, "CSPC850MULTILINGUAL"},\r
-\r
-    /* !IsValidCodePage(862) */\r
-    {862, "862"},\r
-    {862, "CP862"},\r
-    {862, "IBM862"},\r
-    {862, "CSPC862LATINHEBREW"},\r
-\r
-    {866, "866"},\r
-    {866, "CP866"},\r
-    {866, "IBM866"},\r
-    {866, "CSIBM866"},\r
-\r
-    /* !IsValidCodePage(154) */\r
-    {154, "CP154"},\r
-    {154, "CYRILLIC-ASIAN"},\r
-    {154, "PT154"},\r
-    {154, "PTCP154"},\r
-    {154, "CSPTCP154"},\r
-\r
-    /* !IsValidCodePage(1133) */\r
-    {1133, "CP1133"},\r
-    {1133, "IBM-CP1133"},\r
-\r
-    {874, "CP874"},\r
-    {874, "WINDOWS-874"},\r
-\r
-    /* !IsValidCodePage(51932) */\r
-    {51932, "CP51932"},\r
-    {51932, "MS51932"},\r
-    {51932, "WINDOWS-51932"},\r
-    {51932, "EUC-JP"},\r
-\r
-    {932, "CP932"},\r
-    {932, "MS932"},\r
-    {932, "SHIFFT_JIS"},\r
-    {932, "SHIFFT_JIS-MS"},\r
-    {932, "SJIS"},\r
-    {932, "SJIS-MS"},\r
-    {932, "SJIS-OPEN"},\r
-    {932, "SJIS-WIN"},\r
-    {932, "WINDOWS-31J"},\r
-    {932, "WINDOWS-932"},\r
-    {932, "CSWINDOWS31J"},\r
-\r
-    {50221, "CP50221"},\r
-    {50221, "ISO-2022-JP"},\r
-    {50221, "ISO-2022-JP-MS"},\r
-    {50221, "ISO2022-JP"},\r
-    {50221, "ISO2022-JP-MS"},\r
-    {50221, "MS50221"},\r
-    {50221, "WINDOWS-50221"},\r
-\r
-    {936, "CP936"},\r
-    {936, "GBK"},\r
-    {936, "MS936"},\r
-    {936, "WINDOWS-936"},\r
-\r
-    {950, "CP950"},\r
-    {950, "BIG5"},\r
-\r
-    {949, "CP949"},\r
-    {949, "UHC"},\r
-    {949, "EUC-KR"},\r
-\r
-    {1361, "CP1361"},\r
-    {1361, "JOHAB"},\r
-\r
-    {437, "437"},\r
-    {437, "CP437"},\r
-    {437, "IBM437"},\r
-    {437, "CSPC8CODEPAGE437"},\r
-\r
-    {737, "CP737"},\r
-\r
-    {775, "CP775"},\r
-    {775, "IBM775"},\r
-    {775, "CSPC775BALTIC"},\r
-\r
-    {852, "852"},\r
-    {852, "CP852"},\r
-    {852, "IBM852"},\r
-    {852, "CSPCP852"},\r
-\r
-    /* !IsValidCodePage(853) */\r
-    {853, "CP853"},\r
-\r
-    {855, "855"},\r
-    {855, "CP855"},\r
-    {855, "IBM855"},\r
-    {855, "CSIBM855"},\r
-\r
-    {857, "857"},\r
-    {857, "CP857"},\r
-    {857, "IBM857"},\r
-    {857, "CSIBM857"},\r
-\r
-    /* !IsValidCodePage(858) */\r
-    {858, "CP858"},\r
-\r
-    {860, "860"},\r
-    {860, "CP860"},\r
-    {860, "IBM860"},\r
-    {860, "CSIBM860"},\r
-\r
-    {861, "861"},\r
-    {861, "CP-IS"},\r
-    {861, "CP861"},\r
-    {861, "IBM861"},\r
-    {861, "CSIBM861"},\r
-\r
-    {863, "863"},\r
-    {863, "CP863"},\r
-    {863, "IBM863"},\r
-    {863, "CSIBM863"},\r
-\r
-    {864, "CP864"},\r
-    {864, "IBM864"},\r
-    {864, "CSIBM864"},\r
-\r
-    {865, "865"},\r
-    {865, "CP865"},\r
-    {865, "IBM865"},\r
-    {865, "CSIBM865"},\r
-\r
-    {869, "869"},\r
-    {869, "CP-GR"},\r
-    {869, "CP869"},\r
-    {869, "IBM869"},\r
-    {869, "CSIBM869"},\r
-\r
-    /* !IsValidCodePage(1152) */\r
-    {1125, "CP1125"},\r
-\r
-    /*\r
-     * Code Page Identifiers\r
-     * http://msdn2.microsoft.com/en-us/library/ms776446.aspx\r
-     */\r
-    {37, "IBM037"}, /* IBM EBCDIC US-Canada */\r
-    {437, "IBM437"}, /* OEM United States */\r
-    {500, "IBM500"}, /* IBM EBCDIC International */\r
-    {708, "ASMO-708"}, /* Arabic (ASMO 708) */\r
-    /* 709             Arabic (ASMO-449+, BCON V4) */\r
-    /* 710             Arabic - Transparent Arabic */\r
-    {720, "DOS-720"}, /* Arabic (Transparent ASMO); Arabic (DOS) */\r
-    {737, "ibm737"}, /* OEM Greek (formerly 437G); Greek (DOS) */\r
-    {775, "ibm775"}, /* OEM Baltic; Baltic (DOS) */\r
-    {850, "ibm850"}, /* OEM Multilingual Latin 1; Western European (DOS) */\r
-    {852, "ibm852"}, /* OEM Latin 2; Central European (DOS) */\r
-    {855, "IBM855"}, /* OEM Cyrillic (primarily Russian) */\r
-    {857, "ibm857"}, /* OEM Turkish; Turkish (DOS) */\r
-    {858, "IBM00858"}, /* OEM Multilingual Latin 1 + Euro symbol */\r
-    {860, "IBM860"}, /* OEM Portuguese; Portuguese (DOS) */\r
-    {861, "ibm861"}, /* OEM Icelandic; Icelandic (DOS) */\r
-    {862, "DOS-862"}, /* OEM Hebrew; Hebrew (DOS) */\r
-    {863, "IBM863"}, /* OEM French Canadian; French Canadian (DOS) */\r
-    {864, "IBM864"}, /* OEM Arabic; Arabic (864) */\r
-    {865, "IBM865"}, /* OEM Nordic; Nordic (DOS) */\r
-    {866, "cp866"}, /* OEM Russian; Cyrillic (DOS) */\r
-    {869, "ibm869"}, /* OEM Modern Greek; Greek, Modern (DOS) */\r
-    {870, "IBM870"}, /* IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2 */\r
-    {874, "windows-874"}, /* ANSI/OEM Thai (same as 28605, ISO 8859-15); Thai (Windows) */\r
-    {875, "cp875"}, /* IBM EBCDIC Greek Modern */\r
-    {932, "shift_jis"}, /* ANSI/OEM Japanese; Japanese (Shift-JIS) */\r
-    {932, "shift-jis"}, /* alternative name for it */\r
-    {936, "gb2312"}, /* ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312) */\r
-    {949, "ks_c_5601-1987"}, /* ANSI/OEM Korean (Unified Hangul Code) */\r
-    {950, "big5"}, /* ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5) */\r
-    {1026, "IBM1026"}, /* IBM EBCDIC Turkish (Latin 5) */\r
-    {1047, "IBM01047"}, /* IBM EBCDIC Latin 1/Open System */\r
-    {1140, "IBM01140"}, /* IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro) */\r
-    {1141, "IBM01141"}, /* IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro) */\r
-    {1142, "IBM01142"}, /* IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro) */\r
-    {1143, "IBM01143"}, /* IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro) */\r
-    {1144, "IBM01144"}, /* IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro) */\r
-    {1145, "IBM01145"}, /* IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro) */\r
-    {1146, "IBM01146"}, /* IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro) */\r
-    {1147, "IBM01147"}, /* IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro) */\r
-    {1148, "IBM01148"}, /* IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro) */\r
-    {1149, "IBM01149"}, /* IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro) */\r
-    {1250, "windows-1250"}, /* ANSI Central European; Central European (Windows) */\r
-    {1251, "windows-1251"}, /* ANSI Cyrillic; Cyrillic (Windows) */\r
-    {1252, "windows-1252"}, /* ANSI Latin 1; Western European (Windows) */\r
-    {1253, "windows-1253"}, /* ANSI Greek; Greek (Windows) */\r
-    {1254, "windows-1254"}, /* ANSI Turkish; Turkish (Windows) */\r
-    {1255, "windows-1255"}, /* ANSI Hebrew; Hebrew (Windows) */\r
-    {1256, "windows-1256"}, /* ANSI Arabic; Arabic (Windows) */\r
-    {1257, "windows-1257"}, /* ANSI Baltic; Baltic (Windows) */\r
-    {1258, "windows-1258"}, /* ANSI/OEM Vietnamese; Vietnamese (Windows) */\r
-    {1361, "Johab"}, /* Korean (Johab) */\r
-    {10000, "macintosh"}, /* MAC Roman; Western European (Mac) */\r
-    {10001, "x-mac-japanese"}, /* Japanese (Mac) */\r
-    {10002, "x-mac-chinesetrad"}, /* MAC Traditional Chinese (Big5); Chinese Traditional (Mac) */\r
-    {10003, "x-mac-korean"}, /* Korean (Mac) */\r
-    {10004, "x-mac-arabic"}, /* Arabic (Mac) */\r
-    {10005, "x-mac-hebrew"}, /* Hebrew (Mac) */\r
-    {10006, "x-mac-greek"}, /* Greek (Mac) */\r
-    {10007, "x-mac-cyrillic"}, /* Cyrillic (Mac) */\r
-    {10008, "x-mac-chinesesimp"}, /* MAC Simplified Chinese (GB 2312); Chinese Simplified (Mac) */\r
-    {10010, "x-mac-romanian"}, /* Romanian (Mac) */\r
-    {10017, "x-mac-ukrainian"}, /* Ukrainian (Mac) */\r
-    {10021, "x-mac-thai"}, /* Thai (Mac) */\r
-    {10029, "x-mac-ce"}, /* MAC Latin 2; Central European (Mac) */\r
-    {10079, "x-mac-icelandic"}, /* Icelandic (Mac) */\r
-    {10081, "x-mac-turkish"}, /* Turkish (Mac) */\r
-    {10082, "x-mac-croatian"}, /* Croatian (Mac) */\r
-    {20000, "x-Chinese_CNS"}, /* CNS Taiwan; Chinese Traditional (CNS) */\r
-    {20001, "x-cp20001"}, /* TCA Taiwan */\r
-    {20002, "x_Chinese-Eten"}, /* Eten Taiwan; Chinese Traditional (Eten) */\r
-    {20003, "x-cp20003"}, /* IBM5550 Taiwan */\r
-    {20004, "x-cp20004"}, /* TeleText Taiwan */\r
-    {20005, "x-cp20005"}, /* Wang Taiwan */\r
-    {20105, "x-IA5"}, /* IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5) */\r
-    {20106, "x-IA5-German"}, /* IA5 German (7-bit) */\r
-    {20107, "x-IA5-Swedish"}, /* IA5 Swedish (7-bit) */\r
-    {20108, "x-IA5-Norwegian"}, /* IA5 Norwegian (7-bit) */\r
-    {20127, "us-ascii"}, /* US-ASCII (7-bit) */\r
-    {20261, "x-cp20261"}, /* T.61 */\r
-    {20269, "x-cp20269"}, /* ISO 6937 Non-Spacing Accent */\r
-    {20273, "IBM273"}, /* IBM EBCDIC Germany */\r
-    {20277, "IBM277"}, /* IBM EBCDIC Denmark-Norway */\r
-    {20278, "IBM278"}, /* IBM EBCDIC Finland-Sweden */\r
-    {20280, "IBM280"}, /* IBM EBCDIC Italy */\r
-    {20284, "IBM284"}, /* IBM EBCDIC Latin America-Spain */\r
-    {20285, "IBM285"}, /* IBM EBCDIC United Kingdom */\r
-    {20290, "IBM290"}, /* IBM EBCDIC Japanese Katakana Extended */\r
-    {20297, "IBM297"}, /* IBM EBCDIC France */\r
-    {20420, "IBM420"}, /* IBM EBCDIC Arabic */\r
-    {20423, "IBM423"}, /* IBM EBCDIC Greek */\r
-    {20424, "IBM424"}, /* IBM EBCDIC Hebrew */\r
-    {20833, "x-EBCDIC-KoreanExtended"}, /* IBM EBCDIC Korean Extended */\r
-    {20838, "IBM-Thai"}, /* IBM EBCDIC Thai */\r
-    {20866, "koi8-r"}, /* Russian (KOI8-R); Cyrillic (KOI8-R) */\r
-    {20871, "IBM871"}, /* IBM EBCDIC Icelandic */\r
-    {20880, "IBM880"}, /* IBM EBCDIC Cyrillic Russian */\r
-    {20905, "IBM905"}, /* IBM EBCDIC Turkish */\r
-    {20924, "IBM00924"}, /* IBM EBCDIC Latin 1/Open System (1047 + Euro symbol) */\r
-    {20932, "EUC-JP"}, /* Japanese (JIS 0208-1990 and 0121-1990) */\r
-    {20936, "x-cp20936"}, /* Simplified Chinese (GB2312); Chinese Simplified (GB2312-80) */\r
-    {20949, "x-cp20949"}, /* Korean Wansung */\r
-    {21025, "cp1025"}, /* IBM EBCDIC Cyrillic Serbian-Bulgarian */\r
-    /* 21027           (deprecated) */\r
-    {21866, "koi8-u"}, /* Ukrainian (KOI8-U); Cyrillic (KOI8-U) */\r
-    {28591, "iso-8859-1"}, /* ISO 8859-1 Latin 1; Western European (ISO) */\r
-    {28591, "iso8859-1"}, /* ISO 8859-1 Latin 1; Western European (ISO) */\r
-    {28592, "iso-8859-2"}, /* ISO 8859-2 Central European; Central European (ISO) */\r
-    {28592, "iso8859-2"}, /* ISO 8859-2 Central European; Central European (ISO) */\r
-    {28593, "iso-8859-3"}, /* ISO 8859-3 Latin 3 */\r
-    {28593, "iso8859-3"}, /* ISO 8859-3 Latin 3 */\r
-    {28594, "iso-8859-4"}, /* ISO 8859-4 Baltic */\r
-    {28594, "iso8859-4"}, /* ISO 8859-4 Baltic */\r
-    {28595, "iso-8859-5"}, /* ISO 8859-5 Cyrillic */\r
-    {28595, "iso8859-5"}, /* ISO 8859-5 Cyrillic */\r
-    {28596, "iso-8859-6"}, /* ISO 8859-6 Arabic */\r
-    {28596, "iso8859-6"}, /* ISO 8859-6 Arabic */\r
-    {28597, "iso-8859-7"}, /* ISO 8859-7 Greek */\r
-    {28597, "iso8859-7"}, /* ISO 8859-7 Greek */\r
-    {28598, "iso-8859-8"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */\r
-    {28598, "iso8859-8"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */\r
-    {28599, "iso-8859-9"}, /* ISO 8859-9 Turkish */\r
-    {28599, "iso8859-9"}, /* ISO 8859-9 Turkish */\r
-    {28603, "iso-8859-13"}, /* ISO 8859-13 Estonian */\r
-    {28603, "iso8859-13"}, /* ISO 8859-13 Estonian */\r
-    {28605, "iso-8859-15"}, /* ISO 8859-15 Latin 9 */\r
-    {28605, "iso8859-15"}, /* ISO 8859-15 Latin 9 */\r
-    {29001, "x-Europa"}, /* Europa 3 */\r
-    {38598, "iso-8859-8-i"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */\r
-    {38598, "iso8859-8-i"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */\r
-    {50220, "iso-2022-jp"}, /* ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS) */\r
-    {50221, "csISO2022JP"}, /* ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana) */\r
-    {50222, "iso-2022-jp"}, /* ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI) */\r
-    {50225, "iso-2022-kr"}, /* ISO 2022 Korean */\r
-    {50225, "iso2022-kr"}, /* ISO 2022 Korean */\r
-    {50227, "x-cp50227"}, /* ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022) */\r
-    /* 50229           ISO 2022 Traditional Chinese */\r
-    /* 50930           EBCDIC Japanese (Katakana) Extended */\r
-    /* 50931           EBCDIC US-Canada and Japanese */\r
-    /* 50933           EBCDIC Korean Extended and Korean */\r
-    /* 50935           EBCDIC Simplified Chinese Extended and Simplified Chinese */\r
-    /* 50936           EBCDIC Simplified Chinese */\r
-    /* 50937           EBCDIC US-Canada and Traditional Chinese */\r
-    /* 50939           EBCDIC Japanese (Latin) Extended and Japanese */\r
-    {51932, "euc-jp"}, /* EUC Japanese */\r
-    {51936, "EUC-CN"}, /* EUC Simplified Chinese; Chinese Simplified (EUC) */\r
-    {51949, "euc-kr"}, /* EUC Korean */\r
-    /* 51950           EUC Traditional Chinese */\r
-    {52936, "hz-gb-2312"}, /* HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ) */\r
-    {54936, "GB18030"}, /* Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030) */\r
-    {57002, "x-iscii-de"}, /* ISCII Devanagari */\r
-    {57003, "x-iscii-be"}, /* ISCII Bengali */\r
-    {57004, "x-iscii-ta"}, /* ISCII Tamil */\r
-    {57005, "x-iscii-te"}, /* ISCII Telugu */\r
-    {57006, "x-iscii-as"}, /* ISCII Assamese */\r
-    {57007, "x-iscii-or"}, /* ISCII Oriya */\r
-    {57008, "x-iscii-ka"}, /* ISCII Kannada */\r
-    {57009, "x-iscii-ma"}, /* ISCII Malayalam */\r
-    {57010, "x-iscii-gu"}, /* ISCII Gujarati */\r
-    {57011, "x-iscii-pa"}, /* ISCII Punjabi */\r
-\r
-    {0, NULL}\r
-};\r
-\r
-/*\r
- * SJIS SHIFTJIS table              CP932 table\r
- * ---- --------------------------- --------------------------------\r
- *   5C U+00A5 YEN SIGN             U+005C REVERSE SOLIDUS\r
- *   7E U+203E OVERLINE             U+007E TILDE\r
- * 815C U+2014 EM DASH              U+2015 HORIZONTAL BAR\r
- * 815F U+005C REVERSE SOLIDUS      U+FF3C FULLWIDTH REVERSE SOLIDUS\r
- * 8160 U+301C WAVE DASH            U+FF5E FULLWIDTH TILDE\r
- * 8161 U+2016 DOUBLE VERTICAL LINE U+2225 PARALLEL TO\r
- * 817C U+2212 MINUS SIGN           U+FF0D FULLWIDTH HYPHEN-MINUS\r
- * 8191 U+00A2 CENT SIGN            U+FFE0 FULLWIDTH CENT SIGN\r
- * 8192 U+00A3 POUND SIGN           U+FFE1 FULLWIDTH POUND SIGN\r
- * 81CA U+00AC NOT SIGN             U+FFE2 FULLWIDTH NOT SIGN\r
- *\r
- * EUC-JP and ISO-2022-JP should be compatible with CP932.\r
- *\r
- * Kernel and MLang have different Unicode mapping table.  Make sure\r
- * which API is used.\r
- */\r
-static compat_t cp932_compat[] = {\r
-    {0x00A5, 0x005C, COMPAT_OUT},\r
-    {0x203E, 0x007E, COMPAT_OUT},\r
-    {0x2014, 0x2015, COMPAT_OUT},\r
-    {0x301C, 0xFF5E, COMPAT_OUT},\r
-    {0x2016, 0x2225, COMPAT_OUT},\r
-    {0x2212, 0xFF0D, COMPAT_OUT},\r
-    {0x00A2, 0xFFE0, COMPAT_OUT},\r
-    {0x00A3, 0xFFE1, COMPAT_OUT},\r
-    {0x00AC, 0xFFE2, COMPAT_OUT},\r
-    {0, 0, 0}\r
-};\r
-\r
-static compat_t cp20932_compat[] = {\r
-    {0x00A5, 0x005C, COMPAT_OUT},\r
-    {0x203E, 0x007E, COMPAT_OUT},\r
-    {0x2014, 0x2015, COMPAT_OUT},\r
-    {0xFF5E, 0x301C, COMPAT_OUT|COMPAT_IN},\r
-    {0x2225, 0x2016, COMPAT_OUT|COMPAT_IN},\r
-    {0xFF0D, 0x2212, COMPAT_OUT|COMPAT_IN},\r
-    {0xFFE0, 0x00A2, COMPAT_OUT|COMPAT_IN},\r
-    {0xFFE1, 0x00A3, COMPAT_OUT|COMPAT_IN},\r
-    {0xFFE2, 0x00AC, COMPAT_OUT|COMPAT_IN},\r
-    {0, 0, 0}\r
-};\r
-\r
-static compat_t *cp51932_compat = cp932_compat;\r
-\r
-/* cp20932_compat for kernel.  cp932_compat for mlang. */\r
-static compat_t *cp5022x_compat = cp932_compat;\r
-\r
-typedef HRESULT (WINAPI *CONVERTINETSTRING)(\r
-    LPDWORD lpdwMode,\r
-    DWORD dwSrcEncoding,\r
-    DWORD dwDstEncoding,\r
-    LPCSTR lpSrcStr,\r
-    LPINT lpnSrcSize,\r
-    LPBYTE lpDstStr,\r
-    LPINT lpnDstSize\r
-);\r
-typedef HRESULT (WINAPI *CONVERTINETMULTIBYTETOUNICODE)(\r
-    LPDWORD lpdwMode,\r
-    DWORD dwSrcEncoding,\r
-    LPCSTR lpSrcStr,\r
-    LPINT lpnMultiCharCount,\r
-    LPWSTR lpDstStr,\r
-    LPINT lpnWideCharCount\r
-);\r
-typedef HRESULT (WINAPI *CONVERTINETUNICODETOMULTIBYTE)(\r
-    LPDWORD lpdwMode,\r
-    DWORD dwEncoding,\r
-    LPCWSTR lpSrcStr,\r
-    LPINT lpnWideCharCount,\r
-    LPSTR lpDstStr,\r
-    LPINT lpnMultiCharCount\r
-);\r
-typedef HRESULT (WINAPI *ISCONVERTINETSTRINGAVAILABLE)(\r
-    DWORD dwSrcEncoding,\r
-    DWORD dwDstEncoding\r
-);\r
-typedef HRESULT (WINAPI *LCIDTORFC1766A)(\r
-    LCID Locale,\r
-    LPSTR pszRfc1766,\r
-    int nChar\r
-);\r
-typedef HRESULT (WINAPI *LCIDTORFC1766W)(\r
-    LCID Locale,\r
-    LPWSTR pszRfc1766,\r
-    int nChar\r
-);\r
-typedef HRESULT (WINAPI *RFC1766TOLCIDA)(\r
-    LCID *pLocale,\r
-    LPSTR pszRfc1766\r
-);\r
-typedef HRESULT (WINAPI *RFC1766TOLCIDW)(\r
-    LCID *pLocale,\r
-    LPWSTR pszRfc1766\r
-);\r
-static CONVERTINETSTRING ConvertINetString;\r
-static CONVERTINETMULTIBYTETOUNICODE ConvertINetMultiByteToUnicode;\r
-static CONVERTINETUNICODETOMULTIBYTE ConvertINetUnicodeToMultiByte;\r
-static ISCONVERTINETSTRINGAVAILABLE IsConvertINetStringAvailable;\r
-static LCIDTORFC1766A LcidToRfc1766A;\r
-static RFC1766TOLCIDA Rfc1766ToLcidA;\r
-\r
-static int\r
-load_mlang()\r
-{\r
-    HMODULE h;\r
-    if (ConvertINetString != NULL)\r
-        return TRUE;\r
-    h = LoadLibrary("mlang.dll");\r
-    if (!h)\r
-        return FALSE;\r
-    ConvertINetString = (CONVERTINETSTRING)GetProcAddress(h, "ConvertINetString");\r
-    ConvertINetMultiByteToUnicode = (CONVERTINETMULTIBYTETOUNICODE)GetProcAddress(h, "ConvertINetMultiByteToUnicode");\r
-    ConvertINetUnicodeToMultiByte = (CONVERTINETUNICODETOMULTIBYTE)GetProcAddress(h, "ConvertINetUnicodeToMultiByte");\r
-    IsConvertINetStringAvailable = (ISCONVERTINETSTRINGAVAILABLE)GetProcAddress(h, "IsConvertINetStringAvailable");\r
-    LcidToRfc1766A = (LCIDTORFC1766A)GetProcAddress(h, "LcidToRfc1766A");\r
-    Rfc1766ToLcidA = (RFC1766TOLCIDA)GetProcAddress(h, "Rfc1766ToLcidA");\r
-    return TRUE;\r
-}\r
-\r
-iconv_t\r
-iconv_open(const char *tocode, const char *fromcode)\r
-{\r
-    rec_iconv_t *cd;\r
-\r
-    cd = (rec_iconv_t *)calloc(1, sizeof(rec_iconv_t));\r
-    if (cd == NULL)\r
-        return (iconv_t)(-1);\r
-\r
-#if defined(USE_LIBICONV_DLL)\r
-    errno = 0;\r
-    if (libiconv_iconv_open(cd, tocode, fromcode))\r
-        return (iconv_t)cd;\r
-#endif\r
-\r
-    /* reset the errno to prevent reporting wrong error code.\r
-     * 0 for unsorted error. */\r
-    errno = 0;\r
-    if (win_iconv_open(cd, tocode, fromcode))\r
-        return (iconv_t)cd;\r
-\r
-    free(cd);\r
-\r
-    return (iconv_t)(-1);\r
-}\r
-\r
-int\r
-iconv_close(iconv_t _cd)\r
-{\r
-    rec_iconv_t *cd = (rec_iconv_t *)_cd;\r
-    int r = cd->iconv_close(cd->cd);\r
-    int e = *(cd->_errno());\r
-#if defined(USE_LIBICONV_DLL)\r
-    if (cd->hlibiconv != NULL)\r
-        FreeLibrary(cd->hlibiconv);\r
-#endif\r
-    free(cd);\r
-    errno = e;\r
-    return r;\r
-}\r
-\r
-size_t\r
-iconv(iconv_t _cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)\r
-{\r
-    rec_iconv_t *cd = (rec_iconv_t *)_cd;\r
-    size_t r = cd->iconv(cd->cd, inbuf, inbytesleft, outbuf, outbytesleft);\r
-    errno = *(cd->_errno());\r
-    return r;\r
-}\r
-\r
-static int\r
-win_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode)\r
-{\r
-    if (!make_csconv(fromcode, &cd->from) || !make_csconv(tocode, &cd->to))\r
-        return FALSE;\r
-    cd->iconv_close = win_iconv_close;\r
-    cd->iconv = win_iconv;\r
-    cd->_errno = _errno;\r
-    cd->cd = (iconv_t)cd;\r
-    return TRUE;\r
-}\r
-\r
-static int\r
-win_iconv_close(iconv_t cd)\r
-{\r
-    return 0;\r
-}\r
-\r
-static size_t\r
-win_iconv(iconv_t _cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)\r
-{\r
-    rec_iconv_t *cd = (rec_iconv_t *)_cd;\r
-    ushort wbuf[MB_CHAR_MAX]; /* enough room for one character */\r
-    int insize;\r
-    int outsize;\r
-    int wsize;\r
-    DWORD frommode;\r
-    DWORD tomode;\r
-    uint wc;\r
-    compat_t *cp;\r
-    int i;\r
-\r
-    if (inbuf == NULL || *inbuf == NULL)\r
-    {\r
-        if (outbuf != NULL && *outbuf != NULL && cd->to.flush != NULL)\r
-        {\r
-            tomode = cd->to.mode;\r
-            outsize = cd->to.flush(&cd->to, (uchar *)*outbuf, *outbytesleft);\r
-            if (outsize == -1)\r
-            {\r
-                cd->to.mode = tomode;\r
-                return (size_t)(-1);\r
-            }\r
-            *outbuf += outsize;\r
-            *outbytesleft -= outsize;\r
-        }\r
-        cd->from.mode = 0;\r
-        cd->to.mode = 0;\r
-        return 0;\r
-    }\r
-\r
-    while (*inbytesleft != 0)\r
-    {\r
-        frommode = cd->from.mode;\r
-        tomode = cd->to.mode;\r
-        wsize = MB_CHAR_MAX;\r
-\r
-        insize = cd->from.mbtowc(&cd->from, (const uchar *)*inbuf, *inbytesleft, wbuf, &wsize);\r
-        if (insize == -1)\r
-        {\r
-            cd->from.mode = frommode;\r
-            return (size_t)(-1);\r
-        }\r
-\r
-        if (wsize == 0)\r
-        {\r
-            *inbuf += insize;\r
-            *inbytesleft -= insize;\r
-            continue;\r
-        }\r
-\r
-        if (cd->from.compat != NULL)\r
-        {\r
-            wc = utf16_to_ucs4(wbuf);\r
-            cp = cd->from.compat;\r
-            for (i = 0; cp[i].in != 0; ++i)\r
-            {\r
-                if ((cp[i].flag & COMPAT_IN) && cp[i].out == wc)\r
-                {\r
-                    ucs4_to_utf16(cp[i].in, wbuf, &wsize);\r
-                    break;\r
-                }\r
-            }\r
-        }\r
-\r
-        if (cd->to.compat != NULL)\r
-        {\r
-            wc = utf16_to_ucs4(wbuf);\r
-            cp = cd->to.compat;\r
-            for (i = 0; cp[i].in != 0; ++i)\r
-            {\r
-                if ((cp[i].flag & COMPAT_OUT) && cp[i].in == wc)\r
-                {\r
-                    ucs4_to_utf16(cp[i].out, wbuf, &wsize);\r
-                    break;\r
-                }\r
-            }\r
-        }\r
-\r
-        outsize = cd->to.wctomb(&cd->to, wbuf, wsize, (uchar *)*outbuf, *outbytesleft);\r
-        if (outsize == -1)\r
-        {\r
-            cd->from.mode = frommode;\r
-            cd->to.mode = tomode;\r
-            return (size_t)(-1);\r
-        }\r
-\r
-        *inbuf += insize;\r
-        *outbuf += outsize;\r
-        *inbytesleft -= insize;\r
-        *outbytesleft -= outsize;\r
-    }\r
-\r
-    return 0;\r
-}\r
-\r
-static int\r
-make_csconv(const char *_name, csconv_t *cv)\r
-{\r
-    CPINFOEX cpinfoex;\r
-    int use_compat = TRUE;\r
-    int flag = 0;\r
-    char *name;\r
-    char *p;\r
-\r
-    name = xstrndup(_name, strlen(_name));\r
-    if (name == NULL)\r
-        return FALSE;\r
-\r
-    /* check for option "enc_name//opt1//opt2" */\r
-    while ((p = strrstr(name, "//")) != NULL)\r
-    {\r
-        if (_stricmp(p + 2, "nocompat") == 0)\r
-            use_compat = FALSE;\r
-        else if (_stricmp(p + 2, "translit") == 0)\r
-            flag |= FLAG_TRANSLIT;\r
-        else if (_stricmp(p + 2, "ignore") == 0)\r
-            flag |= FLAG_IGNORE;\r
-        *p = 0;\r
-    }\r
-\r
-    cv->mode = 0;\r
-    cv->flags = flag;\r
-    cv->mblen = NULL;\r
-    cv->flush = NULL;\r
-    cv->compat = NULL;\r
-    cv->codepage = name_to_codepage(name);\r
-    if (cv->codepage == 1200 || cv->codepage == 1201)\r
-    {\r
-        cv->mbtowc = utf16_mbtowc;\r
-        cv->wctomb = utf16_wctomb;\r
-        if (_stricmp(name, "UTF-16") == 0 || _stricmp(name, "UTF16") == 0)\r
-            cv->flags |= FLAG_USE_BOM;\r
-    }\r
-    else if (cv->codepage == 12000 || cv->codepage == 12001)\r
-    {\r
-        cv->mbtowc = utf32_mbtowc;\r
-        cv->wctomb = utf32_wctomb;\r
-        if (_stricmp(name, "UTF-32") == 0 || _stricmp(name, "UTF32") == 0)\r
-            cv->flags |= FLAG_USE_BOM;\r
-    }\r
-    else if (cv->codepage == 65001)\r
-    {\r
-        cv->mbtowc = kernel_mbtowc;\r
-        cv->wctomb = kernel_wctomb;\r
-        cv->mblen = utf8_mblen;\r
-    }\r
-    else if ((cv->codepage == 50220 || cv->codepage == 50221 || cv->codepage == 50222) && load_mlang())\r
-    {\r
-        cv->mbtowc = iso2022jp_mbtowc;\r
-        cv->wctomb = iso2022jp_wctomb;\r
-        cv->flush = iso2022jp_flush;\r
-    }\r
-    else if (cv->codepage == 51932 && load_mlang())\r
-    {\r
-        cv->mbtowc = mlang_mbtowc;\r
-        cv->wctomb = mlang_wctomb;\r
-        cv->mblen = eucjp_mblen;\r
-    }\r
-    else if (IsValidCodePage(cv->codepage)\r
-            && GetCPInfoEx(cv->codepage, 0, &cpinfoex) != 0)\r
-    {\r
-        cv->mbtowc = kernel_mbtowc;\r
-        cv->wctomb = kernel_wctomb;\r
-        if (cpinfoex.MaxCharSize == 1)\r
-            cv->mblen = sbcs_mblen;\r
-        else if (cpinfoex.MaxCharSize == 2)\r
-            cv->mblen = dbcs_mblen;\r
-       else\r
-           cv->mblen = mbcs_mblen;\r
-    }\r
-    else\r
-    {\r
-        /* not supported */\r
-        free(name);\r
-        errno = EINVAL;\r
-        return FALSE;\r
-    }\r
-\r
-    if (use_compat)\r
-    {\r
-        switch (cv->codepage)\r
-        {\r
-        case 932: cv->compat = cp932_compat; break;\r
-        case 20932: cv->compat = cp20932_compat; break;\r
-        case 51932: cv->compat = cp51932_compat; break;\r
-        case 50220: case 50221: case 50222: cv->compat = cp5022x_compat; break;\r
-        }\r
-    }\r
-\r
-    free(name);\r
-\r
-    return TRUE;\r
-}\r
-\r
-static int\r
-name_to_codepage(const char *name)\r
-{\r
-    int i;\r
-\r
-    if (*name == '\0' ||\r
-       strcmp(name, "char") == 0)\r
-        return GetACP();\r
-    else if (strcmp(name, "wchar_t") == 0)\r
-        return 1200;\r
-    else if (_strnicmp(name, "cp", 2) == 0)\r
-        return atoi(name + 2); /* CP123 */\r
-    else if ('0' <= name[0] && name[0] <= '9')\r
-        return atoi(name);     /* 123 */\r
-    else if (_strnicmp(name, "xx", 2) == 0)\r
-        return atoi(name + 2); /* XX123 for debug */\r
-\r
-    for (i = 0; codepage_alias[i].name != NULL; ++i)\r
-        if (_stricmp(name, codepage_alias[i].name) == 0)\r
-            return codepage_alias[i].codepage;\r
-    return -1;\r
-}\r
-\r
-/*\r
- * http://www.faqs.org/rfcs/rfc2781.html\r
- */\r
-static uint\r
-utf16_to_ucs4(const ushort *wbuf)\r
-{\r
-    uint wc = wbuf[0];\r
-    if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)\r
-        wc = ((wbuf[0] & 0x3FF) << 10) + (wbuf[1] & 0x3FF) + 0x10000;\r
-    return wc;\r
-}\r
-\r
-static void\r
-ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize)\r
-{\r
-    if (wc < 0x10000)\r
-    {\r
-        wbuf[0] = wc;\r
-        *wbufsize = 1;\r
-    }\r
-    else\r
-    {\r
-        wc -= 0x10000;\r
-        wbuf[0] = 0xD800 | ((wc >> 10) & 0x3FF);\r
-        wbuf[1] = 0xDC00 | (wc & 0x3FF);\r
-        *wbufsize = 2;\r
-    }\r
-}\r
-\r
-/*\r
- * Check if codepage is one of those for which the dwFlags parameter\r
- * to MultiByteToWideChar() must be zero. Return zero or\r
- * MB_ERR_INVALID_CHARS.  The docs in Platform SDK for for Windows\r
- * Server 2003 R2 claims that also codepage 65001 is one of these, but\r
- * that doesn't seem to be the case. The MSDN docs for MSVS2008 leave\r
- * out 65001 (UTF-8), and that indeed seems to be the case on XP, it\r
- * works fine to pass MB_ERR_INVALID_CHARS in dwFlags when converting\r
- * from UTF-8.\r
- */\r
-static int\r
-mbtowc_flags(int codepage)\r
-{\r
-    return (codepage == 50220 || codepage == 50221 ||\r
-           codepage == 50222 || codepage == 50225 ||\r
-           codepage == 50227 || codepage == 50229 ||\r
-           codepage == 52936 || codepage == 54936 ||\r
-           (codepage >= 57002 && codepage <= 57011) ||\r
-           codepage == 65000 || codepage == 42) ? 0 : MB_ERR_INVALID_CHARS;\r
-}\r
-\r
-/*\r
- * Check if codepage is one those for which the lpUsedDefaultChar\r
- * parameter to WideCharToMultiByte() must be NULL.  The docs in\r
- * Platform SDK for for Windows Server 2003 R2 claims that this is the\r
- * list below, while the MSDN docs for MSVS2008 claim that it is only\r
- * for 65000 (UTF-7) and 65001 (UTF-8). This time the earlier Platform\r
- * SDK seems to be correct, at least for XP.\r
- */\r
-static int\r
-must_use_null_useddefaultchar(int codepage)\r
-{\r
-    return (codepage == 65000 || codepage == 65001 ||\r
-            codepage == 50220 || codepage == 50221 ||\r
-            codepage == 50222 || codepage == 50225 ||\r
-            codepage == 50227 || codepage == 50229 ||\r
-            codepage == 52936 || codepage == 54936 ||\r
-            (codepage >= 57002 && codepage <= 57011) ||\r
-            codepage == 42);\r
-}\r
-\r
-static char *\r
-strrstr(const char *str, const char *token)\r
-{\r
-    int len = strlen(token);\r
-    const char *p = str + strlen(str);\r
-\r
-    while (str <= --p)\r
-        if (p[0] == token[0] && strncmp(p, token, len) == 0)\r
-            return (char *)p;\r
-    return NULL;\r
-}\r
-\r
-static char *\r
-xstrndup(const char *s, size_t n)\r
-{\r
-    char *p;\r
-\r
-    p = (char *)malloc(n + 1);\r
-    if (p == NULL)\r
-        return NULL;\r
-    memcpy(p, s, n);\r
-    p[n] = '\0';\r
-    return p;\r
-}\r
-\r
-static int\r
-seterror(int err)\r
-{\r
-    errno = err;\r
-    return -1;\r
-}\r
-\r
-#if defined(USE_LIBICONV_DLL)\r
-static int\r
-libiconv_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode)\r
-{\r
-    HMODULE hlibiconv = NULL;\r
-    HMODULE hmsvcrt = NULL;\r
-    char *dllname;\r
-    const char *p;\r
-    const char *e;\r
-    f_iconv_open _iconv_open;\r
-\r
-    /*\r
-     * always try to load dll, so that we can switch dll in runtime.\r
-     */\r
-\r
-    /* XXX: getenv() can't get variable set by SetEnvironmentVariable() */\r
-    p = getenv("WINICONV_LIBICONV_DLL");\r
-    if (p == NULL)\r
-        p = DEFAULT_LIBICONV_DLL;\r
-    /* parse comma separated value */\r
-    for ( ; *p != 0; p = (*e == ',') ? e + 1 : e)\r
-    {\r
-        e = strchr(p, ',');\r
-        if (p == e)\r
-            continue;\r
-        else if (e == NULL)\r
-            e = p + strlen(p);\r
-        dllname = xstrndup(p, e - p);\r
-        if (dllname == NULL)\r
-            return FALSE;\r
-        hlibiconv = LoadLibrary(dllname);\r
-        free(dllname);\r
-        if (hlibiconv != NULL)\r
-        {\r
-            if (hlibiconv == hwiniconv)\r
-            {\r
-                FreeLibrary(hlibiconv);\r
-                hlibiconv = NULL;\r
-                continue;\r
-            }\r
-            break;\r
-        }\r
-    }\r
-\r
-    if (hlibiconv == NULL)\r
-        goto failed;\r
-\r
-    hmsvcrt = find_imported_module_by_funcname(hlibiconv, "_errno");\r
-    if (hmsvcrt == NULL)\r
-        goto failed;\r
-\r
-    _iconv_open = (f_iconv_open)GetProcAddress(hlibiconv, "libiconv_open");\r
-    if (_iconv_open == NULL)\r
-        _iconv_open = (f_iconv_open)GetProcAddress(hlibiconv, "iconv_open");\r
-    cd->iconv_close = (f_iconv_close)GetProcAddress(hlibiconv, "libiconv_close");\r
-    if (cd->iconv_close == NULL)\r
-        cd->iconv_close = (f_iconv_close)GetProcAddress(hlibiconv, "iconv_close");\r
-    cd->iconv = (f_iconv)GetProcAddress(hlibiconv, "libiconv");\r
-    if (cd->iconv == NULL)\r
-        cd->iconv = (f_iconv)GetProcAddress(hlibiconv, "iconv");\r
-    cd->_errno = (f_errno)GetProcAddress(hmsvcrt, "_errno");\r
-    if (_iconv_open == NULL || cd->iconv_close == NULL\r
-            || cd->iconv == NULL || cd->_errno == NULL)\r
-        goto failed;\r
-\r
-    cd->cd = _iconv_open(tocode, fromcode);\r
-    if (cd->cd == (iconv_t)(-1))\r
-        goto failed;\r
-\r
-    cd->hlibiconv = hlibiconv;\r
-    return TRUE;\r
-\r
-failed:\r
-    if (hlibiconv != NULL)\r
-        FreeLibrary(hlibiconv);\r
-    /* do not free hmsvcrt which is obtained by GetModuleHandle() */\r
-    return FALSE;\r
-}\r
-\r
-/*\r
- * Reference:\r
- * http://forums.belution.com/ja/vc/000/234/78s.shtml\r
- * http://nienie.com/~masapico/api_ImageDirectoryEntryToData.html\r
- *\r
- * The formal way is\r
- *   imagehlp.h or dbghelp.h\r
- *   imagehlp.lib or dbghelp.lib\r
- *   ImageDirectoryEntryToData()\r
- */\r
-#define TO_DOS_HEADER(base) ((PIMAGE_DOS_HEADER)(base))\r
-#define TO_NT_HEADERS(base) ((PIMAGE_NT_HEADERS)((LPBYTE)(base) + TO_DOS_HEADER(base)->e_lfanew))\r
-static PVOID\r
-MyImageDirectoryEntryToData(LPVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size)\r
-{\r
-    /* TODO: MappedAsImage? */\r
-    PIMAGE_DATA_DIRECTORY p;\r
-    p = TO_NT_HEADERS(Base)->OptionalHeader.DataDirectory + DirectoryEntry;\r
-    if (p->VirtualAddress == 0) {\r
-      *Size = 0;\r
-      return NULL;\r
-    }\r
-    *Size = p->Size;\r
-    return (PVOID)((LPBYTE)Base + p->VirtualAddress);\r
-}\r
-\r
-static HMODULE\r
-find_imported_module_by_funcname(HMODULE hModule, const char *funcname)\r
-{\r
-    DWORD Base;\r
-    ULONG Size;\r
-    PIMAGE_IMPORT_DESCRIPTOR Imp;\r
-    PIMAGE_THUNK_DATA Name;         /* Import Name Table */\r
-    PIMAGE_IMPORT_BY_NAME ImpName;\r
-\r
-    Base = (DWORD)hModule;\r
-    Imp = MyImageDirectoryEntryToData(\r
-            (LPVOID)Base,\r
-            TRUE,\r
-            IMAGE_DIRECTORY_ENTRY_IMPORT,\r
-            &Size);\r
-    if (Imp == NULL)\r
-        return NULL;\r
-    for ( ; Imp->OriginalFirstThunk != 0; ++Imp)\r
-    {\r
-        Name = (PIMAGE_THUNK_DATA)(Base + Imp->OriginalFirstThunk);\r
-        for ( ; Name->u1.Ordinal != 0; ++Name)\r
-        {\r
-            if (!IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal))\r
-            {\r
-                ImpName = (PIMAGE_IMPORT_BY_NAME)\r
-                    (Base + (DWORD)Name->u1.AddressOfData);\r
-                if (strcmp((char *)ImpName->Name, funcname) == 0)\r
-                    return GetModuleHandle((char *)(Base + Imp->Name));\r
-            }\r
-        }\r
-    }\r
-    return NULL;\r
-}\r
-#endif\r
-\r
-static int\r
-sbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)\r
-{\r
-    return 1;\r
-}\r
-\r
-static int\r
-dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)\r
-{\r
-    int len = IsDBCSLeadByteEx(cv->codepage, buf[0]) ? 2 : 1;\r
-    if (bufsize < len)\r
-        return seterror(EINVAL);\r
-    return len;\r
-}\r
-\r
-static int\r
-mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)\r
-{\r
-    int len = 0;\r
-\r
-    if (cv->codepage == 54936) {\r
-       if (buf[0] <= 0x7F) len = 1;\r
-       else if (buf[0] >= 0x81 && buf[0] <= 0xFE &&\r
-                bufsize >= 2 &&\r
-                ((buf[1] >= 0x40 && buf[1] <= 0x7E) ||\r
-                 (buf[1] >= 0x80 && buf[1] <= 0xFE))) len = 2;\r
-       else if (buf[0] >= 0x81 && buf[0] <= 0xFE &&\r
-                bufsize >= 4 &&\r
-                buf[1] >= 0x30 && buf[1] <= 0x39) len = 4;\r
-       else\r
-           return seterror(EINVAL);\r
-       return len;\r
-    }\r
-    else\r
-       return seterror(EINVAL);\r
-}\r
-\r
-static int\r
-utf8_mblen(csconv_t *cv, const uchar *buf, int bufsize)\r
-{\r
-    int len = 0;\r
-\r
-    if (buf[0] < 0x80) len = 1;\r
-    else if ((buf[0] & 0xE0) == 0xC0) len = 2;\r
-    else if ((buf[0] & 0xF0) == 0xE0) len = 3;\r
-    else if ((buf[0] & 0xF8) == 0xF0) len = 4;\r
-    else if ((buf[0] & 0xFC) == 0xF8) len = 5;\r
-    else if ((buf[0] & 0xFE) == 0xFC) len = 6;\r
-\r
-    if (len == 0)\r
-        return seterror(EILSEQ);\r
-    else if (bufsize < len)\r
-        return seterror(EINVAL);\r
-    return len;\r
-}\r
-\r
-static int\r
-eucjp_mblen(csconv_t *cv, const uchar *buf, int bufsize)\r
-{\r
-    if (buf[0] < 0x80) /* ASCII */\r
-        return 1;\r
-    else if (buf[0] == 0x8E) /* JIS X 0201 */\r
-    {\r
-        if (bufsize < 2)\r
-            return seterror(EINVAL);\r
-        else if (!(0xA1 <= buf[1] && buf[1] <= 0xDF))\r
-            return seterror(EILSEQ);\r
-        return 2;\r
-    }\r
-    else if (buf[0] == 0x8F) /* JIS X 0212 */\r
-    {\r
-        if (bufsize < 3)\r
-            return seterror(EINVAL);\r
-        else if (!(0xA1 <= buf[1] && buf[1] <= 0xFE)\r
-                || !(0xA1 <= buf[2] && buf[2] <= 0xFE))\r
-            return seterror(EILSEQ);\r
-        return 3;\r
-    }\r
-    else /* JIS X 0208 */\r
-    {\r
-        if (bufsize < 2)\r
-            return seterror(EINVAL);\r
-        else if (!(0xA1 <= buf[0] && buf[0] <= 0xFE)\r
-                || !(0xA1 <= buf[1] && buf[1] <= 0xFE))\r
-            return seterror(EILSEQ);\r
-        return 2;\r
-    }\r
-}\r
-\r
-static int\r
-kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)\r
-{\r
-    int len;\r
-\r
-    len = cv->mblen(cv, buf, bufsize);\r
-    if (len == -1)\r
-        return -1;\r
-    *wbufsize = MultiByteToWideChar(cv->codepage, mbtowc_flags (cv->codepage),\r
-            (const char *)buf, len, (wchar_t *)wbuf, *wbufsize);\r
-    if (*wbufsize == 0)\r
-        return seterror(EILSEQ);\r
-    return len;\r
-}\r
-\r
-static int\r
-kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)\r
-{\r
-    BOOL usedDefaultChar = 0;\r
-    BOOL *p = NULL;\r
-    int flags = 0;\r
-    int len;\r
-\r
-    if (bufsize == 0)\r
-        return seterror(E2BIG);\r
-    if (!must_use_null_useddefaultchar(cv->codepage))\r
-    {\r
-        p = &usedDefaultChar;\r
-#ifdef WC_NO_BEST_FIT_CHARS\r
-        if (!(cv->flags & FLAG_TRANSLIT))\r
-            flags |= WC_NO_BEST_FIT_CHARS;\r
-#endif\r
-    }\r
-    len = WideCharToMultiByte(cv->codepage, flags,\r
-            (const wchar_t *)wbuf, wbufsize, (char *)buf, bufsize, NULL, p);\r
-    if (len == 0)\r
-    {\r
-        if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)\r
-            return seterror(E2BIG);\r
-        return seterror(EILSEQ);\r
-    }\r
-    else if (usedDefaultChar)\r
-        return seterror(EILSEQ);\r
-    else if (cv->mblen(cv, buf, len) != len) /* validate result */\r
-        return seterror(EILSEQ);\r
-    return len;\r
-}\r
-\r
-/*\r
- * It seems that the mode (cv->mode) is fixnum.\r
- * For example, when converting iso-2022-jp(cp50221) to unicode:\r
- *      in ascii sequence: mode=0xC42C0000\r
- *   in jisx0208 sequence: mode=0xC42C0001\r
- * "C42C" is same for each convert session.\r
- * It should be: ((codepage-1)<<16)|state\r
- */\r
-static int\r
-mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)\r
-{\r
-    int len;\r
-    int insize;\r
-    HRESULT hr;\r
-\r
-    len = cv->mblen(cv, buf, bufsize);\r
-    if (len == -1)\r
-        return -1;\r
-    insize = len;\r
-    hr = ConvertINetMultiByteToUnicode(&cv->mode, cv->codepage,\r
-            (const char *)buf, &insize, (wchar_t *)wbuf, wbufsize);\r
-    if (hr != S_OK || insize != len)\r
-        return seterror(EILSEQ);\r
-    return len;\r
-}\r
-\r
-static int\r
-mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)\r
-{\r
-    char tmpbuf[MB_CHAR_MAX]; /* enough room for one character */\r
-    int tmpsize = MB_CHAR_MAX;\r
-    int insize = wbufsize;\r
-    HRESULT hr;\r
-\r
-    hr = ConvertINetUnicodeToMultiByte(&cv->mode, cv->codepage,\r
-            (const wchar_t *)wbuf, &wbufsize, tmpbuf, &tmpsize);\r
-    if (hr != S_OK || insize != wbufsize)\r
-        return seterror(EILSEQ);\r
-    else if (bufsize < tmpsize)\r
-        return seterror(E2BIG);\r
-    else if (cv->mblen(cv, (uchar *)tmpbuf, tmpsize) != tmpsize)\r
-        return seterror(EILSEQ);\r
-    memcpy(buf, tmpbuf, tmpsize);\r
-    return tmpsize;\r
-}\r
-\r
-static int\r
-utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)\r
-{\r
-    int codepage = cv->codepage;\r
-\r
-    /* swap endian: 1200 <-> 1201 */\r
-    if (cv->mode & UNICODE_MODE_SWAPPED)\r
-        codepage ^= 1;\r
-\r
-    if (bufsize < 2)\r
-        return seterror(EINVAL);\r
-    if (codepage == 1200) /* little endian */\r
-        wbuf[0] = (buf[1] << 8) | buf[0];\r
-    else if (codepage == 1201) /* big endian */\r
-        wbuf[0] = (buf[0] << 8) | buf[1];\r
-\r
-    if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))\r
-    {\r
-        cv->mode |= UNICODE_MODE_BOM_DONE;\r
-        if (wbuf[0] == 0xFFFE)\r
-        {\r
-            cv->mode |= UNICODE_MODE_SWAPPED;\r
-            *wbufsize = 0;\r
-            return 2;\r
-        }\r
-        else if (wbuf[0] == 0xFEFF)\r
-        {\r
-            *wbufsize = 0;\r
-            return 2;\r
-        }\r
-    }\r
-\r
-    if (0xDC00 <= wbuf[0] && wbuf[0] <= 0xDFFF)\r
-        return seterror(EILSEQ);\r
-    if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)\r
-    {\r
-        if (bufsize < 4)\r
-            return seterror(EINVAL);\r
-        if (codepage == 1200) /* little endian */\r
-            wbuf[1] = (buf[3] << 8) | buf[2];\r
-        else if (codepage == 1201) /* big endian */\r
-            wbuf[1] = (buf[2] << 8) | buf[3];\r
-        if (!(0xDC00 <= wbuf[1] && wbuf[1] <= 0xDFFF))\r
-            return seterror(EILSEQ);\r
-        *wbufsize = 2;\r
-        return 4;\r
-    }\r
-    *wbufsize = 1;\r
-    return 2;\r
-}\r
-\r
-static int\r
-utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)\r
-{\r
-    if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))\r
-    {\r
-        int r;\r
-\r
-        cv->mode |= UNICODE_MODE_BOM_DONE;\r
-        if (bufsize < 2)\r
-            return seterror(E2BIG);\r
-        if (cv->codepage == 1200) /* little endian */\r
-            memcpy(buf, "\xFF\xFE", 2);\r
-        else if (cv->codepage == 1201) /* big endian */\r
-            memcpy(buf, "\xFE\xFF", 2);\r
-\r
-        r = utf16_wctomb(cv, wbuf, wbufsize, buf + 2, bufsize - 2);\r
-        if (r == -1)\r
-            return -1;\r
-        return r + 2;\r
-    }\r
-\r
-    if (bufsize < 2)\r
-        return seterror(E2BIG);\r
-    if (cv->codepage == 1200) /* little endian */\r
-    {\r
-        buf[0] = (wbuf[0] & 0x00FF);\r
-        buf[1] = (wbuf[0] & 0xFF00) >> 8;\r
-    }\r
-    else if (cv->codepage == 1201) /* big endian */\r
-    {\r
-        buf[0] = (wbuf[0] & 0xFF00) >> 8;\r
-        buf[1] = (wbuf[0] & 0x00FF);\r
-    }\r
-    if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)\r
-    {\r
-        if (bufsize < 4)\r
-            return seterror(E2BIG);\r
-        if (cv->codepage == 1200) /* little endian */\r
-        {\r
-            buf[2] = (wbuf[1] & 0x00FF);\r
-            buf[3] = (wbuf[1] & 0xFF00) >> 8;\r
-        }\r
-        else if (cv->codepage == 1201) /* big endian */\r
-        {\r
-            buf[2] = (wbuf[1] & 0xFF00) >> 8;\r
-            buf[3] = (wbuf[1] & 0x00FF);\r
-        }\r
-        return 4;\r
-    }\r
-    return 2;\r
-}\r
-\r
-static int\r
-utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)\r
-{\r
-    int codepage = cv->codepage;\r
-    uint wc = 0;\r
-\r
-    /* swap endian: 12000 <-> 12001 */\r
-    if (cv->mode & UNICODE_MODE_SWAPPED)\r
-        codepage ^= 1;\r
-\r
-    if (bufsize < 4)\r
-        return seterror(EINVAL);\r
-    if (codepage == 12000) /* little endian */\r
-        wc = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];\r
-    else if (codepage == 12001) /* big endian */\r
-        wc = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];\r
-\r
-    if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))\r
-    {\r
-        cv->mode |= UNICODE_MODE_BOM_DONE;\r
-        if (wc == 0xFFFE0000)\r
-        {\r
-            cv->mode |= UNICODE_MODE_SWAPPED;\r
-            *wbufsize = 0;\r
-            return 4;\r
-        }\r
-        else if (wc == 0x0000FEFF)\r
-        {\r
-            *wbufsize = 0;\r
-            return 4;\r
-        }\r
-    }\r
-\r
-    if ((0xD800 <= wc && wc <= 0xDFFF) || 0x10FFFF < wc)\r
-        return seterror(EILSEQ);\r
-    ucs4_to_utf16(wc, wbuf, wbufsize);\r
-    return 4;\r
-}\r
-\r
-static int\r
-utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)\r
-{\r
-    uint wc;\r
-\r
-    if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))\r
-    {\r
-        int r;\r
-\r
-        cv->mode |= UNICODE_MODE_BOM_DONE;\r
-        if (bufsize < 4)\r
-            return seterror(E2BIG);\r
-        if (cv->codepage == 12000) /* little endian */\r
-            memcpy(buf, "\xFF\xFE\x00\x00", 4);\r
-        else if (cv->codepage == 12001) /* big endian */\r
-            memcpy(buf, "\x00\x00\xFE\xFF", 4);\r
-\r
-        r = utf32_wctomb(cv, wbuf, wbufsize, buf + 4, bufsize - 4);\r
-        if (r == -1)\r
-            return -1;\r
-        return r + 4;\r
-    }\r
-\r
-    if (bufsize < 4)\r
-        return seterror(E2BIG);\r
-    wc = utf16_to_ucs4(wbuf);\r
-    if (cv->codepage == 12000) /* little endian */\r
-    {\r
-        buf[0] = wc & 0x000000FF;\r
-        buf[1] = (wc & 0x0000FF00) >> 8;\r
-        buf[2] = (wc & 0x00FF0000) >> 16;\r
-        buf[3] = (wc & 0xFF000000) >> 24;\r
-    }\r
-    else if (cv->codepage == 12001) /* big endian */\r
-    {\r
-        buf[0] = (wc & 0xFF000000) >> 24;\r
-        buf[1] = (wc & 0x00FF0000) >> 16;\r
-        buf[2] = (wc & 0x0000FF00) >> 8;\r
-        buf[3] = wc & 0x000000FF;\r
-    }\r
-    return 4;\r
-}\r
-\r
-/*\r
- * 50220: ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS)\r
- * 50221: ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow\r
- *        1 byte Kana)\r
- * 50222: ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte\r
- *        Kana - SO/SI)\r
- *\r
- * MultiByteToWideChar() and WideCharToMultiByte() behave differently\r
- * depending on Windows version.  On XP, WideCharToMultiByte() doesn't\r
- * terminate result sequence with ascii escape.  But Vista does.\r
- * Use MLang instead.\r
- */\r
-\r
-#define ISO2022_MODE(cs, shift) (((cs) << 8) | (shift))\r
-#define ISO2022_MODE_CS(mode) (((mode) >> 8) & 0xFF)\r
-#define ISO2022_MODE_SHIFT(mode) ((mode) & 0xFF)\r
-\r
-#define ISO2022_SI  0\r
-#define ISO2022_SO  1\r
-\r
-/* shift in */\r
-static const char iso2022_SI_seq[] = "\x0F";\r
-/* shift out */\r
-static const char iso2022_SO_seq[] = "\x0E";\r
-\r
-typedef struct iso2022_esc_t iso2022_esc_t;\r
-struct iso2022_esc_t {\r
-    const char *esc;\r
-    int esc_len;\r
-    int len;\r
-    int cs;\r
-};\r
-\r
-#define ISO2022JP_CS_ASCII            0\r
-#define ISO2022JP_CS_JISX0201_ROMAN   1\r
-#define ISO2022JP_CS_JISX0201_KANA    2\r
-#define ISO2022JP_CS_JISX0208_1978    3\r
-#define ISO2022JP_CS_JISX0208_1983    4\r
-#define ISO2022JP_CS_JISX0212         5\r
-\r
-static iso2022_esc_t iso2022jp_esc[] = {\r
-    {"\x1B\x28\x42", 3, 1, ISO2022JP_CS_ASCII},\r
-    {"\x1B\x28\x4A", 3, 1, ISO2022JP_CS_JISX0201_ROMAN},\r
-    {"\x1B\x28\x49", 3, 1, ISO2022JP_CS_JISX0201_KANA},\r
-    {"\x1B\x24\x40", 3, 2, ISO2022JP_CS_JISX0208_1983}, /* unify 1978 with 1983 */\r
-    {"\x1B\x24\x42", 3, 2, ISO2022JP_CS_JISX0208_1983},\r
-    {"\x1B\x24\x28\x44", 4, 2, ISO2022JP_CS_JISX0212},\r
-    {NULL, 0, 0, 0}\r
-};\r
-\r
-static int\r
-iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)\r
-{\r
-    iso2022_esc_t *iesc = iso2022jp_esc;\r
-    char tmp[MB_CHAR_MAX];\r
-    int insize;\r
-    HRESULT hr;\r
-    DWORD dummy = 0;\r
-    int len;\r
-    int esc_len;\r
-    int cs;\r
-    int shift;\r
-    int i;\r
-\r
-    if (buf[0] == 0x1B)\r
-    {\r
-        for (i = 0; iesc[i].esc != NULL; ++i)\r
-        {\r
-            esc_len = iesc[i].esc_len;\r
-            if (bufsize < esc_len)\r
-            {\r
-                if (strncmp((char *)buf, iesc[i].esc, bufsize) == 0)\r
-                    return seterror(EINVAL);\r
-            }\r
-            else\r
-            {\r
-                if (strncmp((char *)buf, iesc[i].esc, esc_len) == 0)\r
-                {\r
-                    cv->mode = ISO2022_MODE(iesc[i].cs, ISO2022_SI);\r
-                    *wbufsize = 0;\r
-                    return esc_len;\r
-                }\r
-            }\r
-        }\r
-        /* not supported escape sequence */\r
-        return seterror(EILSEQ);\r
-    }\r
-    else if (buf[0] == iso2022_SO_seq[0])\r
-    {\r
-        cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SO);\r
-        *wbufsize = 0;\r
-        return 1;\r
-    }\r
-    else if (buf[0] == iso2022_SI_seq[0])\r
-    {\r
-        cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SI);\r
-        *wbufsize = 0;\r
-        return 1;\r
-    }\r
-\r
-    cs = ISO2022_MODE_CS(cv->mode);\r
-    shift = ISO2022_MODE_SHIFT(cv->mode);\r
-\r
-    /* reset the mode for informal sequence */\r
-    if (buf[0] < 0x20)\r
-    {\r
-        cs = ISO2022JP_CS_ASCII;\r
-        shift = ISO2022_SI;\r
-    }\r
-\r
-    len = iesc[cs].len;\r
-    if (bufsize < len)\r
-        return seterror(EINVAL);\r
-    for (i = 0; i < len; ++i)\r
-        if (!(buf[i] < 0x80))\r
-            return seterror(EILSEQ);\r
-    esc_len = iesc[cs].esc_len;\r
-    memcpy(tmp, iesc[cs].esc, esc_len);\r
-    if (shift == ISO2022_SO)\r
-    {\r
-        memcpy(tmp + esc_len, iso2022_SO_seq, 1);\r
-        esc_len += 1;\r
-    }\r
-    memcpy(tmp + esc_len, buf, len);\r
-\r
-    if ((cv->codepage == 50220 || cv->codepage == 50221\r
-                || cv->codepage == 50222) && shift == ISO2022_SO)\r
-    {\r
-        /* XXX: shift-out cannot be used for mbtowc (both kernel and\r
-         * mlang) */\r
-        esc_len = iesc[ISO2022JP_CS_JISX0201_KANA].esc_len;\r
-        memcpy(tmp, iesc[ISO2022JP_CS_JISX0201_KANA].esc, esc_len);\r
-        memcpy(tmp + esc_len, buf, len);\r
-    }\r
-\r
-    insize = len + esc_len;\r
-    hr = ConvertINetMultiByteToUnicode(&dummy, cv->codepage,\r
-            (const char *)tmp, &insize, (wchar_t *)wbuf, wbufsize);\r
-    if (hr != S_OK || insize != len + esc_len)\r
-        return seterror(EILSEQ);\r
-\r
-    /* Check for conversion error.  Assuming defaultChar is 0x3F. */\r
-    /* ascii should be converted from ascii */\r
-    if (wbuf[0] == buf[0]\r
-            && cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI))\r
-        return seterror(EILSEQ);\r
-\r
-    /* reset the mode for informal sequence */\r
-    if (cv->mode != ISO2022_MODE(cs, shift))\r
-        cv->mode = ISO2022_MODE(cs, shift);\r
-\r
-    return len;\r
-}\r
-\r
-static int\r
-iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)\r
-{\r
-    iso2022_esc_t *iesc = iso2022jp_esc;\r
-    char tmp[MB_CHAR_MAX];\r
-    int tmpsize = MB_CHAR_MAX;\r
-    int insize = wbufsize;\r
-    HRESULT hr;\r
-    DWORD dummy = 0;\r
-    int len;\r
-    int esc_len = 0;\r
-    int cs = 0;\r
-    int shift;\r
-    int i;\r
-\r
-    /*\r
-     * MultiByte = [escape sequence] + character + [escape sequence]\r
-     *\r
-     * Whether trailing escape sequence is added depends on which API is\r
-     * used (kernel or MLang, and its version).\r
-     */\r
-    hr = ConvertINetUnicodeToMultiByte(&dummy, cv->codepage,\r
-            (const wchar_t *)wbuf, &wbufsize, tmp, &tmpsize);\r
-    if (hr != S_OK || insize != wbufsize)\r
-        return seterror(EILSEQ);\r
-    else if (bufsize < tmpsize)\r
-        return seterror(E2BIG);\r
-\r
-    if (tmpsize == 1)\r
-    {\r
-        cs = ISO2022JP_CS_ASCII;\r
-        esc_len = 0;\r
-    }\r
-    else\r
-    {\r
-        for (i = 1; iesc[i].esc != NULL; ++i)\r
-        {\r
-            esc_len = iesc[i].esc_len;\r
-            if (strncmp(tmp, iesc[i].esc, esc_len) == 0)\r
-            {\r
-                cs = iesc[i].cs;\r
-                break;\r
-            }\r
-        }\r
-        if (iesc[i].esc == NULL)\r
-            /* not supported escape sequence */\r
-            return seterror(EILSEQ);\r
-    }\r
-\r
-    shift = ISO2022_SI;\r
-    if (tmp[esc_len] == iso2022_SO_seq[0])\r
-    {\r
-        shift = ISO2022_SO;\r
-        esc_len += 1;\r
-    }\r
-\r
-    len = iesc[cs].len;\r
-\r
-    /* Check for converting error.  Assuming defaultChar is 0x3F. */\r
-    /* ascii should be converted from ascii */\r
-    if (cs == ISO2022JP_CS_ASCII && !(wbuf[0] < 0x80))\r
-        return seterror(EILSEQ);\r
-    else if (tmpsize < esc_len + len)\r
-        return seterror(EILSEQ);\r
-\r
-    if (cv->mode == ISO2022_MODE(cs, shift))\r
-    {\r
-        /* remove escape sequence */\r
-        if (esc_len != 0)\r
-            memmove(tmp, tmp + esc_len, len);\r
-        esc_len = 0;\r
-    }\r
-    else\r
-    {\r
-        if (cs == ISO2022JP_CS_ASCII)\r
-        {\r
-            esc_len = iesc[ISO2022JP_CS_ASCII].esc_len;\r
-            memmove(tmp + esc_len, tmp, len);\r
-            memcpy(tmp, iesc[ISO2022JP_CS_ASCII].esc, esc_len);\r
-        }\r
-        if (ISO2022_MODE_SHIFT(cv->mode) == ISO2022_SO)\r
-        {\r
-            /* shift-in before changing to other mode */\r
-            memmove(tmp + 1, tmp, len + esc_len);\r
-            memcpy(tmp, iso2022_SI_seq, 1);\r
-            esc_len += 1;\r
-        }\r
-    }\r
-\r
-    if (bufsize < len + esc_len)\r
-        return seterror(E2BIG);\r
-    memcpy(buf, tmp, len + esc_len);\r
-    cv->mode = ISO2022_MODE(cs, shift);\r
-    return len + esc_len;\r
-}\r
-\r
-static int\r
-iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize)\r
-{\r
-    iso2022_esc_t *iesc = iso2022jp_esc;\r
-    int esc_len;\r
-\r
-    if (cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI))\r
-    {\r
-        esc_len = 0;\r
-        if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI)\r
-            esc_len += 1;\r
-        if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII)\r
-            esc_len += iesc[ISO2022JP_CS_ASCII].esc_len;\r
-        if (bufsize < esc_len)\r
-            return seterror(E2BIG);\r
-\r
-        esc_len = 0;\r
-        if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI)\r
-        {\r
-            memcpy(buf, iso2022_SI_seq, 1);\r
-            esc_len += 1;\r
-        }\r
-        if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII)\r
-        {\r
-            memcpy(buf + esc_len, iesc[ISO2022JP_CS_ASCII].esc,\r
-                    iesc[ISO2022JP_CS_ASCII].esc_len);\r
-            esc_len += iesc[ISO2022JP_CS_ASCII].esc_len;\r
-        }\r
-        return esc_len;\r
-    }\r
-    return 0;\r
-}\r
-\r
-#if defined(MAKE_DLL) && defined(USE_LIBICONV_DLL)\r
-BOOL WINAPI\r
-DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)\r
-{\r
-    switch( fdwReason )\r
-    {\r
-    case DLL_PROCESS_ATTACH:\r
-        hwiniconv = (HMODULE)hinstDLL;\r
-        break;\r
-    case DLL_THREAD_ATTACH:\r
-    case DLL_THREAD_DETACH:\r
-    case DLL_PROCESS_DETACH:\r
-        break;\r
-    }\r
-    return TRUE;\r
-}\r
-#endif\r
-\r
-#if defined(MAKE_EXE)\r
-#include <stdio.h>\r
-#include <fcntl.h>\r
-#include <io.h>\r
-int\r
-main(int argc, char **argv)\r
-{\r
-    char *fromcode = NULL;\r
-    char *tocode = NULL;\r
-    int i;\r
-    char inbuf[BUFSIZ];\r
-    char outbuf[BUFSIZ];\r
-    const char *pin;\r
-    char *pout;\r
-    size_t inbytesleft;\r
-    size_t outbytesleft;\r
-    size_t rest = 0;\r
-    iconv_t cd;\r
-    size_t r;\r
-    FILE *in = stdin;\r
-\r
-    _setmode(_fileno(stdin), _O_BINARY);\r
-    _setmode(_fileno(stdout), _O_BINARY);\r
-\r
-    for (i = 1; i < argc; ++i)\r
-    {\r
-        if (strcmp(argv[i], "-l") == 0)\r
-        {\r
-            for (i = 0; codepage_alias[i].name != NULL; ++i)\r
-                printf("%s\n", codepage_alias[i].name);\r
-            return 0;\r
-        }\r
-\r
-        if (strcmp(argv[i], "-f") == 0)\r
-            fromcode = argv[++i];\r
-        else if (strcmp(argv[i], "-t") == 0)\r
-            tocode = argv[++i];\r
-        else\r
-        {\r
-            in = fopen(argv[i], "rb");\r
-            if (in == NULL)\r
-            {\r
-                fprintf(stderr, "cannot open %s\n", argv[i]);\r
-                return 1;\r
-            }\r
-            break;\r
-        }\r
-    }\r
-\r
-    if (fromcode == NULL || tocode == NULL)\r
-    {\r
-        printf("usage: %s -f from-enc -t to-enc [file]\n", argv[0]);\r
-        return 0;\r
-    }\r
-\r
-    cd = iconv_open(tocode, fromcode);\r
-    if (cd == (iconv_t)(-1))\r
-    {\r
-        perror("iconv_open error");\r
-        return 1;\r
-    }\r
-\r
-    while ((inbytesleft = fread(inbuf + rest, 1, sizeof(inbuf) - rest, in)) != 0\r
-            || rest != 0)\r
-    {\r
-        inbytesleft += rest;\r
-        pin = inbuf;\r
-        pout = outbuf;\r
-        outbytesleft = sizeof(outbuf);\r
-        r = iconv(cd, &pin, &inbytesleft, &pout, &outbytesleft);\r
-        fwrite(outbuf, 1, sizeof(outbuf) - outbytesleft, stdout);\r
-        if (r == (size_t)(-1) && errno != E2BIG && (errno != EINVAL || feof(in)))\r
-        {\r
-            perror("conversion error");\r
-            return 1;\r
-        }\r
-        memmove(inbuf, pin, inbytesleft);\r
-        rest = inbytesleft;\r
-    }\r
-    pout = outbuf;\r
-    outbytesleft = sizeof(outbuf);\r
-    r = iconv(cd, NULL, NULL, &pout, &outbytesleft);\r
-    fwrite(outbuf, 1, sizeof(outbuf) - outbytesleft, stdout);\r
-    if (r == (size_t)(-1))\r
-    {\r
-        perror("conversion error");\r
-        return 1;\r
-    }\r
-\r
-    iconv_close(cd);\r
-\r
-    return 0;\r
-}\r
-#endif\r
-\r
+/*
+ * iconv library using Win32 API to conversion.
+ *
+ * This file is placed in the public domain.
+ *
+ * Last Change: 2009-07-06
+ *
+ * ENVIRONMENT VARIABLE:
+ *     WINICONV_LIBICONV_DLL
+ *         If $WINICONV_LIBICONV_DLL is set, win_iconv uses the DLL.  If
+ *         loading the DLL or iconv_open() failed, falls back to internal
+ *         conversion.  If a few DLL are specified as comma separated list,
+ *         the first loadable DLL is used.  The DLL should have iconv_open(),
+ *         iconv_close() and iconv().  Or libiconv_open(), libiconv_close()
+ *         and libiconv().
+ *         (only available when USE_LIBICONV_DLL is defined at compile time)
+ *
+ * Win32 API does not support strict encoding conversion for some
+ * codepage.  And MLang function drop or replace invalid bytes and does
+ * not return useful error status as iconv.  This implementation cannot
+ * be used for encoding validation purpose.
+ */
+
+/* for WC_NO_BEST_FIT_CHARS */
+#ifndef WINVER
+# define WINVER 0x0500
+#endif
+
+#include <windows.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#if 0
+# define MAKE_EXE
+# define MAKE_DLL
+# define USE_LIBICONV_DLL
+#endif
+
+#if !defined(DEFAULT_LIBICONV_DLL)
+# define DEFAULT_LIBICONV_DLL ""
+#endif
+
+#define MB_CHAR_MAX 16
+
+#define UNICODE_MODE_BOM_DONE   1
+#define UNICODE_MODE_SWAPPED    2
+
+#define FLAG_USE_BOM            1
+#define FLAG_TRANSLIT           2 /* //TRANSLIT */
+#define FLAG_IGNORE             4 /* //IGNORE (not implemented) */
+
+typedef unsigned char uchar;
+typedef unsigned short ushort;
+typedef unsigned int uint;
+
+typedef void* iconv_t;
+
+iconv_t iconv_open(const char *tocode, const char *fromcode);
+int iconv_close(iconv_t cd);
+size_t iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
+
+/* libiconv interface for vim */
+#if defined(MAKE_DLL)
+int
+iconvctl (iconv_t cd, int request, void* argument)
+{
+    /* not supported */
+    return 0;
+}
+#endif
+
+typedef struct compat_t compat_t;
+typedef struct csconv_t csconv_t;
+typedef struct rec_iconv_t rec_iconv_t;
+
+typedef iconv_t (*f_iconv_open)(const char *tocode, const char *fromcode);
+typedef int (*f_iconv_close)(iconv_t cd);
+typedef size_t (*f_iconv)(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
+typedef int* (*f_errno)(void);
+typedef int (*f_mbtowc)(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
+typedef int (*f_wctomb)(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
+typedef int (*f_mblen)(csconv_t *cv, const uchar *buf, int bufsize);
+typedef int (*f_flush)(csconv_t *cv, uchar *buf, int bufsize);
+
+#define COMPAT_IN   1
+#define COMPAT_OUT  2
+
+/* unicode mapping for compatibility with other conversion table. */
+struct compat_t {
+    uint in;
+    uint out;
+    uint flag;
+};
+
+struct csconv_t {
+    int codepage;
+    int flags;
+    f_mbtowc mbtowc;
+    f_wctomb wctomb;
+    f_mblen mblen;
+    f_flush flush;
+    DWORD mode;
+    compat_t *compat;
+};
+
+struct rec_iconv_t {
+    iconv_t cd;
+    f_iconv_close iconv_close;
+    f_iconv iconv;
+    f_errno _errno;
+    csconv_t from;
+    csconv_t to;
+#if defined(USE_LIBICONV_DLL)
+    HMODULE hlibiconv;
+#endif
+};
+
+static int win_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode);
+static int win_iconv_close(iconv_t cd);
+static size_t win_iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
+
+static int load_mlang();
+static int make_csconv(const char *name, csconv_t *cv);
+static int name_to_codepage(const char *name);
+static uint utf16_to_ucs4(const ushort *wbuf);
+static void ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize);
+static int mbtowc_flags(int codepage);
+static int must_use_null_useddefaultchar(int codepage);
+static char *strrstr(const char *str, const char *token);
+static char *xstrndup(const char *s, size_t n);
+static int seterror(int err);
+
+#if defined(USE_LIBICONV_DLL)
+static int libiconv_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode);
+static PVOID MyImageDirectoryEntryToData(LPVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size);
+static HMODULE find_imported_module_by_funcname(HMODULE hModule, const char *funcname);
+
+static HMODULE hwiniconv;
+#endif
+
+static int sbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);
+static int dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);
+static int mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);
+static int utf8_mblen(csconv_t *cv, const uchar *buf, int bufsize);
+static int eucjp_mblen(csconv_t *cv, const uchar *buf, int bufsize);
+
+static int kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
+static int kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
+static int mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
+static int mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
+static int utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
+static int utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
+static int utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
+static int utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
+static int iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
+static int iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
+static int iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize);
+
+static struct {
+    int codepage;
+    const char *name;
+} codepage_alias[] = {
+    {65001, "CP65001"},
+    {65001, "UTF8"},
+    {65001, "UTF-8"},
+
+    {1200, "CP1200"},
+    {1200, "UTF16LE"},
+    {1200, "UTF-16LE"},
+    {1200, "UCS-2LE"},
+
+    {1201, "CP1201"},
+    {1201, "UTF16BE"},
+    {1201, "UTF-16BE"},
+    {1201, "UCS-2BE"},
+    {1201, "unicodeFFFE"},
+
+    {12000, "CP12000"},
+    {12000, "UTF32LE"},
+    {12000, "UTF-32LE"},
+
+    {12001, "CP12001"},
+    {12001, "UTF32BE"},
+    {12001, "UTF-32BE"},
+
+#ifndef GLIB_COMPILATION
+    /*
+     * Default is big endian.
+     * See rfc2781 4.3 Interpreting text labelled as UTF-16.
+     */
+    {1201, "UTF16"},
+    {1201, "UTF-16"},
+    {12001, "UTF32"},
+    {12001, "UTF-32"},
+#else
+    /* Default is little endian, because the platform is */
+    {1200, "UTF16"},
+    {1200, "UTF-16"},
+    {1200, "UCS-2"},
+    {12000, "UTF32"},
+    {12000, "UTF-32"},
+#endif
+
+    /* copy from libiconv `iconv -l` */
+    /* !IsValidCodePage(367) */
+    {20127, "ANSI_X3.4-1968"},
+    {20127, "ANSI_X3.4-1986"},
+    {20127, "ASCII"},
+    {20127, "CP367"},
+    {20127, "IBM367"},
+    {20127, "ISO-IR-6"},
+    {20127, "ISO646-US"},
+    {20127, "ISO_646.IRV:1991"},
+    {20127, "US"},
+    {20127, "US-ASCII"},
+    {20127, "CSASCII"},
+
+    /* !IsValidCodePage(819) */
+    {1252, "CP819"},
+    {1252, "IBM819"},
+    {28591, "ISO-8859-1"},
+    {28591, "ISO-IR-100"},
+    {28591, "ISO8859-1"},
+    {28591, "ISO_8859-1"},
+    {28591, "ISO_8859-1:1987"},
+    {28591, "L1"},
+    {28591, "LATIN1"},
+    {28591, "CSISOLATIN1"},
+
+    {1250, "CP1250"},
+    {1250, "MS-EE"},
+    {1250, "WINDOWS-1250"},
+
+    {1251, "CP1251"},
+    {1251, "MS-CYRL"},
+    {1251, "WINDOWS-1251"},
+
+    {1252, "CP1252"},
+    {1252, "MS-ANSI"},
+    {1252, "WINDOWS-1252"},
+
+    {1253, "CP1253"},
+    {1253, "MS-GREEK"},
+    {1253, "WINDOWS-1253"},
+
+    {1254, "CP1254"},
+    {1254, "MS-TURK"},
+    {1254, "WINDOWS-1254"},
+
+    {1255, "CP1255"},
+    {1255, "MS-HEBR"},
+    {1255, "WINDOWS-1255"},
+
+    {1256, "CP1256"},
+    {1256, "MS-ARAB"},
+    {1256, "WINDOWS-1256"},
+
+    {1257, "CP1257"},
+    {1257, "WINBALTRIM"},
+    {1257, "WINDOWS-1257"},
+
+    {1258, "CP1258"},
+    {1258, "WINDOWS-1258"},
+
+    {850, "850"},
+    {850, "CP850"},
+    {850, "IBM850"},
+    {850, "CSPC850MULTILINGUAL"},
+
+    /* !IsValidCodePage(862) */
+    {862, "862"},
+    {862, "CP862"},
+    {862, "IBM862"},
+    {862, "CSPC862LATINHEBREW"},
+
+    {866, "866"},
+    {866, "CP866"},
+    {866, "IBM866"},
+    {866, "CSIBM866"},
+
+    /* !IsValidCodePage(154) */
+    {154, "CP154"},
+    {154, "CYRILLIC-ASIAN"},
+    {154, "PT154"},
+    {154, "PTCP154"},
+    {154, "CSPTCP154"},
+
+    /* !IsValidCodePage(1133) */
+    {1133, "CP1133"},
+    {1133, "IBM-CP1133"},
+
+    {874, "CP874"},
+    {874, "WINDOWS-874"},
+
+    /* !IsValidCodePage(51932) */
+    {51932, "CP51932"},
+    {51932, "MS51932"},
+    {51932, "WINDOWS-51932"},
+    {51932, "EUC-JP"},
+
+    {932, "CP932"},
+    {932, "MS932"},
+    {932, "SHIFFT_JIS"},
+    {932, "SHIFFT_JIS-MS"},
+    {932, "SJIS"},
+    {932, "SJIS-MS"},
+    {932, "SJIS-OPEN"},
+    {932, "SJIS-WIN"},
+    {932, "WINDOWS-31J"},
+    {932, "WINDOWS-932"},
+    {932, "CSWINDOWS31J"},
+
+    {50221, "CP50221"},
+    {50221, "ISO-2022-JP"},
+    {50221, "ISO-2022-JP-MS"},
+    {50221, "ISO2022-JP"},
+    {50221, "ISO2022-JP-MS"},
+    {50221, "MS50221"},
+    {50221, "WINDOWS-50221"},
+
+    {936, "CP936"},
+    {936, "GBK"},
+    {936, "MS936"},
+    {936, "WINDOWS-936"},
+
+    {950, "CP950"},
+    {950, "BIG5"},
+
+    {949, "CP949"},
+    {949, "UHC"},
+    {949, "EUC-KR"},
+
+    {1361, "CP1361"},
+    {1361, "JOHAB"},
+
+    {437, "437"},
+    {437, "CP437"},
+    {437, "IBM437"},
+    {437, "CSPC8CODEPAGE437"},
+
+    {737, "CP737"},
+
+    {775, "CP775"},
+    {775, "IBM775"},
+    {775, "CSPC775BALTIC"},
+
+    {852, "852"},
+    {852, "CP852"},
+    {852, "IBM852"},
+    {852, "CSPCP852"},
+
+    /* !IsValidCodePage(853) */
+    {853, "CP853"},
+
+    {855, "855"},
+    {855, "CP855"},
+    {855, "IBM855"},
+    {855, "CSIBM855"},
+
+    {857, "857"},
+    {857, "CP857"},
+    {857, "IBM857"},
+    {857, "CSIBM857"},
+
+    /* !IsValidCodePage(858) */
+    {858, "CP858"},
+
+    {860, "860"},
+    {860, "CP860"},
+    {860, "IBM860"},
+    {860, "CSIBM860"},
+
+    {861, "861"},
+    {861, "CP-IS"},
+    {861, "CP861"},
+    {861, "IBM861"},
+    {861, "CSIBM861"},
+
+    {863, "863"},
+    {863, "CP863"},
+    {863, "IBM863"},
+    {863, "CSIBM863"},
+
+    {864, "CP864"},
+    {864, "IBM864"},
+    {864, "CSIBM864"},
+
+    {865, "865"},
+    {865, "CP865"},
+    {865, "IBM865"},
+    {865, "CSIBM865"},
+
+    {869, "869"},
+    {869, "CP-GR"},
+    {869, "CP869"},
+    {869, "IBM869"},
+    {869, "CSIBM869"},
+
+    /* !IsValidCodePage(1152) */
+    {1125, "CP1125"},
+
+    /*
+     * Code Page Identifiers
+     * http://msdn2.microsoft.com/en-us/library/ms776446.aspx
+     */
+    {37, "IBM037"}, /* IBM EBCDIC US-Canada */
+    {437, "IBM437"}, /* OEM United States */
+    {500, "IBM500"}, /* IBM EBCDIC International */
+    {708, "ASMO-708"}, /* Arabic (ASMO 708) */
+    /* 709             Arabic (ASMO-449+, BCON V4) */
+    /* 710             Arabic - Transparent Arabic */
+    {720, "DOS-720"}, /* Arabic (Transparent ASMO); Arabic (DOS) */
+    {737, "ibm737"}, /* OEM Greek (formerly 437G); Greek (DOS) */
+    {775, "ibm775"}, /* OEM Baltic; Baltic (DOS) */
+    {850, "ibm850"}, /* OEM Multilingual Latin 1; Western European (DOS) */
+    {852, "ibm852"}, /* OEM Latin 2; Central European (DOS) */
+    {855, "IBM855"}, /* OEM Cyrillic (primarily Russian) */
+    {857, "ibm857"}, /* OEM Turkish; Turkish (DOS) */
+    {858, "IBM00858"}, /* OEM Multilingual Latin 1 + Euro symbol */
+    {860, "IBM860"}, /* OEM Portuguese; Portuguese (DOS) */
+    {861, "ibm861"}, /* OEM Icelandic; Icelandic (DOS) */
+    {862, "DOS-862"}, /* OEM Hebrew; Hebrew (DOS) */
+    {863, "IBM863"}, /* OEM French Canadian; French Canadian (DOS) */
+    {864, "IBM864"}, /* OEM Arabic; Arabic (864) */
+    {865, "IBM865"}, /* OEM Nordic; Nordic (DOS) */
+    {866, "cp866"}, /* OEM Russian; Cyrillic (DOS) */
+    {869, "ibm869"}, /* OEM Modern Greek; Greek, Modern (DOS) */
+    {870, "IBM870"}, /* IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2 */
+    {874, "windows-874"}, /* ANSI/OEM Thai (same as 28605, ISO 8859-15); Thai (Windows) */
+    {875, "cp875"}, /* IBM EBCDIC Greek Modern */
+    {932, "shift_jis"}, /* ANSI/OEM Japanese; Japanese (Shift-JIS) */
+    {932, "shift-jis"}, /* alternative name for it */
+    {936, "gb2312"}, /* ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312) */
+    {949, "ks_c_5601-1987"}, /* ANSI/OEM Korean (Unified Hangul Code) */
+    {950, "big5"}, /* ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5) */
+    {1026, "IBM1026"}, /* IBM EBCDIC Turkish (Latin 5) */
+    {1047, "IBM01047"}, /* IBM EBCDIC Latin 1/Open System */
+    {1140, "IBM01140"}, /* IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro) */
+    {1141, "IBM01141"}, /* IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro) */
+    {1142, "IBM01142"}, /* IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro) */
+    {1143, "IBM01143"}, /* IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro) */
+    {1144, "IBM01144"}, /* IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro) */
+    {1145, "IBM01145"}, /* IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro) */
+    {1146, "IBM01146"}, /* IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro) */
+    {1147, "IBM01147"}, /* IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro) */
+    {1148, "IBM01148"}, /* IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro) */
+    {1149, "IBM01149"}, /* IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro) */
+    {1250, "windows-1250"}, /* ANSI Central European; Central European (Windows) */
+    {1251, "windows-1251"}, /* ANSI Cyrillic; Cyrillic (Windows) */
+    {1252, "windows-1252"}, /* ANSI Latin 1; Western European (Windows) */
+    {1253, "windows-1253"}, /* ANSI Greek; Greek (Windows) */
+    {1254, "windows-1254"}, /* ANSI Turkish; Turkish (Windows) */
+    {1255, "windows-1255"}, /* ANSI Hebrew; Hebrew (Windows) */
+    {1256, "windows-1256"}, /* ANSI Arabic; Arabic (Windows) */
+    {1257, "windows-1257"}, /* ANSI Baltic; Baltic (Windows) */
+    {1258, "windows-1258"}, /* ANSI/OEM Vietnamese; Vietnamese (Windows) */
+    {1361, "Johab"}, /* Korean (Johab) */
+    {10000, "macintosh"}, /* MAC Roman; Western European (Mac) */
+    {10001, "x-mac-japanese"}, /* Japanese (Mac) */
+    {10002, "x-mac-chinesetrad"}, /* MAC Traditional Chinese (Big5); Chinese Traditional (Mac) */
+    {10003, "x-mac-korean"}, /* Korean (Mac) */
+    {10004, "x-mac-arabic"}, /* Arabic (Mac) */
+    {10005, "x-mac-hebrew"}, /* Hebrew (Mac) */
+    {10006, "x-mac-greek"}, /* Greek (Mac) */
+    {10007, "x-mac-cyrillic"}, /* Cyrillic (Mac) */
+    {10008, "x-mac-chinesesimp"}, /* MAC Simplified Chinese (GB 2312); Chinese Simplified (Mac) */
+    {10010, "x-mac-romanian"}, /* Romanian (Mac) */
+    {10017, "x-mac-ukrainian"}, /* Ukrainian (Mac) */
+    {10021, "x-mac-thai"}, /* Thai (Mac) */
+    {10029, "x-mac-ce"}, /* MAC Latin 2; Central European (Mac) */
+    {10079, "x-mac-icelandic"}, /* Icelandic (Mac) */
+    {10081, "x-mac-turkish"}, /* Turkish (Mac) */
+    {10082, "x-mac-croatian"}, /* Croatian (Mac) */
+    {20000, "x-Chinese_CNS"}, /* CNS Taiwan; Chinese Traditional (CNS) */
+    {20001, "x-cp20001"}, /* TCA Taiwan */
+    {20002, "x_Chinese-Eten"}, /* Eten Taiwan; Chinese Traditional (Eten) */
+    {20003, "x-cp20003"}, /* IBM5550 Taiwan */
+    {20004, "x-cp20004"}, /* TeleText Taiwan */
+    {20005, "x-cp20005"}, /* Wang Taiwan */
+    {20105, "x-IA5"}, /* IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5) */
+    {20106, "x-IA5-German"}, /* IA5 German (7-bit) */
+    {20107, "x-IA5-Swedish"}, /* IA5 Swedish (7-bit) */
+    {20108, "x-IA5-Norwegian"}, /* IA5 Norwegian (7-bit) */
+    {20127, "us-ascii"}, /* US-ASCII (7-bit) */
+    {20261, "x-cp20261"}, /* T.61 */
+    {20269, "x-cp20269"}, /* ISO 6937 Non-Spacing Accent */
+    {20273, "IBM273"}, /* IBM EBCDIC Germany */
+    {20277, "IBM277"}, /* IBM EBCDIC Denmark-Norway */
+    {20278, "IBM278"}, /* IBM EBCDIC Finland-Sweden */
+    {20280, "IBM280"}, /* IBM EBCDIC Italy */
+    {20284, "IBM284"}, /* IBM EBCDIC Latin America-Spain */
+    {20285, "IBM285"}, /* IBM EBCDIC United Kingdom */
+    {20290, "IBM290"}, /* IBM EBCDIC Japanese Katakana Extended */
+    {20297, "IBM297"}, /* IBM EBCDIC France */
+    {20420, "IBM420"}, /* IBM EBCDIC Arabic */
+    {20423, "IBM423"}, /* IBM EBCDIC Greek */
+    {20424, "IBM424"}, /* IBM EBCDIC Hebrew */
+    {20833, "x-EBCDIC-KoreanExtended"}, /* IBM EBCDIC Korean Extended */
+    {20838, "IBM-Thai"}, /* IBM EBCDIC Thai */
+    {20866, "koi8-r"}, /* Russian (KOI8-R); Cyrillic (KOI8-R) */
+    {20871, "IBM871"}, /* IBM EBCDIC Icelandic */
+    {20880, "IBM880"}, /* IBM EBCDIC Cyrillic Russian */
+    {20905, "IBM905"}, /* IBM EBCDIC Turkish */
+    {20924, "IBM00924"}, /* IBM EBCDIC Latin 1/Open System (1047 + Euro symbol) */
+    {20932, "EUC-JP"}, /* Japanese (JIS 0208-1990 and 0121-1990) */
+    {20936, "x-cp20936"}, /* Simplified Chinese (GB2312); Chinese Simplified (GB2312-80) */
+    {20949, "x-cp20949"}, /* Korean Wansung */
+    {21025, "cp1025"}, /* IBM EBCDIC Cyrillic Serbian-Bulgarian */
+    /* 21027           (deprecated) */
+    {21866, "koi8-u"}, /* Ukrainian (KOI8-U); Cyrillic (KOI8-U) */
+    {28591, "iso-8859-1"}, /* ISO 8859-1 Latin 1; Western European (ISO) */
+    {28591, "iso8859-1"}, /* ISO 8859-1 Latin 1; Western European (ISO) */
+    {28592, "iso-8859-2"}, /* ISO 8859-2 Central European; Central European (ISO) */
+    {28592, "iso8859-2"}, /* ISO 8859-2 Central European; Central European (ISO) */
+    {28593, "iso-8859-3"}, /* ISO 8859-3 Latin 3 */
+    {28593, "iso8859-3"}, /* ISO 8859-3 Latin 3 */
+    {28594, "iso-8859-4"}, /* ISO 8859-4 Baltic */
+    {28594, "iso8859-4"}, /* ISO 8859-4 Baltic */
+    {28595, "iso-8859-5"}, /* ISO 8859-5 Cyrillic */
+    {28595, "iso8859-5"}, /* ISO 8859-5 Cyrillic */
+    {28596, "iso-8859-6"}, /* ISO 8859-6 Arabic */
+    {28596, "iso8859-6"}, /* ISO 8859-6 Arabic */
+    {28597, "iso-8859-7"}, /* ISO 8859-7 Greek */
+    {28597, "iso8859-7"}, /* ISO 8859-7 Greek */
+    {28598, "iso-8859-8"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */
+    {28598, "iso8859-8"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */
+    {28599, "iso-8859-9"}, /* ISO 8859-9 Turkish */
+    {28599, "iso8859-9"}, /* ISO 8859-9 Turkish */
+    {28603, "iso-8859-13"}, /* ISO 8859-13 Estonian */
+    {28603, "iso8859-13"}, /* ISO 8859-13 Estonian */
+    {28605, "iso-8859-15"}, /* ISO 8859-15 Latin 9 */
+    {28605, "iso8859-15"}, /* ISO 8859-15 Latin 9 */
+    {29001, "x-Europa"}, /* Europa 3 */
+    {38598, "iso-8859-8-i"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */
+    {38598, "iso8859-8-i"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */
+    {50220, "iso-2022-jp"}, /* ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS) */
+    {50221, "csISO2022JP"}, /* ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana) */
+    {50222, "iso-2022-jp"}, /* ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI) */
+    {50225, "iso-2022-kr"}, /* ISO 2022 Korean */
+    {50225, "iso2022-kr"}, /* ISO 2022 Korean */
+    {50227, "x-cp50227"}, /* ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022) */
+    /* 50229           ISO 2022 Traditional Chinese */
+    /* 50930           EBCDIC Japanese (Katakana) Extended */
+    /* 50931           EBCDIC US-Canada and Japanese */
+    /* 50933           EBCDIC Korean Extended and Korean */
+    /* 50935           EBCDIC Simplified Chinese Extended and Simplified Chinese */
+    /* 50936           EBCDIC Simplified Chinese */
+    /* 50937           EBCDIC US-Canada and Traditional Chinese */
+    /* 50939           EBCDIC Japanese (Latin) Extended and Japanese */
+    {51932, "euc-jp"}, /* EUC Japanese */
+    {51936, "EUC-CN"}, /* EUC Simplified Chinese; Chinese Simplified (EUC) */
+    {51949, "euc-kr"}, /* EUC Korean */
+    /* 51950           EUC Traditional Chinese */
+    {52936, "hz-gb-2312"}, /* HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ) */
+    {54936, "GB18030"}, /* Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030) */
+    {57002, "x-iscii-de"}, /* ISCII Devanagari */
+    {57003, "x-iscii-be"}, /* ISCII Bengali */
+    {57004, "x-iscii-ta"}, /* ISCII Tamil */
+    {57005, "x-iscii-te"}, /* ISCII Telugu */
+    {57006, "x-iscii-as"}, /* ISCII Assamese */
+    {57007, "x-iscii-or"}, /* ISCII Oriya */
+    {57008, "x-iscii-ka"}, /* ISCII Kannada */
+    {57009, "x-iscii-ma"}, /* ISCII Malayalam */
+    {57010, "x-iscii-gu"}, /* ISCII Gujarati */
+    {57011, "x-iscii-pa"}, /* ISCII Punjabi */
+
+    {0, NULL}
+};
+
+/*
+ * SJIS SHIFTJIS table              CP932 table
+ * ---- --------------------------- --------------------------------
+ *   5C U+00A5 YEN SIGN             U+005C REVERSE SOLIDUS
+ *   7E U+203E OVERLINE             U+007E TILDE
+ * 815C U+2014 EM DASH              U+2015 HORIZONTAL BAR
+ * 815F U+005C REVERSE SOLIDUS      U+FF3C FULLWIDTH REVERSE SOLIDUS
+ * 8160 U+301C WAVE DASH            U+FF5E FULLWIDTH TILDE
+ * 8161 U+2016 DOUBLE VERTICAL LINE U+2225 PARALLEL TO
+ * 817C U+2212 MINUS SIGN           U+FF0D FULLWIDTH HYPHEN-MINUS
+ * 8191 U+00A2 CENT SIGN            U+FFE0 FULLWIDTH CENT SIGN
+ * 8192 U+00A3 POUND SIGN           U+FFE1 FULLWIDTH POUND SIGN
+ * 81CA U+00AC NOT SIGN             U+FFE2 FULLWIDTH NOT SIGN
+ *
+ * EUC-JP and ISO-2022-JP should be compatible with CP932.
+ *
+ * Kernel and MLang have different Unicode mapping table.  Make sure
+ * which API is used.
+ */
+static compat_t cp932_compat[] = {
+    {0x00A5, 0x005C, COMPAT_OUT},
+    {0x203E, 0x007E, COMPAT_OUT},
+    {0x2014, 0x2015, COMPAT_OUT},
+    {0x301C, 0xFF5E, COMPAT_OUT},
+    {0x2016, 0x2225, COMPAT_OUT},
+    {0x2212, 0xFF0D, COMPAT_OUT},
+    {0x00A2, 0xFFE0, COMPAT_OUT},
+    {0x00A3, 0xFFE1, COMPAT_OUT},
+    {0x00AC, 0xFFE2, COMPAT_OUT},
+    {0, 0, 0}
+};
+
+static compat_t cp20932_compat[] = {
+    {0x00A5, 0x005C, COMPAT_OUT},
+    {0x203E, 0x007E, COMPAT_OUT},
+    {0x2014, 0x2015, COMPAT_OUT},
+    {0xFF5E, 0x301C, COMPAT_OUT|COMPAT_IN},
+    {0x2225, 0x2016, COMPAT_OUT|COMPAT_IN},
+    {0xFF0D, 0x2212, COMPAT_OUT|COMPAT_IN},
+    {0xFFE0, 0x00A2, COMPAT_OUT|COMPAT_IN},
+    {0xFFE1, 0x00A3, COMPAT_OUT|COMPAT_IN},
+    {0xFFE2, 0x00AC, COMPAT_OUT|COMPAT_IN},
+    {0, 0, 0}
+};
+
+static compat_t *cp51932_compat = cp932_compat;
+
+/* cp20932_compat for kernel.  cp932_compat for mlang. */
+static compat_t *cp5022x_compat = cp932_compat;
+
+typedef HRESULT (WINAPI *CONVERTINETSTRING)(
+    LPDWORD lpdwMode,
+    DWORD dwSrcEncoding,
+    DWORD dwDstEncoding,
+    LPCSTR lpSrcStr,
+    LPINT lpnSrcSize,
+    LPBYTE lpDstStr,
+    LPINT lpnDstSize
+);
+typedef HRESULT (WINAPI *CONVERTINETMULTIBYTETOUNICODE)(
+    LPDWORD lpdwMode,
+    DWORD dwSrcEncoding,
+    LPCSTR lpSrcStr,
+    LPINT lpnMultiCharCount,
+    LPWSTR lpDstStr,
+    LPINT lpnWideCharCount
+);
+typedef HRESULT (WINAPI *CONVERTINETUNICODETOMULTIBYTE)(
+    LPDWORD lpdwMode,
+    DWORD dwEncoding,
+    LPCWSTR lpSrcStr,
+    LPINT lpnWideCharCount,
+    LPSTR lpDstStr,
+    LPINT lpnMultiCharCount
+);
+typedef HRESULT (WINAPI *ISCONVERTINETSTRINGAVAILABLE)(
+    DWORD dwSrcEncoding,
+    DWORD dwDstEncoding
+);
+typedef HRESULT (WINAPI *LCIDTORFC1766A)(
+    LCID Locale,
+    LPSTR pszRfc1766,
+    int nChar
+);
+typedef HRESULT (WINAPI *LCIDTORFC1766W)(
+    LCID Locale,
+    LPWSTR pszRfc1766,
+    int nChar
+);
+typedef HRESULT (WINAPI *RFC1766TOLCIDA)(
+    LCID *pLocale,
+    LPSTR pszRfc1766
+);
+typedef HRESULT (WINAPI *RFC1766TOLCIDW)(
+    LCID *pLocale,
+    LPWSTR pszRfc1766
+);
+static CONVERTINETSTRING ConvertINetString;
+static CONVERTINETMULTIBYTETOUNICODE ConvertINetMultiByteToUnicode;
+static CONVERTINETUNICODETOMULTIBYTE ConvertINetUnicodeToMultiByte;
+static ISCONVERTINETSTRINGAVAILABLE IsConvertINetStringAvailable;
+static LCIDTORFC1766A LcidToRfc1766A;
+static RFC1766TOLCIDA Rfc1766ToLcidA;
+
+static int
+load_mlang()
+{
+    HMODULE h;
+    if (ConvertINetString != NULL)
+        return TRUE;
+    h = LoadLibrary("mlang.dll");
+    if (!h)
+        return FALSE;
+    ConvertINetString = (CONVERTINETSTRING)GetProcAddress(h, "ConvertINetString");
+    ConvertINetMultiByteToUnicode = (CONVERTINETMULTIBYTETOUNICODE)GetProcAddress(h, "ConvertINetMultiByteToUnicode");
+    ConvertINetUnicodeToMultiByte = (CONVERTINETUNICODETOMULTIBYTE)GetProcAddress(h, "ConvertINetUnicodeToMultiByte");
+    IsConvertINetStringAvailable = (ISCONVERTINETSTRINGAVAILABLE)GetProcAddress(h, "IsConvertINetStringAvailable");
+    LcidToRfc1766A = (LCIDTORFC1766A)GetProcAddress(h, "LcidToRfc1766A");
+    Rfc1766ToLcidA = (RFC1766TOLCIDA)GetProcAddress(h, "Rfc1766ToLcidA");
+    return TRUE;
+}
+
+iconv_t
+iconv_open(const char *tocode, const char *fromcode)
+{
+    rec_iconv_t *cd;
+
+    cd = (rec_iconv_t *)calloc(1, sizeof(rec_iconv_t));
+    if (cd == NULL)
+        return (iconv_t)(-1);
+
+#if defined(USE_LIBICONV_DLL)
+    errno = 0;
+    if (libiconv_iconv_open(cd, tocode, fromcode))
+        return (iconv_t)cd;
+#endif
+
+    /* reset the errno to prevent reporting wrong error code.
+     * 0 for unsorted error. */
+    errno = 0;
+    if (win_iconv_open(cd, tocode, fromcode))
+        return (iconv_t)cd;
+
+    free(cd);
+
+    return (iconv_t)(-1);
+}
+
+int
+iconv_close(iconv_t _cd)
+{
+    rec_iconv_t *cd = (rec_iconv_t *)_cd;
+    int r = cd->iconv_close(cd->cd);
+    int e = *(cd->_errno());
+#if defined(USE_LIBICONV_DLL)
+    if (cd->hlibiconv != NULL)
+        FreeLibrary(cd->hlibiconv);
+#endif
+    free(cd);
+    errno = e;
+    return r;
+}
+
+size_t
+iconv(iconv_t _cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
+{
+    rec_iconv_t *cd = (rec_iconv_t *)_cd;
+    size_t r = cd->iconv(cd->cd, inbuf, inbytesleft, outbuf, outbytesleft);
+    errno = *(cd->_errno());
+    return r;
+}
+
+static int
+win_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode)
+{
+    if (!make_csconv(fromcode, &cd->from) || !make_csconv(tocode, &cd->to))
+        return FALSE;
+    cd->iconv_close = win_iconv_close;
+    cd->iconv = win_iconv;
+    cd->_errno = _errno;
+    cd->cd = (iconv_t)cd;
+    return TRUE;
+}
+
+static int
+win_iconv_close(iconv_t cd)
+{
+    return 0;
+}
+
+static size_t
+win_iconv(iconv_t _cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
+{
+    rec_iconv_t *cd = (rec_iconv_t *)_cd;
+    ushort wbuf[MB_CHAR_MAX]; /* enough room for one character */
+    int insize;
+    int outsize;
+    int wsize;
+    DWORD frommode;
+    DWORD tomode;
+    uint wc;
+    compat_t *cp;
+    int i;
+
+    if (inbuf == NULL || *inbuf == NULL)
+    {
+        if (outbuf != NULL && *outbuf != NULL && cd->to.flush != NULL)
+        {
+            tomode = cd->to.mode;
+            outsize = cd->to.flush(&cd->to, (uchar *)*outbuf, *outbytesleft);
+            if (outsize == -1)
+            {
+                cd->to.mode = tomode;
+                return (size_t)(-1);
+            }
+            *outbuf += outsize;
+            *outbytesleft -= outsize;
+        }
+        cd->from.mode = 0;
+        cd->to.mode = 0;
+        return 0;
+    }
+
+    while (*inbytesleft != 0)
+    {
+        frommode = cd->from.mode;
+        tomode = cd->to.mode;
+        wsize = MB_CHAR_MAX;
+
+        insize = cd->from.mbtowc(&cd->from, (const uchar *)*inbuf, *inbytesleft, wbuf, &wsize);
+        if (insize == -1)
+        {
+            cd->from.mode = frommode;
+            return (size_t)(-1);
+        }
+
+        if (wsize == 0)
+        {
+            *inbuf += insize;
+            *inbytesleft -= insize;
+            continue;
+        }
+
+        if (cd->from.compat != NULL)
+        {
+            wc = utf16_to_ucs4(wbuf);
+            cp = cd->from.compat;
+            for (i = 0; cp[i].in != 0; ++i)
+            {
+                if ((cp[i].flag & COMPAT_IN) && cp[i].out == wc)
+                {
+                    ucs4_to_utf16(cp[i].in, wbuf, &wsize);
+                    break;
+                }
+            }
+        }
+
+        if (cd->to.compat != NULL)
+        {
+            wc = utf16_to_ucs4(wbuf);
+            cp = cd->to.compat;
+            for (i = 0; cp[i].in != 0; ++i)
+            {
+                if ((cp[i].flag & COMPAT_OUT) && cp[i].in == wc)
+                {
+                    ucs4_to_utf16(cp[i].out, wbuf, &wsize);
+                    break;
+                }
+            }
+        }
+
+        outsize = cd->to.wctomb(&cd->to, wbuf, wsize, (uchar *)*outbuf, *outbytesleft);
+        if (outsize == -1)
+        {
+            cd->from.mode = frommode;
+            cd->to.mode = tomode;
+            return (size_t)(-1);
+        }
+
+        *inbuf += insize;
+        *outbuf += outsize;
+        *inbytesleft -= insize;
+        *outbytesleft -= outsize;
+    }
+
+    return 0;
+}
+
+static int
+make_csconv(const char *_name, csconv_t *cv)
+{
+    CPINFOEX cpinfoex;
+    int use_compat = TRUE;
+    int flag = 0;
+    char *name;
+    char *p;
+
+    name = xstrndup(_name, strlen(_name));
+    if (name == NULL)
+        return FALSE;
+
+    /* check for option "enc_name//opt1//opt2" */
+    while ((p = strrstr(name, "//")) != NULL)
+    {
+        if (_stricmp(p + 2, "nocompat") == 0)
+            use_compat = FALSE;
+        else if (_stricmp(p + 2, "translit") == 0)
+            flag |= FLAG_TRANSLIT;
+        else if (_stricmp(p + 2, "ignore") == 0)
+            flag |= FLAG_IGNORE;
+        *p = 0;
+    }
+
+    cv->mode = 0;
+    cv->flags = flag;
+    cv->mblen = NULL;
+    cv->flush = NULL;
+    cv->compat = NULL;
+    cv->codepage = name_to_codepage(name);
+    if (cv->codepage == 1200 || cv->codepage == 1201)
+    {
+        cv->mbtowc = utf16_mbtowc;
+        cv->wctomb = utf16_wctomb;
+        if (_stricmp(name, "UTF-16") == 0 || _stricmp(name, "UTF16") == 0)
+            cv->flags |= FLAG_USE_BOM;
+    }
+    else if (cv->codepage == 12000 || cv->codepage == 12001)
+    {
+        cv->mbtowc = utf32_mbtowc;
+        cv->wctomb = utf32_wctomb;
+        if (_stricmp(name, "UTF-32") == 0 || _stricmp(name, "UTF32") == 0)
+            cv->flags |= FLAG_USE_BOM;
+    }
+    else if (cv->codepage == 65001)
+    {
+        cv->mbtowc = kernel_mbtowc;
+        cv->wctomb = kernel_wctomb;
+        cv->mblen = utf8_mblen;
+    }
+    else if ((cv->codepage == 50220 || cv->codepage == 50221 || cv->codepage == 50222) && load_mlang())
+    {
+        cv->mbtowc = iso2022jp_mbtowc;
+        cv->wctomb = iso2022jp_wctomb;
+        cv->flush = iso2022jp_flush;
+    }
+    else if (cv->codepage == 51932 && load_mlang())
+    {
+        cv->mbtowc = mlang_mbtowc;
+        cv->wctomb = mlang_wctomb;
+        cv->mblen = eucjp_mblen;
+    }
+    else if (IsValidCodePage(cv->codepage)
+            && GetCPInfoEx(cv->codepage, 0, &cpinfoex) != 0)
+    {
+        cv->mbtowc = kernel_mbtowc;
+        cv->wctomb = kernel_wctomb;
+        if (cpinfoex.MaxCharSize == 1)
+            cv->mblen = sbcs_mblen;
+        else if (cpinfoex.MaxCharSize == 2)
+            cv->mblen = dbcs_mblen;
+       else
+           cv->mblen = mbcs_mblen;
+    }
+    else
+    {
+        /* not supported */
+        free(name);
+        errno = EINVAL;
+        return FALSE;
+    }
+
+    if (use_compat)
+    {
+        switch (cv->codepage)
+        {
+        case 932: cv->compat = cp932_compat; break;
+        case 20932: cv->compat = cp20932_compat; break;
+        case 51932: cv->compat = cp51932_compat; break;
+        case 50220: case 50221: case 50222: cv->compat = cp5022x_compat; break;
+        }
+    }
+
+    free(name);
+
+    return TRUE;
+}
+
+static int
+name_to_codepage(const char *name)
+{
+    int i;
+
+    if (*name == '\0' ||
+       strcmp(name, "char") == 0)
+        return GetACP();
+    else if (strcmp(name, "wchar_t") == 0)
+        return 1200;
+    else if (_strnicmp(name, "cp", 2) == 0)
+        return atoi(name + 2); /* CP123 */
+    else if ('0' <= name[0] && name[0] <= '9')
+        return atoi(name);     /* 123 */
+    else if (_strnicmp(name, "xx", 2) == 0)
+        return atoi(name + 2); /* XX123 for debug */
+
+    for (i = 0; codepage_alias[i].name != NULL; ++i)
+        if (_stricmp(name, codepage_alias[i].name) == 0)
+            return codepage_alias[i].codepage;
+    return -1;
+}
+
+/*
+ * http://www.faqs.org/rfcs/rfc2781.html
+ */
+static uint
+utf16_to_ucs4(const ushort *wbuf)
+{
+    uint wc = wbuf[0];
+    if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)
+        wc = ((wbuf[0] & 0x3FF) << 10) + (wbuf[1] & 0x3FF) + 0x10000;
+    return wc;
+}
+
+static void
+ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize)
+{
+    if (wc < 0x10000)
+    {
+        wbuf[0] = wc;
+        *wbufsize = 1;
+    }
+    else
+    {
+        wc -= 0x10000;
+        wbuf[0] = 0xD800 | ((wc >> 10) & 0x3FF);
+        wbuf[1] = 0xDC00 | (wc & 0x3FF);
+        *wbufsize = 2;
+    }
+}
+
+/*
+ * Check if codepage is one of those for which the dwFlags parameter
+ * to MultiByteToWideChar() must be zero. Return zero or
+ * MB_ERR_INVALID_CHARS.  The docs in Platform SDK for for Windows
+ * Server 2003 R2 claims that also codepage 65001 is one of these, but
+ * that doesn't seem to be the case. The MSDN docs for MSVS2008 leave
+ * out 65001 (UTF-8), and that indeed seems to be the case on XP, it
+ * works fine to pass MB_ERR_INVALID_CHARS in dwFlags when converting
+ * from UTF-8.
+ */
+static int
+mbtowc_flags(int codepage)
+{
+    return (codepage == 50220 || codepage == 50221 ||
+           codepage == 50222 || codepage == 50225 ||
+           codepage == 50227 || codepage == 50229 ||
+           codepage == 52936 || codepage == 54936 ||
+           (codepage >= 57002 && codepage <= 57011) ||
+           codepage == 65000 || codepage == 42) ? 0 : MB_ERR_INVALID_CHARS;
+}
+
+/*
+ * Check if codepage is one those for which the lpUsedDefaultChar
+ * parameter to WideCharToMultiByte() must be NULL.  The docs in
+ * Platform SDK for for Windows Server 2003 R2 claims that this is the
+ * list below, while the MSDN docs for MSVS2008 claim that it is only
+ * for 65000 (UTF-7) and 65001 (UTF-8). This time the earlier Platform
+ * SDK seems to be correct, at least for XP.
+ */
+static int
+must_use_null_useddefaultchar(int codepage)
+{
+    return (codepage == 65000 || codepage == 65001 ||
+            codepage == 50220 || codepage == 50221 ||
+            codepage == 50222 || codepage == 50225 ||
+            codepage == 50227 || codepage == 50229 ||
+            codepage == 52936 || codepage == 54936 ||
+            (codepage >= 57002 && codepage <= 57011) ||
+            codepage == 42);
+}
+
+static char *
+strrstr(const char *str, const char *token)
+{
+    int len = strlen(token);
+    const char *p = str + strlen(str);
+
+    while (str <= --p)
+        if (p[0] == token[0] && strncmp(p, token, len) == 0)
+            return (char *)p;
+    return NULL;
+}
+
+static char *
+xstrndup(const char *s, size_t n)
+{
+    char *p;
+
+    p = (char *)malloc(n + 1);
+    if (p == NULL)
+        return NULL;
+    memcpy(p, s, n);
+    p[n] = '\0';
+    return p;
+}
+
+static int
+seterror(int err)
+{
+    errno = err;
+    return -1;
+}
+
+#if defined(USE_LIBICONV_DLL)
+static int
+libiconv_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode)
+{
+    HMODULE hlibiconv = NULL;
+    HMODULE hmsvcrt = NULL;
+    char *dllname;
+    const char *p;
+    const char *e;
+    f_iconv_open _iconv_open;
+
+    /*
+     * always try to load dll, so that we can switch dll in runtime.
+     */
+
+    /* XXX: getenv() can't get variable set by SetEnvironmentVariable() */
+    p = getenv("WINICONV_LIBICONV_DLL");
+    if (p == NULL)
+        p = DEFAULT_LIBICONV_DLL;
+    /* parse comma separated value */
+    for ( ; *p != 0; p = (*e == ',') ? e + 1 : e)
+    {
+        e = strchr(p, ',');
+        if (p == e)
+            continue;
+        else if (e == NULL)
+            e = p + strlen(p);
+        dllname = xstrndup(p, e - p);
+        if (dllname == NULL)
+            return FALSE;
+        hlibiconv = LoadLibrary(dllname);
+        free(dllname);
+        if (hlibiconv != NULL)
+        {
+            if (hlibiconv == hwiniconv)
+            {
+                FreeLibrary(hlibiconv);
+                hlibiconv = NULL;
+                continue;
+            }
+            break;
+        }
+    }
+
+    if (hlibiconv == NULL)
+        goto failed;
+
+    hmsvcrt = find_imported_module_by_funcname(hlibiconv, "_errno");
+    if (hmsvcrt == NULL)
+        goto failed;
+
+    _iconv_open = (f_iconv_open)GetProcAddress(hlibiconv, "libiconv_open");
+    if (_iconv_open == NULL)
+        _iconv_open = (f_iconv_open)GetProcAddress(hlibiconv, "iconv_open");
+    cd->iconv_close = (f_iconv_close)GetProcAddress(hlibiconv, "libiconv_close");
+    if (cd->iconv_close == NULL)
+        cd->iconv_close = (f_iconv_close)GetProcAddress(hlibiconv, "iconv_close");
+    cd->iconv = (f_iconv)GetProcAddress(hlibiconv, "libiconv");
+    if (cd->iconv == NULL)
+        cd->iconv = (f_iconv)GetProcAddress(hlibiconv, "iconv");
+    cd->_errno = (f_errno)GetProcAddress(hmsvcrt, "_errno");
+    if (_iconv_open == NULL || cd->iconv_close == NULL
+            || cd->iconv == NULL || cd->_errno == NULL)
+        goto failed;
+
+    cd->cd = _iconv_open(tocode, fromcode);
+    if (cd->cd == (iconv_t)(-1))
+        goto failed;
+
+    cd->hlibiconv = hlibiconv;
+    return TRUE;
+
+failed:
+    if (hlibiconv != NULL)
+        FreeLibrary(hlibiconv);
+    /* do not free hmsvcrt which is obtained by GetModuleHandle() */
+    return FALSE;
+}
+
+/*
+ * Reference:
+ * http://forums.belution.com/ja/vc/000/234/78s.shtml
+ * http://nienie.com/~masapico/api_ImageDirectoryEntryToData.html
+ *
+ * The formal way is
+ *   imagehlp.h or dbghelp.h
+ *   imagehlp.lib or dbghelp.lib
+ *   ImageDirectoryEntryToData()
+ */
+#define TO_DOS_HEADER(base) ((PIMAGE_DOS_HEADER)(base))
+#define TO_NT_HEADERS(base) ((PIMAGE_NT_HEADERS)((LPBYTE)(base) + TO_DOS_HEADER(base)->e_lfanew))
+static PVOID
+MyImageDirectoryEntryToData(LPVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size)
+{
+    /* TODO: MappedAsImage? */
+    PIMAGE_DATA_DIRECTORY p;
+    p = TO_NT_HEADERS(Base)->OptionalHeader.DataDirectory + DirectoryEntry;
+    if (p->VirtualAddress == 0) {
+      *Size = 0;
+      return NULL;
+    }
+    *Size = p->Size;
+    return (PVOID)((LPBYTE)Base + p->VirtualAddress);
+}
+
+static HMODULE
+find_imported_module_by_funcname(HMODULE hModule, const char *funcname)
+{
+    DWORD Base;
+    ULONG Size;
+    PIMAGE_IMPORT_DESCRIPTOR Imp;
+    PIMAGE_THUNK_DATA Name;         /* Import Name Table */
+    PIMAGE_IMPORT_BY_NAME ImpName;
+
+    Base = (DWORD)hModule;
+    Imp = MyImageDirectoryEntryToData(
+            (LPVOID)Base,
+            TRUE,
+            IMAGE_DIRECTORY_ENTRY_IMPORT,
+            &Size);
+    if (Imp == NULL)
+        return NULL;
+    for ( ; Imp->OriginalFirstThunk != 0; ++Imp)
+    {
+        Name = (PIMAGE_THUNK_DATA)(Base + Imp->OriginalFirstThunk);
+        for ( ; Name->u1.Ordinal != 0; ++Name)
+        {
+            if (!IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal))
+            {
+                ImpName = (PIMAGE_IMPORT_BY_NAME)
+                    (Base + (DWORD)Name->u1.AddressOfData);
+                if (strcmp((char *)ImpName->Name, funcname) == 0)
+                    return GetModuleHandle((char *)(Base + Imp->Name));
+            }
+        }
+    }
+    return NULL;
+}
+#endif
+
+static int
+sbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)
+{
+    return 1;
+}
+
+static int
+dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)
+{
+    int len = IsDBCSLeadByteEx(cv->codepage, buf[0]) ? 2 : 1;
+    if (bufsize < len)
+        return seterror(EINVAL);
+    return len;
+}
+
+static int
+mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)
+{
+    int len = 0;
+
+    if (cv->codepage == 54936) {
+       if (buf[0] <= 0x7F) len = 1;
+       else if (buf[0] >= 0x81 && buf[0] <= 0xFE &&
+                bufsize >= 2 &&
+                ((buf[1] >= 0x40 && buf[1] <= 0x7E) ||
+                 (buf[1] >= 0x80 && buf[1] <= 0xFE))) len = 2;
+       else if (buf[0] >= 0x81 && buf[0] <= 0xFE &&
+                bufsize >= 4 &&
+                buf[1] >= 0x30 && buf[1] <= 0x39) len = 4;
+       else
+           return seterror(EINVAL);
+       return len;
+    }
+    else
+       return seterror(EINVAL);
+}
+
+static int
+utf8_mblen(csconv_t *cv, const uchar *buf, int bufsize)
+{
+    int len = 0;
+
+    if (buf[0] < 0x80) len = 1;
+    else if ((buf[0] & 0xE0) == 0xC0) len = 2;
+    else if ((buf[0] & 0xF0) == 0xE0) len = 3;
+    else if ((buf[0] & 0xF8) == 0xF0) len = 4;
+    else if ((buf[0] & 0xFC) == 0xF8) len = 5;
+    else if ((buf[0] & 0xFE) == 0xFC) len = 6;
+
+    if (len == 0)
+        return seterror(EILSEQ);
+    else if (bufsize < len)
+        return seterror(EINVAL);
+    return len;
+}
+
+static int
+eucjp_mblen(csconv_t *cv, const uchar *buf, int bufsize)
+{
+    if (buf[0] < 0x80) /* ASCII */
+        return 1;
+    else if (buf[0] == 0x8E) /* JIS X 0201 */
+    {
+        if (bufsize < 2)
+            return seterror(EINVAL);
+        else if (!(0xA1 <= buf[1] && buf[1] <= 0xDF))
+            return seterror(EILSEQ);
+        return 2;
+    }
+    else if (buf[0] == 0x8F) /* JIS X 0212 */
+    {
+        if (bufsize < 3)
+            return seterror(EINVAL);
+        else if (!(0xA1 <= buf[1] && buf[1] <= 0xFE)
+                || !(0xA1 <= buf[2] && buf[2] <= 0xFE))
+            return seterror(EILSEQ);
+        return 3;
+    }
+    else /* JIS X 0208 */
+    {
+        if (bufsize < 2)
+            return seterror(EINVAL);
+        else if (!(0xA1 <= buf[0] && buf[0] <= 0xFE)
+                || !(0xA1 <= buf[1] && buf[1] <= 0xFE))
+            return seterror(EILSEQ);
+        return 2;
+    }
+}
+
+static int
+kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
+{
+    int len;
+
+    len = cv->mblen(cv, buf, bufsize);
+    if (len == -1)
+        return -1;
+    *wbufsize = MultiByteToWideChar(cv->codepage, mbtowc_flags (cv->codepage),
+            (const char *)buf, len, (wchar_t *)wbuf, *wbufsize);
+    if (*wbufsize == 0)
+        return seterror(EILSEQ);
+    return len;
+}
+
+static int
+kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
+{
+    BOOL usedDefaultChar = 0;
+    BOOL *p = NULL;
+    int flags = 0;
+    int len;
+
+    if (bufsize == 0)
+        return seterror(E2BIG);
+    if (!must_use_null_useddefaultchar(cv->codepage))
+    {
+        p = &usedDefaultChar;
+#ifdef WC_NO_BEST_FIT_CHARS
+        if (!(cv->flags & FLAG_TRANSLIT))
+            flags |= WC_NO_BEST_FIT_CHARS;
+#endif
+    }
+    len = WideCharToMultiByte(cv->codepage, flags,
+            (const wchar_t *)wbuf, wbufsize, (char *)buf, bufsize, NULL, p);
+    if (len == 0)
+    {
+        if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+            return seterror(E2BIG);
+        return seterror(EILSEQ);
+    }
+    else if (usedDefaultChar)
+        return seterror(EILSEQ);
+    else if (cv->mblen(cv, buf, len) != len) /* validate result */
+        return seterror(EILSEQ);
+    return len;
+}
+
+/*
+ * It seems that the mode (cv->mode) is fixnum.
+ * For example, when converting iso-2022-jp(cp50221) to unicode:
+ *      in ascii sequence: mode=0xC42C0000
+ *   in jisx0208 sequence: mode=0xC42C0001
+ * "C42C" is same for each convert session.
+ * It should be: ((codepage-1)<<16)|state
+ */
+static int
+mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
+{
+    int len;
+    int insize;
+    HRESULT hr;
+
+    len = cv->mblen(cv, buf, bufsize);
+    if (len == -1)
+        return -1;
+    insize = len;
+    hr = ConvertINetMultiByteToUnicode(&cv->mode, cv->codepage,
+            (const char *)buf, &insize, (wchar_t *)wbuf, wbufsize);
+    if (hr != S_OK || insize != len)
+        return seterror(EILSEQ);
+    return len;
+}
+
+static int
+mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
+{
+    char tmpbuf[MB_CHAR_MAX]; /* enough room for one character */
+    int tmpsize = MB_CHAR_MAX;
+    int insize = wbufsize;
+    HRESULT hr;
+
+    hr = ConvertINetUnicodeToMultiByte(&cv->mode, cv->codepage,
+            (const wchar_t *)wbuf, &wbufsize, tmpbuf, &tmpsize);
+    if (hr != S_OK || insize != wbufsize)
+        return seterror(EILSEQ);
+    else if (bufsize < tmpsize)
+        return seterror(E2BIG);
+    else if (cv->mblen(cv, (uchar *)tmpbuf, tmpsize) != tmpsize)
+        return seterror(EILSEQ);
+    memcpy(buf, tmpbuf, tmpsize);
+    return tmpsize;
+}
+
+static int
+utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
+{
+    int codepage = cv->codepage;
+
+    /* swap endian: 1200 <-> 1201 */
+    if (cv->mode & UNICODE_MODE_SWAPPED)
+        codepage ^= 1;
+
+    if (bufsize < 2)
+        return seterror(EINVAL);
+    if (codepage == 1200) /* little endian */
+        wbuf[0] = (buf[1] << 8) | buf[0];
+    else if (codepage == 1201) /* big endian */
+        wbuf[0] = (buf[0] << 8) | buf[1];
+
+    if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))
+    {
+        cv->mode |= UNICODE_MODE_BOM_DONE;
+        if (wbuf[0] == 0xFFFE)
+        {
+            cv->mode |= UNICODE_MODE_SWAPPED;
+            *wbufsize = 0;
+            return 2;
+        }
+        else if (wbuf[0] == 0xFEFF)
+        {
+            *wbufsize = 0;
+            return 2;
+        }
+    }
+
+    if (0xDC00 <= wbuf[0] && wbuf[0] <= 0xDFFF)
+        return seterror(EILSEQ);
+    if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)
+    {
+        if (bufsize < 4)
+            return seterror(EINVAL);
+        if (codepage == 1200) /* little endian */
+            wbuf[1] = (buf[3] << 8) | buf[2];
+        else if (codepage == 1201) /* big endian */
+            wbuf[1] = (buf[2] << 8) | buf[3];
+        if (!(0xDC00 <= wbuf[1] && wbuf[1] <= 0xDFFF))
+            return seterror(EILSEQ);
+        *wbufsize = 2;
+        return 4;
+    }
+    *wbufsize = 1;
+    return 2;
+}
+
+static int
+utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
+{
+    if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))
+    {
+        int r;
+
+        cv->mode |= UNICODE_MODE_BOM_DONE;
+        if (bufsize < 2)
+            return seterror(E2BIG);
+        if (cv->codepage == 1200) /* little endian */
+            memcpy(buf, "\xFF\xFE", 2);
+        else if (cv->codepage == 1201) /* big endian */
+            memcpy(buf, "\xFE\xFF", 2);
+
+        r = utf16_wctomb(cv, wbuf, wbufsize, buf + 2, bufsize - 2);
+        if (r == -1)
+            return -1;
+        return r + 2;
+    }
+
+    if (bufsize < 2)
+        return seterror(E2BIG);
+    if (cv->codepage == 1200) /* little endian */
+    {
+        buf[0] = (wbuf[0] & 0x00FF);
+        buf[1] = (wbuf[0] & 0xFF00) >> 8;
+    }
+    else if (cv->codepage == 1201) /* big endian */
+    {
+        buf[0] = (wbuf[0] & 0xFF00) >> 8;
+        buf[1] = (wbuf[0] & 0x00FF);
+    }
+    if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)
+    {
+        if (bufsize < 4)
+            return seterror(E2BIG);
+        if (cv->codepage == 1200) /* little endian */
+        {
+            buf[2] = (wbuf[1] & 0x00FF);
+            buf[3] = (wbuf[1] & 0xFF00) >> 8;
+        }
+        else if (cv->codepage == 1201) /* big endian */
+        {
+            buf[2] = (wbuf[1] & 0xFF00) >> 8;
+            buf[3] = (wbuf[1] & 0x00FF);
+        }
+        return 4;
+    }
+    return 2;
+}
+
+static int
+utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
+{
+    int codepage = cv->codepage;
+    uint wc = 0;
+
+    /* swap endian: 12000 <-> 12001 */
+    if (cv->mode & UNICODE_MODE_SWAPPED)
+        codepage ^= 1;
+
+    if (bufsize < 4)
+        return seterror(EINVAL);
+    if (codepage == 12000) /* little endian */
+        wc = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+    else if (codepage == 12001) /* big endian */
+        wc = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+
+    if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))
+    {
+        cv->mode |= UNICODE_MODE_BOM_DONE;
+        if (wc == 0xFFFE0000)
+        {
+            cv->mode |= UNICODE_MODE_SWAPPED;
+            *wbufsize = 0;
+            return 4;
+        }
+        else if (wc == 0x0000FEFF)
+        {
+            *wbufsize = 0;
+            return 4;
+        }
+    }
+
+    if ((0xD800 <= wc && wc <= 0xDFFF) || 0x10FFFF < wc)
+        return seterror(EILSEQ);
+    ucs4_to_utf16(wc, wbuf, wbufsize);
+    return 4;
+}
+
+static int
+utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
+{
+    uint wc;
+
+    if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))
+    {
+        int r;
+
+        cv->mode |= UNICODE_MODE_BOM_DONE;
+        if (bufsize < 4)
+            return seterror(E2BIG);
+        if (cv->codepage == 12000) /* little endian */
+            memcpy(buf, "\xFF\xFE\x00\x00", 4);
+        else if (cv->codepage == 12001) /* big endian */
+            memcpy(buf, "\x00\x00\xFE\xFF", 4);
+
+        r = utf32_wctomb(cv, wbuf, wbufsize, buf + 4, bufsize - 4);
+        if (r == -1)
+            return -1;
+        return r + 4;
+    }
+
+    if (bufsize < 4)
+        return seterror(E2BIG);
+    wc = utf16_to_ucs4(wbuf);
+    if (cv->codepage == 12000) /* little endian */
+    {
+        buf[0] = wc & 0x000000FF;
+        buf[1] = (wc & 0x0000FF00) >> 8;
+        buf[2] = (wc & 0x00FF0000) >> 16;
+        buf[3] = (wc & 0xFF000000) >> 24;
+    }
+    else if (cv->codepage == 12001) /* big endian */
+    {
+        buf[0] = (wc & 0xFF000000) >> 24;
+        buf[1] = (wc & 0x00FF0000) >> 16;
+        buf[2] = (wc & 0x0000FF00) >> 8;
+        buf[3] = wc & 0x000000FF;
+    }
+    return 4;
+}
+
+/*
+ * 50220: ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS)
+ * 50221: ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow
+ *        1 byte Kana)
+ * 50222: ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte
+ *        Kana - SO/SI)
+ *
+ * MultiByteToWideChar() and WideCharToMultiByte() behave differently
+ * depending on Windows version.  On XP, WideCharToMultiByte() doesn't
+ * terminate result sequence with ascii escape.  But Vista does.
+ * Use MLang instead.
+ */
+
+#define ISO2022_MODE(cs, shift) (((cs) << 8) | (shift))
+#define ISO2022_MODE_CS(mode) (((mode) >> 8) & 0xFF)
+#define ISO2022_MODE_SHIFT(mode) ((mode) & 0xFF)
+
+#define ISO2022_SI  0
+#define ISO2022_SO  1
+
+/* shift in */
+static const char iso2022_SI_seq[] = "\x0F";
+/* shift out */
+static const char iso2022_SO_seq[] = "\x0E";
+
+typedef struct iso2022_esc_t iso2022_esc_t;
+struct iso2022_esc_t {
+    const char *esc;
+    int esc_len;
+    int len;
+    int cs;
+};
+
+#define ISO2022JP_CS_ASCII            0
+#define ISO2022JP_CS_JISX0201_ROMAN   1
+#define ISO2022JP_CS_JISX0201_KANA    2
+#define ISO2022JP_CS_JISX0208_1978    3
+#define ISO2022JP_CS_JISX0208_1983    4
+#define ISO2022JP_CS_JISX0212         5
+
+static iso2022_esc_t iso2022jp_esc[] = {
+    {"\x1B\x28\x42", 3, 1, ISO2022JP_CS_ASCII},
+    {"\x1B\x28\x4A", 3, 1, ISO2022JP_CS_JISX0201_ROMAN},
+    {"\x1B\x28\x49", 3, 1, ISO2022JP_CS_JISX0201_KANA},
+    {"\x1B\x24\x40", 3, 2, ISO2022JP_CS_JISX0208_1983}, /* unify 1978 with 1983 */
+    {"\x1B\x24\x42", 3, 2, ISO2022JP_CS_JISX0208_1983},
+    {"\x1B\x24\x28\x44", 4, 2, ISO2022JP_CS_JISX0212},
+    {NULL, 0, 0, 0}
+};
+
+static int
+iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
+{
+    iso2022_esc_t *iesc = iso2022jp_esc;
+    char tmp[MB_CHAR_MAX];
+    int insize;
+    HRESULT hr;
+    DWORD dummy = 0;
+    int len;
+    int esc_len;
+    int cs;
+    int shift;
+    int i;
+
+    if (buf[0] == 0x1B)
+    {
+        for (i = 0; iesc[i].esc != NULL; ++i)
+        {
+            esc_len = iesc[i].esc_len;
+            if (bufsize < esc_len)
+            {
+                if (strncmp((char *)buf, iesc[i].esc, bufsize) == 0)
+                    return seterror(EINVAL);
+            }
+            else
+            {
+                if (strncmp((char *)buf, iesc[i].esc, esc_len) == 0)
+                {
+                    cv->mode = ISO2022_MODE(iesc[i].cs, ISO2022_SI);
+                    *wbufsize = 0;
+                    return esc_len;
+                }
+            }
+        }
+        /* not supported escape sequence */
+        return seterror(EILSEQ);
+    }
+    else if (buf[0] == iso2022_SO_seq[0])
+    {
+        cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SO);
+        *wbufsize = 0;
+        return 1;
+    }
+    else if (buf[0] == iso2022_SI_seq[0])
+    {
+        cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SI);
+        *wbufsize = 0;
+        return 1;
+    }
+
+    cs = ISO2022_MODE_CS(cv->mode);
+    shift = ISO2022_MODE_SHIFT(cv->mode);
+
+    /* reset the mode for informal sequence */
+    if (buf[0] < 0x20)
+    {
+        cs = ISO2022JP_CS_ASCII;
+        shift = ISO2022_SI;
+    }
+
+    len = iesc[cs].len;
+    if (bufsize < len)
+        return seterror(EINVAL);
+    for (i = 0; i < len; ++i)
+        if (!(buf[i] < 0x80))
+            return seterror(EILSEQ);
+    esc_len = iesc[cs].esc_len;
+    memcpy(tmp, iesc[cs].esc, esc_len);
+    if (shift == ISO2022_SO)
+    {
+        memcpy(tmp + esc_len, iso2022_SO_seq, 1);
+        esc_len += 1;
+    }
+    memcpy(tmp + esc_len, buf, len);
+
+    if ((cv->codepage == 50220 || cv->codepage == 50221
+                || cv->codepage == 50222) && shift == ISO2022_SO)
+    {
+        /* XXX: shift-out cannot be used for mbtowc (both kernel and
+         * mlang) */
+        esc_len = iesc[ISO2022JP_CS_JISX0201_KANA].esc_len;
+        memcpy(tmp, iesc[ISO2022JP_CS_JISX0201_KANA].esc, esc_len);
+        memcpy(tmp + esc_len, buf, len);
+    }
+
+    insize = len + esc_len;
+    hr = ConvertINetMultiByteToUnicode(&dummy, cv->codepage,
+            (const char *)tmp, &insize, (wchar_t *)wbuf, wbufsize);
+    if (hr != S_OK || insize != len + esc_len)
+        return seterror(EILSEQ);
+
+    /* Check for conversion error.  Assuming defaultChar is 0x3F. */
+    /* ascii should be converted from ascii */
+    if (wbuf[0] == buf[0]
+            && cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI))
+        return seterror(EILSEQ);
+
+    /* reset the mode for informal sequence */
+    if (cv->mode != ISO2022_MODE(cs, shift))
+        cv->mode = ISO2022_MODE(cs, shift);
+
+    return len;
+}
+
+static int
+iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
+{
+    iso2022_esc_t *iesc = iso2022jp_esc;
+    char tmp[MB_CHAR_MAX];
+    int tmpsize = MB_CHAR_MAX;
+    int insize = wbufsize;
+    HRESULT hr;
+    DWORD dummy = 0;
+    int len;
+    int esc_len = 0;
+    int cs = 0;
+    int shift;
+    int i;
+
+    /*
+     * MultiByte = [escape sequence] + character + [escape sequence]
+     *
+     * Whether trailing escape sequence is added depends on which API is
+     * used (kernel or MLang, and its version).
+     */
+    hr = ConvertINetUnicodeToMultiByte(&dummy, cv->codepage,
+            (const wchar_t *)wbuf, &wbufsize, tmp, &tmpsize);
+    if (hr != S_OK || insize != wbufsize)
+        return seterror(EILSEQ);
+    else if (bufsize < tmpsize)
+        return seterror(E2BIG);
+
+    if (tmpsize == 1)
+    {
+        cs = ISO2022JP_CS_ASCII;
+        esc_len = 0;
+    }
+    else
+    {
+        for (i = 1; iesc[i].esc != NULL; ++i)
+        {
+            esc_len = iesc[i].esc_len;
+            if (strncmp(tmp, iesc[i].esc, esc_len) == 0)
+            {
+                cs = iesc[i].cs;
+                break;
+            }
+        }
+        if (iesc[i].esc == NULL)
+            /* not supported escape sequence */
+            return seterror(EILSEQ);
+    }
+
+    shift = ISO2022_SI;
+    if (tmp[esc_len] == iso2022_SO_seq[0])
+    {
+        shift = ISO2022_SO;
+        esc_len += 1;
+    }
+
+    len = iesc[cs].len;
+
+    /* Check for converting error.  Assuming defaultChar is 0x3F. */
+    /* ascii should be converted from ascii */
+    if (cs == ISO2022JP_CS_ASCII && !(wbuf[0] < 0x80))
+        return seterror(EILSEQ);
+    else if (tmpsize < esc_len + len)
+        return seterror(EILSEQ);
+
+    if (cv->mode == ISO2022_MODE(cs, shift))
+    {
+        /* remove escape sequence */
+        if (esc_len != 0)
+            memmove(tmp, tmp + esc_len, len);
+        esc_len = 0;
+    }
+    else
+    {
+        if (cs == ISO2022JP_CS_ASCII)
+        {
+            esc_len = iesc[ISO2022JP_CS_ASCII].esc_len;
+            memmove(tmp + esc_len, tmp, len);
+            memcpy(tmp, iesc[ISO2022JP_CS_ASCII].esc, esc_len);
+        }
+        if (ISO2022_MODE_SHIFT(cv->mode) == ISO2022_SO)
+        {
+            /* shift-in before changing to other mode */
+            memmove(tmp + 1, tmp, len + esc_len);
+            memcpy(tmp, iso2022_SI_seq, 1);
+            esc_len += 1;
+        }
+    }
+
+    if (bufsize < len + esc_len)
+        return seterror(E2BIG);
+    memcpy(buf, tmp, len + esc_len);
+    cv->mode = ISO2022_MODE(cs, shift);
+    return len + esc_len;
+}
+
+static int
+iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize)
+{
+    iso2022_esc_t *iesc = iso2022jp_esc;
+    int esc_len;
+
+    if (cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI))
+    {
+        esc_len = 0;
+        if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI)
+            esc_len += 1;
+        if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII)
+            esc_len += iesc[ISO2022JP_CS_ASCII].esc_len;
+        if (bufsize < esc_len)
+            return seterror(E2BIG);
+
+        esc_len = 0;
+        if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI)
+        {
+            memcpy(buf, iso2022_SI_seq, 1);
+            esc_len += 1;
+        }
+        if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII)
+        {
+            memcpy(buf + esc_len, iesc[ISO2022JP_CS_ASCII].esc,
+                    iesc[ISO2022JP_CS_ASCII].esc_len);
+            esc_len += iesc[ISO2022JP_CS_ASCII].esc_len;
+        }
+        return esc_len;
+    }
+    return 0;
+}
+
+#if defined(MAKE_DLL) && defined(USE_LIBICONV_DLL)
+BOOL WINAPI
+DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
+{
+    switch( fdwReason )
+    {
+    case DLL_PROCESS_ATTACH:
+        hwiniconv = (HMODULE)hinstDLL;
+        break;
+    case DLL_THREAD_ATTACH:
+    case DLL_THREAD_DETACH:
+    case DLL_PROCESS_DETACH:
+        break;
+    }
+    return TRUE;
+}
+#endif
+
+#if defined(MAKE_EXE)
+#include <stdio.h>
+#include <fcntl.h>
+#include <io.h>
+int
+main(int argc, char **argv)
+{
+    char *fromcode = NULL;
+    char *tocode = NULL;
+    int i;
+    char inbuf[BUFSIZ];
+    char outbuf[BUFSIZ];
+    const char *pin;
+    char *pout;
+    size_t inbytesleft;
+    size_t outbytesleft;
+    size_t rest = 0;
+    iconv_t cd;
+    size_t r;
+    FILE *in = stdin;
+
+    _setmode(_fileno(stdin), _O_BINARY);
+    _setmode(_fileno(stdout), _O_BINARY);
+
+    for (i = 1; i < argc; ++i)
+    {
+        if (strcmp(argv[i], "-l") == 0)
+        {
+            for (i = 0; codepage_alias[i].name != NULL; ++i)
+                printf("%s\n", codepage_alias[i].name);
+            return 0;
+        }
+
+        if (strcmp(argv[i], "-f") == 0)
+            fromcode = argv[++i];
+        else if (strcmp(argv[i], "-t") == 0)
+            tocode = argv[++i];
+        else
+        {
+            in = fopen(argv[i], "rb");
+            if (in == NULL)
+            {
+                fprintf(stderr, "cannot open %s\n", argv[i]);
+                return 1;
+            }
+            break;
+        }
+    }
+
+    if (fromcode == NULL || tocode == NULL)
+    {
+        printf("usage: %s -f from-enc -t to-enc [file]\n", argv[0]);
+        return 0;
+    }
+
+    cd = iconv_open(tocode, fromcode);
+    if (cd == (iconv_t)(-1))
+    {
+        perror("iconv_open error");
+        return 1;
+    }
+
+    while ((inbytesleft = fread(inbuf + rest, 1, sizeof(inbuf) - rest, in)) != 0
+            || rest != 0)
+    {
+        inbytesleft += rest;
+        pin = inbuf;
+        pout = outbuf;
+        outbytesleft = sizeof(outbuf);
+        r = iconv(cd, &pin, &inbytesleft, &pout, &outbytesleft);
+        fwrite(outbuf, 1, sizeof(outbuf) - outbytesleft, stdout);
+        if (r == (size_t)(-1) && errno != E2BIG && (errno != EINVAL || feof(in)))
+        {
+            perror("conversion error");
+            return 1;
+        }
+        memmove(inbuf, pin, inbytesleft);
+        rest = inbytesleft;
+    }
+    pout = outbuf;
+    outbytesleft = sizeof(outbuf);
+    r = iconv(cd, NULL, NULL, &pout, &outbytesleft);
+    fwrite(outbuf, 1, sizeof(outbuf) - outbytesleft, stdout);
+    if (r == (size_t)(-1))
+    {
+        perror("conversion error");
+        return 1;
+    }
+
+    iconv_close(cd);
+
+    return 0;
+}
+#endif
+
index 7c941fe43563edf28aac60a1ab9324ba900afbb2..455be3b6b77e6fdeca90afcfbf74d0c632040e31 100644 (file)
@@ -1,5 +1,5 @@
-#include <stddef.h>\r
-typedef void* iconv_t;\r
-iconv_t iconv_open(const char *tocode, const char *fromcode);\r
-int iconv_close(iconv_t cd);\r
-size_t iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);\r
+#include <stddef.h>
+typedef void* iconv_t;
+iconv_t iconv_open(const char *tocode, const char *fromcode);
+int iconv_close(iconv_t cd);
+size_t iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
index 525f484e9873f464b82bf19672f7af976404992a..5cbf779c92715e0e6a751fa63ea96404d1f57088 100644 (file)
@@ -1,54 +1,54 @@
-HRESULT WINAPI ConvertINetString(\r
-    LPDWORD lpdwMode,\r
-    DWORD dwSrcEncoding,\r
-    DWORD dwDstEncoding,\r
-    LPCSTR lpSrcStr,\r
-    LPINT lpnSrcSize,\r
-    LPBYTE lpDstStr,\r
-    LPINT lpnDstSize\r
-);\r
-\r
-HRESULT WINAPI ConvertINetMultiByteToUnicode(\r
-    LPDWORD lpdwMode,\r
-    DWORD dwSrcEncoding,\r
-    LPCSTR lpSrcStr,\r
-    LPINT lpnMultiCharCount,\r
-    LPWSTR lpDstStr,\r
-    LPINT lpnWideCharCount\r
-);\r
-\r
-HRESULT WINAPI ConvertINetUnicodeToMultiByte(\r
-    LPDWORD lpdwMode,\r
-    DWORD dwEncoding,\r
-    LPCWSTR lpSrcStr,\r
-    LPINT lpnWideCharCount,\r
-    LPSTR lpDstStr,\r
-    LPINT lpnMultiCharCount\r
-);\r
-\r
-HRESULT WINAPI IsConvertINetStringAvailable(\r
-    DWORD dwSrcEncoding,\r
-    DWORD dwDstEncoding\r
-);\r
-\r
-HRESULT WINAPI LcidToRfc1766A(\r
-    LCID Locale,\r
-    LPSTR pszRfc1766,\r
-    int nChar\r
-);\r
-\r
-HRESULT WINAPI LcidToRfc1766W(\r
-    LCID Locale,\r
-    LPWSTR pszRfc1766,\r
-    int nChar\r
-);\r
-\r
-HRESULT WINAPI Rfc1766ToLcidA(\r
-    LCID *pLocale,\r
-    LPSTR pszRfc1766\r
-);\r
-\r
-HRESULT WINAPI Rfc1766ToLcidW(\r
-    LCID *pLocale,\r
-    LPWSTR pszRfc1766\r
-);\r
+HRESULT WINAPI ConvertINetString(
+    LPDWORD lpdwMode,
+    DWORD dwSrcEncoding,
+    DWORD dwDstEncoding,
+    LPCSTR lpSrcStr,
+    LPINT lpnSrcSize,
+    LPBYTE lpDstStr,
+    LPINT lpnDstSize
+);
+
+HRESULT WINAPI ConvertINetMultiByteToUnicode(
+    LPDWORD lpdwMode,
+    DWORD dwSrcEncoding,
+    LPCSTR lpSrcStr,
+    LPINT lpnMultiCharCount,
+    LPWSTR lpDstStr,
+    LPINT lpnWideCharCount
+);
+
+HRESULT WINAPI ConvertINetUnicodeToMultiByte(
+    LPDWORD lpdwMode,
+    DWORD dwEncoding,
+    LPCWSTR lpSrcStr,
+    LPINT lpnWideCharCount,
+    LPSTR lpDstStr,
+    LPINT lpnMultiCharCount
+);
+
+HRESULT WINAPI IsConvertINetStringAvailable(
+    DWORD dwSrcEncoding,
+    DWORD dwDstEncoding
+);
+
+HRESULT WINAPI LcidToRfc1766A(
+    LCID Locale,
+    LPSTR pszRfc1766,
+    int nChar
+);
+
+HRESULT WINAPI LcidToRfc1766W(
+    LCID Locale,
+    LPWSTR pszRfc1766,
+    int nChar
+);
+
+HRESULT WINAPI Rfc1766ToLcidA(
+    LCID *pLocale,
+    LPSTR pszRfc1766
+);
+
+HRESULT WINAPI Rfc1766ToLcidW(
+    LCID *pLocale,
+    LPWSTR pszRfc1766
+);
index c4fb7d692b0f80cf588ea65b33fba0bc249ee965..31f423dc75e9bb5ea07a5cb39c891ebba67de8bf 100644 (file)
@@ -1,3 +1,3 @@
-win_iconv is a iconv library using Win32 API to conversion.\r
-win_iconv is placed in the public domain.\r
-Yukihiro Nakadaira <yukihiro.nakadaira@gmail.com>\r
+win_iconv is a iconv library using Win32 API to conversion.
+win_iconv is placed in the public domain.
+Yukihiro Nakadaira <yukihiro.nakadaira@gmail.com>
index 94c8d4a1e76ddea78aa33703bb238ad925f457da..7a3eda3e106d43edeb37f1be305fa66bf5da7a8d 100644 (file)
-/*\r
- * iconv library using Win32 API to conversion.\r
- *\r
- * This file is placed in the public domain.\r
- *\r
- * Last Change: 2009-07-06\r
- *\r
- * ENVIRONMENT VARIABLE:\r
- *     WINICONV_LIBICONV_DLL\r
- *         If $WINICONV_LIBICONV_DLL is set, win_iconv uses the DLL.  If\r
- *         loading the DLL or iconv_open() failed, falls back to internal\r
- *         conversion.  If a few DLL are specified as comma separated list,\r
- *         the first loadable DLL is used.  The DLL should have iconv_open(),\r
- *         iconv_close() and iconv().  Or libiconv_open(), libiconv_close()\r
- *         and libiconv().\r
- *         (only available when USE_LIBICONV_DLL is defined at compile time)\r
- *\r
- * Win32 API does not support strict encoding conversion for some\r
- * codepage.  And MLang function drop or replace invalid bytes and does\r
- * not return useful error status as iconv.  This implementation cannot\r
- * be used for encoding validation purpose.\r
- */\r
-\r
-/* for WC_NO_BEST_FIT_CHARS */\r
-#ifndef WINVER\r
-# define WINVER 0x0500\r
-#endif\r
-\r
-#include <windows.h>\r
-#include <errno.h>\r
-#include <string.h>\r
-#include <stdlib.h>\r
-\r
-#if 0\r
-# define MAKE_EXE\r
-# define MAKE_DLL\r
-# define USE_LIBICONV_DLL\r
-#endif\r
-\r
-#if !defined(DEFAULT_LIBICONV_DLL)\r
-# define DEFAULT_LIBICONV_DLL ""\r
-#endif\r
-\r
-#define MB_CHAR_MAX 16\r
-\r
-#define UNICODE_MODE_BOM_DONE   1\r
-#define UNICODE_MODE_SWAPPED    2\r
-\r
-#define FLAG_USE_BOM            1\r
-#define FLAG_TRANSLIT           2 /* //TRANSLIT */\r
-#define FLAG_IGNORE             4 /* //IGNORE (not implemented) */\r
-\r
-typedef unsigned char uchar;\r
-typedef unsigned short ushort;\r
-typedef unsigned int uint;\r
-\r
-typedef void* iconv_t;\r
-\r
-iconv_t iconv_open(const char *tocode, const char *fromcode);\r
-int iconv_close(iconv_t cd);\r
-size_t iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);\r
-\r
-/* libiconv interface for vim */\r
-#if defined(MAKE_DLL)\r
-int\r
-iconvctl (iconv_t cd, int request, void* argument)\r
-{\r
-    /* not supported */\r
-    return 0;\r
-}\r
-#endif\r
-\r
-typedef struct compat_t compat_t;\r
-typedef struct csconv_t csconv_t;\r
-typedef struct rec_iconv_t rec_iconv_t;\r
-\r
-typedef iconv_t (*f_iconv_open)(const char *tocode, const char *fromcode);\r
-typedef int (*f_iconv_close)(iconv_t cd);\r
-typedef size_t (*f_iconv)(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);\r
-typedef int* (*f_errno)(void);\r
-typedef int (*f_mbtowc)(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);\r
-typedef int (*f_wctomb)(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);\r
-typedef int (*f_mblen)(csconv_t *cv, const uchar *buf, int bufsize);\r
-typedef int (*f_flush)(csconv_t *cv, uchar *buf, int bufsize);\r
-\r
-#define COMPAT_IN   1\r
-#define COMPAT_OUT  2\r
-\r
-/* unicode mapping for compatibility with other conversion table. */\r
-struct compat_t {\r
-    uint in;\r
-    uint out;\r
-    uint flag;\r
-};\r
-\r
-struct csconv_t {\r
-    int codepage;\r
-    int flags;\r
-    f_mbtowc mbtowc;\r
-    f_wctomb wctomb;\r
-    f_mblen mblen;\r
-    f_flush flush;\r
-    DWORD mode;\r
-    compat_t *compat;\r
-};\r
-\r
-struct rec_iconv_t {\r
-    iconv_t cd;\r
-    f_iconv_close iconv_close;\r
-    f_iconv iconv;\r
-    f_errno _errno;\r
-    csconv_t from;\r
-    csconv_t to;\r
-#if defined(USE_LIBICONV_DLL)\r
-    HMODULE hlibiconv;\r
-#endif\r
-};\r
-\r
-static int win_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode);\r
-static int win_iconv_close(iconv_t cd);\r
-static size_t win_iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);\r
-\r
-static int load_mlang();\r
-static int make_csconv(const char *name, csconv_t *cv);\r
-static int name_to_codepage(const char *name);\r
-static uint utf16_to_ucs4(const ushort *wbuf);\r
-static void ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize);\r
-static int mbtowc_flags(int codepage);\r
-static int must_use_null_useddefaultchar(int codepage);\r
-static char *strrstr(const char *str, const char *token);\r
-static char *xstrndup(const char *s, size_t n);\r
-static int seterror(int err);\r
-\r
-#if defined(USE_LIBICONV_DLL)\r
-static int libiconv_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode);\r
-static PVOID MyImageDirectoryEntryToData(LPVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size);\r
-static HMODULE find_imported_module_by_funcname(HMODULE hModule, const char *funcname);\r
-\r
-static HMODULE hwiniconv;\r
-#endif\r
-\r
-static int sbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);\r
-static int dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);\r
-static int mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);\r
-static int utf8_mblen(csconv_t *cv, const uchar *buf, int bufsize);\r
-static int eucjp_mblen(csconv_t *cv, const uchar *buf, int bufsize);\r
-\r
-static int kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);\r
-static int kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);\r
-static int mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);\r
-static int mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);\r
-static int utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);\r
-static int utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);\r
-static int utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);\r
-static int utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);\r
-static int iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);\r
-static int iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);\r
-static int iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize);\r
-\r
-static struct {\r
-    int codepage;\r
-    const char *name;\r
-} codepage_alias[] = {\r
-    {65001, "CP65001"},\r
-    {65001, "UTF8"},\r
-    {65001, "UTF-8"},\r
-\r
-    {1200, "CP1200"},\r
-    {1200, "UTF16LE"},\r
-    {1200, "UTF-16LE"},\r
-    {1200, "UCS-2LE"},\r
-\r
-    {1201, "CP1201"},\r
-    {1201, "UTF16BE"},\r
-    {1201, "UTF-16BE"},\r
-    {1201, "UCS-2BE"},\r
-    {1201, "unicodeFFFE"},\r
-\r
-    {12000, "CP12000"},\r
-    {12000, "UTF32LE"},\r
-    {12000, "UTF-32LE"},\r
-\r
-    {12001, "CP12001"},\r
-    {12001, "UTF32BE"},\r
-    {12001, "UTF-32BE"},\r
-\r
-#ifndef GLIB_COMPILATION\r
-    /*\r
-     * Default is big endian.\r
-     * See rfc2781 4.3 Interpreting text labelled as UTF-16.\r
-     */\r
-    {1201, "UTF16"},\r
-    {1201, "UTF-16"},\r
-    {12001, "UTF32"},\r
-    {12001, "UTF-32"},\r
-#else\r
-    /* Default is little endian, because the platform is */\r
-    {1200, "UTF16"},\r
-    {1200, "UTF-16"},\r
-    {1200, "UCS-2"},\r
-    {12000, "UTF32"},\r
-    {12000, "UTF-32"},\r
-#endif\r
-\r
-    /* copy from libiconv `iconv -l` */\r
-    /* !IsValidCodePage(367) */\r
-    {20127, "ANSI_X3.4-1968"},\r
-    {20127, "ANSI_X3.4-1986"},\r
-    {20127, "ASCII"},\r
-    {20127, "CP367"},\r
-    {20127, "IBM367"},\r
-    {20127, "ISO-IR-6"},\r
-    {20127, "ISO646-US"},\r
-    {20127, "ISO_646.IRV:1991"},\r
-    {20127, "US"},\r
-    {20127, "US-ASCII"},\r
-    {20127, "CSASCII"},\r
-\r
-    /* !IsValidCodePage(819) */\r
-    {1252, "CP819"},\r
-    {1252, "IBM819"},\r
-    {28591, "ISO-8859-1"},\r
-    {28591, "ISO-IR-100"},\r
-    {28591, "ISO8859-1"},\r
-    {28591, "ISO_8859-1"},\r
-    {28591, "ISO_8859-1:1987"},\r
-    {28591, "L1"},\r
-    {28591, "LATIN1"},\r
-    {28591, "CSISOLATIN1"},\r
-\r
-    {1250, "CP1250"},\r
-    {1250, "MS-EE"},\r
-    {1250, "WINDOWS-1250"},\r
-\r
-    {1251, "CP1251"},\r
-    {1251, "MS-CYRL"},\r
-    {1251, "WINDOWS-1251"},\r
-\r
-    {1252, "CP1252"},\r
-    {1252, "MS-ANSI"},\r
-    {1252, "WINDOWS-1252"},\r
-\r
-    {1253, "CP1253"},\r
-    {1253, "MS-GREEK"},\r
-    {1253, "WINDOWS-1253"},\r
-\r
-    {1254, "CP1254"},\r
-    {1254, "MS-TURK"},\r
-    {1254, "WINDOWS-1254"},\r
-\r
-    {1255, "CP1255"},\r
-    {1255, "MS-HEBR"},\r
-    {1255, "WINDOWS-1255"},\r
-\r
-    {1256, "CP1256"},\r
-    {1256, "MS-ARAB"},\r
-    {1256, "WINDOWS-1256"},\r
-\r
-    {1257, "CP1257"},\r
-    {1257, "WINBALTRIM"},\r
-    {1257, "WINDOWS-1257"},\r
-\r
-    {1258, "CP1258"},\r
-    {1258, "WINDOWS-1258"},\r
-\r
-    {850, "850"},\r
-    {850, "CP850"},\r
-    {850, "IBM850"},\r
-    {850, "CSPC850MULTILINGUAL"},\r
-\r
-    /* !IsValidCodePage(862) */\r
-    {862, "862"},\r
-    {862, "CP862"},\r
-    {862, "IBM862"},\r
-    {862, "CSPC862LATINHEBREW"},\r
-\r
-    {866, "866"},\r
-    {866, "CP866"},\r
-    {866, "IBM866"},\r
-    {866, "CSIBM866"},\r
-\r
-    /* !IsValidCodePage(154) */\r
-    {154, "CP154"},\r
-    {154, "CYRILLIC-ASIAN"},\r
-    {154, "PT154"},\r
-    {154, "PTCP154"},\r
-    {154, "CSPTCP154"},\r
-\r
-    /* !IsValidCodePage(1133) */\r
-    {1133, "CP1133"},\r
-    {1133, "IBM-CP1133"},\r
-\r
-    {874, "CP874"},\r
-    {874, "WINDOWS-874"},\r
-\r
-    /* !IsValidCodePage(51932) */\r
-    {51932, "CP51932"},\r
-    {51932, "MS51932"},\r
-    {51932, "WINDOWS-51932"},\r
-    {51932, "EUC-JP"},\r
-\r
-    {932, "CP932"},\r
-    {932, "MS932"},\r
-    {932, "SHIFFT_JIS"},\r
-    {932, "SHIFFT_JIS-MS"},\r
-    {932, "SJIS"},\r
-    {932, "SJIS-MS"},\r
-    {932, "SJIS-OPEN"},\r
-    {932, "SJIS-WIN"},\r
-    {932, "WINDOWS-31J"},\r
-    {932, "WINDOWS-932"},\r
-    {932, "CSWINDOWS31J"},\r
-\r
-    {50221, "CP50221"},\r
-    {50221, "ISO-2022-JP"},\r
-    {50221, "ISO-2022-JP-MS"},\r
-    {50221, "ISO2022-JP"},\r
-    {50221, "ISO2022-JP-MS"},\r
-    {50221, "MS50221"},\r
-    {50221, "WINDOWS-50221"},\r
-\r
-    {936, "CP936"},\r
-    {936, "GBK"},\r
-    {936, "MS936"},\r
-    {936, "WINDOWS-936"},\r
-\r
-    {950, "CP950"},\r
-    {950, "BIG5"},\r
-\r
-    {949, "CP949"},\r
-    {949, "UHC"},\r
-    {949, "EUC-KR"},\r
-\r
-    {1361, "CP1361"},\r
-    {1361, "JOHAB"},\r
-\r
-    {437, "437"},\r
-    {437, "CP437"},\r
-    {437, "IBM437"},\r
-    {437, "CSPC8CODEPAGE437"},\r
-\r
-    {737, "CP737"},\r
-\r
-    {775, "CP775"},\r
-    {775, "IBM775"},\r
-    {775, "CSPC775BALTIC"},\r
-\r
-    {852, "852"},\r
-    {852, "CP852"},\r
-    {852, "IBM852"},\r
-    {852, "CSPCP852"},\r
-\r
-    /* !IsValidCodePage(853) */\r
-    {853, "CP853"},\r
-\r
-    {855, "855"},\r
-    {855, "CP855"},\r
-    {855, "IBM855"},\r
-    {855, "CSIBM855"},\r
-\r
-    {857, "857"},\r
-    {857, "CP857"},\r
-    {857, "IBM857"},\r
-    {857, "CSIBM857"},\r
-\r
-    /* !IsValidCodePage(858) */\r
-    {858, "CP858"},\r
-\r
-    {860, "860"},\r
-    {860, "CP860"},\r
-    {860, "IBM860"},\r
-    {860, "CSIBM860"},\r
-\r
-    {861, "861"},\r
-    {861, "CP-IS"},\r
-    {861, "CP861"},\r
-    {861, "IBM861"},\r
-    {861, "CSIBM861"},\r
-\r
-    {863, "863"},\r
-    {863, "CP863"},\r
-    {863, "IBM863"},\r
-    {863, "CSIBM863"},\r
-\r
-    {864, "CP864"},\r
-    {864, "IBM864"},\r
-    {864, "CSIBM864"},\r
-\r
-    {865, "865"},\r
-    {865, "CP865"},\r
-    {865, "IBM865"},\r
-    {865, "CSIBM865"},\r
-\r
-    {869, "869"},\r
-    {869, "CP-GR"},\r
-    {869, "CP869"},\r
-    {869, "IBM869"},\r
-    {869, "CSIBM869"},\r
-\r
-    /* !IsValidCodePage(1152) */\r
-    {1125, "CP1125"},\r
-\r
-    /*\r
-     * Code Page Identifiers\r
-     * http://msdn2.microsoft.com/en-us/library/ms776446.aspx\r
-     */\r
-    {37, "IBM037"}, /* IBM EBCDIC US-Canada */\r
-    {437, "IBM437"}, /* OEM United States */\r
-    {500, "IBM500"}, /* IBM EBCDIC International */\r
-    {708, "ASMO-708"}, /* Arabic (ASMO 708) */\r
-    /* 709             Arabic (ASMO-449+, BCON V4) */\r
-    /* 710             Arabic - Transparent Arabic */\r
-    {720, "DOS-720"}, /* Arabic (Transparent ASMO); Arabic (DOS) */\r
-    {737, "ibm737"}, /* OEM Greek (formerly 437G); Greek (DOS) */\r
-    {775, "ibm775"}, /* OEM Baltic; Baltic (DOS) */\r
-    {850, "ibm850"}, /* OEM Multilingual Latin 1; Western European (DOS) */\r
-    {852, "ibm852"}, /* OEM Latin 2; Central European (DOS) */\r
-    {855, "IBM855"}, /* OEM Cyrillic (primarily Russian) */\r
-    {857, "ibm857"}, /* OEM Turkish; Turkish (DOS) */\r
-    {858, "IBM00858"}, /* OEM Multilingual Latin 1 + Euro symbol */\r
-    {860, "IBM860"}, /* OEM Portuguese; Portuguese (DOS) */\r
-    {861, "ibm861"}, /* OEM Icelandic; Icelandic (DOS) */\r
-    {862, "DOS-862"}, /* OEM Hebrew; Hebrew (DOS) */\r
-    {863, "IBM863"}, /* OEM French Canadian; French Canadian (DOS) */\r
-    {864, "IBM864"}, /* OEM Arabic; Arabic (864) */\r
-    {865, "IBM865"}, /* OEM Nordic; Nordic (DOS) */\r
-    {866, "cp866"}, /* OEM Russian; Cyrillic (DOS) */\r
-    {869, "ibm869"}, /* OEM Modern Greek; Greek, Modern (DOS) */\r
-    {870, "IBM870"}, /* IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2 */\r
-    {874, "windows-874"}, /* ANSI/OEM Thai (same as 28605, ISO 8859-15); Thai (Windows) */\r
-    {875, "cp875"}, /* IBM EBCDIC Greek Modern */\r
-    {932, "shift_jis"}, /* ANSI/OEM Japanese; Japanese (Shift-JIS) */\r
-    {932, "shift-jis"}, /* alternative name for it */\r
-    {936, "gb2312"}, /* ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312) */\r
-    {949, "ks_c_5601-1987"}, /* ANSI/OEM Korean (Unified Hangul Code) */\r
-    {950, "big5"}, /* ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5) */\r
-    {1026, "IBM1026"}, /* IBM EBCDIC Turkish (Latin 5) */\r
-    {1047, "IBM01047"}, /* IBM EBCDIC Latin 1/Open System */\r
-    {1140, "IBM01140"}, /* IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro) */\r
-    {1141, "IBM01141"}, /* IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro) */\r
-    {1142, "IBM01142"}, /* IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro) */\r
-    {1143, "IBM01143"}, /* IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro) */\r
-    {1144, "IBM01144"}, /* IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro) */\r
-    {1145, "IBM01145"}, /* IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro) */\r
-    {1146, "IBM01146"}, /* IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro) */\r
-    {1147, "IBM01147"}, /* IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro) */\r
-    {1148, "IBM01148"}, /* IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro) */\r
-    {1149, "IBM01149"}, /* IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro) */\r
-    {1250, "windows-1250"}, /* ANSI Central European; Central European (Windows) */\r
-    {1251, "windows-1251"}, /* ANSI Cyrillic; Cyrillic (Windows) */\r
-    {1252, "windows-1252"}, /* ANSI Latin 1; Western European (Windows) */\r
-    {1253, "windows-1253"}, /* ANSI Greek; Greek (Windows) */\r
-    {1254, "windows-1254"}, /* ANSI Turkish; Turkish (Windows) */\r
-    {1255, "windows-1255"}, /* ANSI Hebrew; Hebrew (Windows) */\r
-    {1256, "windows-1256"}, /* ANSI Arabic; Arabic (Windows) */\r
-    {1257, "windows-1257"}, /* ANSI Baltic; Baltic (Windows) */\r
-    {1258, "windows-1258"}, /* ANSI/OEM Vietnamese; Vietnamese (Windows) */\r
-    {1361, "Johab"}, /* Korean (Johab) */\r
-    {10000, "macintosh"}, /* MAC Roman; Western European (Mac) */\r
-    {10001, "x-mac-japanese"}, /* Japanese (Mac) */\r
-    {10002, "x-mac-chinesetrad"}, /* MAC Traditional Chinese (Big5); Chinese Traditional (Mac) */\r
-    {10003, "x-mac-korean"}, /* Korean (Mac) */\r
-    {10004, "x-mac-arabic"}, /* Arabic (Mac) */\r
-    {10005, "x-mac-hebrew"}, /* Hebrew (Mac) */\r
-    {10006, "x-mac-greek"}, /* Greek (Mac) */\r
-    {10007, "x-mac-cyrillic"}, /* Cyrillic (Mac) */\r
-    {10008, "x-mac-chinesesimp"}, /* MAC Simplified Chinese (GB 2312); Chinese Simplified (Mac) */\r
-    {10010, "x-mac-romanian"}, /* Romanian (Mac) */\r
-    {10017, "x-mac-ukrainian"}, /* Ukrainian (Mac) */\r
-    {10021, "x-mac-thai"}, /* Thai (Mac) */\r
-    {10029, "x-mac-ce"}, /* MAC Latin 2; Central European (Mac) */\r
-    {10079, "x-mac-icelandic"}, /* Icelandic (Mac) */\r
-    {10081, "x-mac-turkish"}, /* Turkish (Mac) */\r
-    {10082, "x-mac-croatian"}, /* Croatian (Mac) */\r
-    {20000, "x-Chinese_CNS"}, /* CNS Taiwan; Chinese Traditional (CNS) */\r
-    {20001, "x-cp20001"}, /* TCA Taiwan */\r
-    {20002, "x_Chinese-Eten"}, /* Eten Taiwan; Chinese Traditional (Eten) */\r
-    {20003, "x-cp20003"}, /* IBM5550 Taiwan */\r
-    {20004, "x-cp20004"}, /* TeleText Taiwan */\r
-    {20005, "x-cp20005"}, /* Wang Taiwan */\r
-    {20105, "x-IA5"}, /* IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5) */\r
-    {20106, "x-IA5-German"}, /* IA5 German (7-bit) */\r
-    {20107, "x-IA5-Swedish"}, /* IA5 Swedish (7-bit) */\r
-    {20108, "x-IA5-Norwegian"}, /* IA5 Norwegian (7-bit) */\r
-    {20127, "us-ascii"}, /* US-ASCII (7-bit) */\r
-    {20261, "x-cp20261"}, /* T.61 */\r
-    {20269, "x-cp20269"}, /* ISO 6937 Non-Spacing Accent */\r
-    {20273, "IBM273"}, /* IBM EBCDIC Germany */\r
-    {20277, "IBM277"}, /* IBM EBCDIC Denmark-Norway */\r
-    {20278, "IBM278"}, /* IBM EBCDIC Finland-Sweden */\r
-    {20280, "IBM280"}, /* IBM EBCDIC Italy */\r
-    {20284, "IBM284"}, /* IBM EBCDIC Latin America-Spain */\r
-    {20285, "IBM285"}, /* IBM EBCDIC United Kingdom */\r
-    {20290, "IBM290"}, /* IBM EBCDIC Japanese Katakana Extended */\r
-    {20297, "IBM297"}, /* IBM EBCDIC France */\r
-    {20420, "IBM420"}, /* IBM EBCDIC Arabic */\r
-    {20423, "IBM423"}, /* IBM EBCDIC Greek */\r
-    {20424, "IBM424"}, /* IBM EBCDIC Hebrew */\r
-    {20833, "x-EBCDIC-KoreanExtended"}, /* IBM EBCDIC Korean Extended */\r
-    {20838, "IBM-Thai"}, /* IBM EBCDIC Thai */\r
-    {20866, "koi8-r"}, /* Russian (KOI8-R); Cyrillic (KOI8-R) */\r
-    {20871, "IBM871"}, /* IBM EBCDIC Icelandic */\r
-    {20880, "IBM880"}, /* IBM EBCDIC Cyrillic Russian */\r
-    {20905, "IBM905"}, /* IBM EBCDIC Turkish */\r
-    {20924, "IBM00924"}, /* IBM EBCDIC Latin 1/Open System (1047 + Euro symbol) */\r
-    {20932, "EUC-JP"}, /* Japanese (JIS 0208-1990 and 0121-1990) */\r
-    {20936, "x-cp20936"}, /* Simplified Chinese (GB2312); Chinese Simplified (GB2312-80) */\r
-    {20949, "x-cp20949"}, /* Korean Wansung */\r
-    {21025, "cp1025"}, /* IBM EBCDIC Cyrillic Serbian-Bulgarian */\r
-    /* 21027           (deprecated) */\r
-    {21866, "koi8-u"}, /* Ukrainian (KOI8-U); Cyrillic (KOI8-U) */\r
-    {28591, "iso-8859-1"}, /* ISO 8859-1 Latin 1; Western European (ISO) */\r
-    {28591, "iso8859-1"}, /* ISO 8859-1 Latin 1; Western European (ISO) */\r
-    {28592, "iso-8859-2"}, /* ISO 8859-2 Central European; Central European (ISO) */\r
-    {28592, "iso8859-2"}, /* ISO 8859-2 Central European; Central European (ISO) */\r
-    {28593, "iso-8859-3"}, /* ISO 8859-3 Latin 3 */\r
-    {28593, "iso8859-3"}, /* ISO 8859-3 Latin 3 */\r
-    {28594, "iso-8859-4"}, /* ISO 8859-4 Baltic */\r
-    {28594, "iso8859-4"}, /* ISO 8859-4 Baltic */\r
-    {28595, "iso-8859-5"}, /* ISO 8859-5 Cyrillic */\r
-    {28595, "iso8859-5"}, /* ISO 8859-5 Cyrillic */\r
-    {28596, "iso-8859-6"}, /* ISO 8859-6 Arabic */\r
-    {28596, "iso8859-6"}, /* ISO 8859-6 Arabic */\r
-    {28597, "iso-8859-7"}, /* ISO 8859-7 Greek */\r
-    {28597, "iso8859-7"}, /* ISO 8859-7 Greek */\r
-    {28598, "iso-8859-8"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */\r
-    {28598, "iso8859-8"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */\r
-    {28599, "iso-8859-9"}, /* ISO 8859-9 Turkish */\r
-    {28599, "iso8859-9"}, /* ISO 8859-9 Turkish */\r
-    {28603, "iso-8859-13"}, /* ISO 8859-13 Estonian */\r
-    {28603, "iso8859-13"}, /* ISO 8859-13 Estonian */\r
-    {28605, "iso-8859-15"}, /* ISO 8859-15 Latin 9 */\r
-    {28605, "iso8859-15"}, /* ISO 8859-15 Latin 9 */\r
-    {29001, "x-Europa"}, /* Europa 3 */\r
-    {38598, "iso-8859-8-i"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */\r
-    {38598, "iso8859-8-i"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */\r
-    {50220, "iso-2022-jp"}, /* ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS) */\r
-    {50221, "csISO2022JP"}, /* ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana) */\r
-    {50222, "iso-2022-jp"}, /* ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI) */\r
-    {50225, "iso-2022-kr"}, /* ISO 2022 Korean */\r
-    {50225, "iso2022-kr"}, /* ISO 2022 Korean */\r
-    {50227, "x-cp50227"}, /* ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022) */\r
-    /* 50229           ISO 2022 Traditional Chinese */\r
-    /* 50930           EBCDIC Japanese (Katakana) Extended */\r
-    /* 50931           EBCDIC US-Canada and Japanese */\r
-    /* 50933           EBCDIC Korean Extended and Korean */\r
-    /* 50935           EBCDIC Simplified Chinese Extended and Simplified Chinese */\r
-    /* 50936           EBCDIC Simplified Chinese */\r
-    /* 50937           EBCDIC US-Canada and Traditional Chinese */\r
-    /* 50939           EBCDIC Japanese (Latin) Extended and Japanese */\r
-    {51932, "euc-jp"}, /* EUC Japanese */\r
-    {51936, "EUC-CN"}, /* EUC Simplified Chinese; Chinese Simplified (EUC) */\r
-    {51949, "euc-kr"}, /* EUC Korean */\r
-    /* 51950           EUC Traditional Chinese */\r
-    {52936, "hz-gb-2312"}, /* HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ) */\r
-    {54936, "GB18030"}, /* Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030) */\r
-    {57002, "x-iscii-de"}, /* ISCII Devanagari */\r
-    {57003, "x-iscii-be"}, /* ISCII Bengali */\r
-    {57004, "x-iscii-ta"}, /* ISCII Tamil */\r
-    {57005, "x-iscii-te"}, /* ISCII Telugu */\r
-    {57006, "x-iscii-as"}, /* ISCII Assamese */\r
-    {57007, "x-iscii-or"}, /* ISCII Oriya */\r
-    {57008, "x-iscii-ka"}, /* ISCII Kannada */\r
-    {57009, "x-iscii-ma"}, /* ISCII Malayalam */\r
-    {57010, "x-iscii-gu"}, /* ISCII Gujarati */\r
-    {57011, "x-iscii-pa"}, /* ISCII Punjabi */\r
-\r
-    {0, NULL}\r
-};\r
-\r
-/*\r
- * SJIS SHIFTJIS table              CP932 table\r
- * ---- --------------------------- --------------------------------\r
- *   5C U+00A5 YEN SIGN             U+005C REVERSE SOLIDUS\r
- *   7E U+203E OVERLINE             U+007E TILDE\r
- * 815C U+2014 EM DASH              U+2015 HORIZONTAL BAR\r
- * 815F U+005C REVERSE SOLIDUS      U+FF3C FULLWIDTH REVERSE SOLIDUS\r
- * 8160 U+301C WAVE DASH            U+FF5E FULLWIDTH TILDE\r
- * 8161 U+2016 DOUBLE VERTICAL LINE U+2225 PARALLEL TO\r
- * 817C U+2212 MINUS SIGN           U+FF0D FULLWIDTH HYPHEN-MINUS\r
- * 8191 U+00A2 CENT SIGN            U+FFE0 FULLWIDTH CENT SIGN\r
- * 8192 U+00A3 POUND SIGN           U+FFE1 FULLWIDTH POUND SIGN\r
- * 81CA U+00AC NOT SIGN             U+FFE2 FULLWIDTH NOT SIGN\r
- *\r
- * EUC-JP and ISO-2022-JP should be compatible with CP932.\r
- *\r
- * Kernel and MLang have different Unicode mapping table.  Make sure\r
- * which API is used.\r
- */\r
-static compat_t cp932_compat[] = {\r
-    {0x00A5, 0x005C, COMPAT_OUT},\r
-    {0x203E, 0x007E, COMPAT_OUT},\r
-    {0x2014, 0x2015, COMPAT_OUT},\r
-    {0x301C, 0xFF5E, COMPAT_OUT},\r
-    {0x2016, 0x2225, COMPAT_OUT},\r
-    {0x2212, 0xFF0D, COMPAT_OUT},\r
-    {0x00A2, 0xFFE0, COMPAT_OUT},\r
-    {0x00A3, 0xFFE1, COMPAT_OUT},\r
-    {0x00AC, 0xFFE2, COMPAT_OUT},\r
-    {0, 0, 0}\r
-};\r
-\r
-static compat_t cp20932_compat[] = {\r
-    {0x00A5, 0x005C, COMPAT_OUT},\r
-    {0x203E, 0x007E, COMPAT_OUT},\r
-    {0x2014, 0x2015, COMPAT_OUT},\r
-    {0xFF5E, 0x301C, COMPAT_OUT|COMPAT_IN},\r
-    {0x2225, 0x2016, COMPAT_OUT|COMPAT_IN},\r
-    {0xFF0D, 0x2212, COMPAT_OUT|COMPAT_IN},\r
-    {0xFFE0, 0x00A2, COMPAT_OUT|COMPAT_IN},\r
-    {0xFFE1, 0x00A3, COMPAT_OUT|COMPAT_IN},\r
-    {0xFFE2, 0x00AC, COMPAT_OUT|COMPAT_IN},\r
-    {0, 0, 0}\r
-};\r
-\r
-static compat_t *cp51932_compat = cp932_compat;\r
-\r
-/* cp20932_compat for kernel.  cp932_compat for mlang. */\r
-static compat_t *cp5022x_compat = cp932_compat;\r
-\r
-typedef HRESULT (WINAPI *CONVERTINETSTRING)(\r
-    LPDWORD lpdwMode,\r
-    DWORD dwSrcEncoding,\r
-    DWORD dwDstEncoding,\r
-    LPCSTR lpSrcStr,\r
-    LPINT lpnSrcSize,\r
-    LPBYTE lpDstStr,\r
-    LPINT lpnDstSize\r
-);\r
-typedef HRESULT (WINAPI *CONVERTINETMULTIBYTETOUNICODE)(\r
-    LPDWORD lpdwMode,\r
-    DWORD dwSrcEncoding,\r
-    LPCSTR lpSrcStr,\r
-    LPINT lpnMultiCharCount,\r
-    LPWSTR lpDstStr,\r
-    LPINT lpnWideCharCount\r
-);\r
-typedef HRESULT (WINAPI *CONVERTINETUNICODETOMULTIBYTE)(\r
-    LPDWORD lpdwMode,\r
-    DWORD dwEncoding,\r
-    LPCWSTR lpSrcStr,\r
-    LPINT lpnWideCharCount,\r
-    LPSTR lpDstStr,\r
-    LPINT lpnMultiCharCount\r
-);\r
-typedef HRESULT (WINAPI *ISCONVERTINETSTRINGAVAILABLE)(\r
-    DWORD dwSrcEncoding,\r
-    DWORD dwDstEncoding\r
-);\r
-typedef HRESULT (WINAPI *LCIDTORFC1766A)(\r
-    LCID Locale,\r
-    LPSTR pszRfc1766,\r
-    int nChar\r
-);\r
-typedef HRESULT (WINAPI *LCIDTORFC1766W)(\r
-    LCID Locale,\r
-    LPWSTR pszRfc1766,\r
-    int nChar\r
-);\r
-typedef HRESULT (WINAPI *RFC1766TOLCIDA)(\r
-    LCID *pLocale,\r
-    LPSTR pszRfc1766\r
-);\r
-typedef HRESULT (WINAPI *RFC1766TOLCIDW)(\r
-    LCID *pLocale,\r
-    LPWSTR pszRfc1766\r
-);\r
-static CONVERTINETSTRING ConvertINetString;\r
-static CONVERTINETMULTIBYTETOUNICODE ConvertINetMultiByteToUnicode;\r
-static CONVERTINETUNICODETOMULTIBYTE ConvertINetUnicodeToMultiByte;\r
-static ISCONVERTINETSTRINGAVAILABLE IsConvertINetStringAvailable;\r
-static LCIDTORFC1766A LcidToRfc1766A;\r
-static RFC1766TOLCIDA Rfc1766ToLcidA;\r
-\r
-static int\r
-load_mlang()\r
-{\r
-    HMODULE h;\r
-    if (ConvertINetString != NULL)\r
-        return TRUE;\r
-    h = LoadLibrary("mlang.dll");\r
-    if (!h)\r
-        return FALSE;\r
-    ConvertINetString = (CONVERTINETSTRING)GetProcAddress(h, "ConvertINetString");\r
-    ConvertINetMultiByteToUnicode = (CONVERTINETMULTIBYTETOUNICODE)GetProcAddress(h, "ConvertINetMultiByteToUnicode");\r
-    ConvertINetUnicodeToMultiByte = (CONVERTINETUNICODETOMULTIBYTE)GetProcAddress(h, "ConvertINetUnicodeToMultiByte");\r
-    IsConvertINetStringAvailable = (ISCONVERTINETSTRINGAVAILABLE)GetProcAddress(h, "IsConvertINetStringAvailable");\r
-    LcidToRfc1766A = (LCIDTORFC1766A)GetProcAddress(h, "LcidToRfc1766A");\r
-    Rfc1766ToLcidA = (RFC1766TOLCIDA)GetProcAddress(h, "Rfc1766ToLcidA");\r
-    return TRUE;\r
-}\r
-\r
-iconv_t\r
-iconv_open(const char *tocode, const char *fromcode)\r
-{\r
-    rec_iconv_t *cd;\r
-\r
-    cd = (rec_iconv_t *)calloc(1, sizeof(rec_iconv_t));\r
-    if (cd == NULL)\r
-        return (iconv_t)(-1);\r
-\r
-#if defined(USE_LIBICONV_DLL)\r
-    errno = 0;\r
-    if (libiconv_iconv_open(cd, tocode, fromcode))\r
-        return (iconv_t)cd;\r
-#endif\r
-\r
-    /* reset the errno to prevent reporting wrong error code.\r
-     * 0 for unsorted error. */\r
-    errno = 0;\r
-    if (win_iconv_open(cd, tocode, fromcode))\r
-        return (iconv_t)cd;\r
-\r
-    free(cd);\r
-\r
-    return (iconv_t)(-1);\r
-}\r
-\r
-int\r
-iconv_close(iconv_t _cd)\r
-{\r
-    rec_iconv_t *cd = (rec_iconv_t *)_cd;\r
-    int r = cd->iconv_close(cd->cd);\r
-    int e = *(cd->_errno());\r
-#if defined(USE_LIBICONV_DLL)\r
-    if (cd->hlibiconv != NULL)\r
-        FreeLibrary(cd->hlibiconv);\r
-#endif\r
-    free(cd);\r
-    errno = e;\r
-    return r;\r
-}\r
-\r
-size_t\r
-iconv(iconv_t _cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)\r
-{\r
-    rec_iconv_t *cd = (rec_iconv_t *)_cd;\r
-    size_t r = cd->iconv(cd->cd, inbuf, inbytesleft, outbuf, outbytesleft);\r
-    errno = *(cd->_errno());\r
-    return r;\r
-}\r
-\r
-static int\r
-win_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode)\r
-{\r
-    if (!make_csconv(fromcode, &cd->from) || !make_csconv(tocode, &cd->to))\r
-        return FALSE;\r
-    cd->iconv_close = win_iconv_close;\r
-    cd->iconv = win_iconv;\r
-    cd->_errno = _errno;\r
-    cd->cd = (iconv_t)cd;\r
-    return TRUE;\r
-}\r
-\r
-static int\r
-win_iconv_close(iconv_t cd)\r
-{\r
-    return 0;\r
-}\r
-\r
-static size_t\r
-win_iconv(iconv_t _cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)\r
-{\r
-    rec_iconv_t *cd = (rec_iconv_t *)_cd;\r
-    ushort wbuf[MB_CHAR_MAX]; /* enough room for one character */\r
-    int insize;\r
-    int outsize;\r
-    int wsize;\r
-    DWORD frommode;\r
-    DWORD tomode;\r
-    uint wc;\r
-    compat_t *cp;\r
-    int i;\r
-\r
-    if (inbuf == NULL || *inbuf == NULL)\r
-    {\r
-        if (outbuf != NULL && *outbuf != NULL && cd->to.flush != NULL)\r
-        {\r
-            tomode = cd->to.mode;\r
-            outsize = cd->to.flush(&cd->to, (uchar *)*outbuf, *outbytesleft);\r
-            if (outsize == -1)\r
-            {\r
-                cd->to.mode = tomode;\r
-                return (size_t)(-1);\r
-            }\r
-            *outbuf += outsize;\r
-            *outbytesleft -= outsize;\r
-        }\r
-        cd->from.mode = 0;\r
-        cd->to.mode = 0;\r
-        return 0;\r
-    }\r
-\r
-    while (*inbytesleft != 0)\r
-    {\r
-        frommode = cd->from.mode;\r
-        tomode = cd->to.mode;\r
-        wsize = MB_CHAR_MAX;\r
-\r
-        insize = cd->from.mbtowc(&cd->from, (const uchar *)*inbuf, *inbytesleft, wbuf, &wsize);\r
-        if (insize == -1)\r
-        {\r
-            cd->from.mode = frommode;\r
-            return (size_t)(-1);\r
-        }\r
-\r
-        if (wsize == 0)\r
-        {\r
-            *inbuf += insize;\r
-            *inbytesleft -= insize;\r
-            continue;\r
-        }\r
-\r
-        if (cd->from.compat != NULL)\r
-        {\r
-            wc = utf16_to_ucs4(wbuf);\r
-            cp = cd->from.compat;\r
-            for (i = 0; cp[i].in != 0; ++i)\r
-            {\r
-                if ((cp[i].flag & COMPAT_IN) && cp[i].out == wc)\r
-                {\r
-                    ucs4_to_utf16(cp[i].in, wbuf, &wsize);\r
-                    break;\r
-                }\r
-            }\r
-        }\r
-\r
-        if (cd->to.compat != NULL)\r
-        {\r
-            wc = utf16_to_ucs4(wbuf);\r
-            cp = cd->to.compat;\r
-            for (i = 0; cp[i].in != 0; ++i)\r
-            {\r
-                if ((cp[i].flag & COMPAT_OUT) && cp[i].in == wc)\r
-                {\r
-                    ucs4_to_utf16(cp[i].out, wbuf, &wsize);\r
-                    break;\r
-                }\r
-            }\r
-        }\r
-\r
-        outsize = cd->to.wctomb(&cd->to, wbuf, wsize, (uchar *)*outbuf, *outbytesleft);\r
-        if (outsize == -1)\r
-        {\r
-            cd->from.mode = frommode;\r
-            cd->to.mode = tomode;\r
-            return (size_t)(-1);\r
-        }\r
-\r
-        *inbuf += insize;\r
-        *outbuf += outsize;\r
-        *inbytesleft -= insize;\r
-        *outbytesleft -= outsize;\r
-    }\r
-\r
-    return 0;\r
-}\r
-\r
-static int\r
-make_csconv(const char *_name, csconv_t *cv)\r
-{\r
-    CPINFOEX cpinfoex;\r
-    int use_compat = TRUE;\r
-    int flag = 0;\r
-    char *name;\r
-    char *p;\r
-\r
-    name = xstrndup(_name, strlen(_name));\r
-    if (name == NULL)\r
-        return FALSE;\r
-\r
-    /* check for option "enc_name//opt1//opt2" */\r
-    while ((p = strrstr(name, "//")) != NULL)\r
-    {\r
-        if (_stricmp(p + 2, "nocompat") == 0)\r
-            use_compat = FALSE;\r
-        else if (_stricmp(p + 2, "translit") == 0)\r
-            flag |= FLAG_TRANSLIT;\r
-        else if (_stricmp(p + 2, "ignore") == 0)\r
-            flag |= FLAG_IGNORE;\r
-        *p = 0;\r
-    }\r
-\r
-    cv->mode = 0;\r
-    cv->flags = flag;\r
-    cv->mblen = NULL;\r
-    cv->flush = NULL;\r
-    cv->compat = NULL;\r
-    cv->codepage = name_to_codepage(name);\r
-    if (cv->codepage == 1200 || cv->codepage == 1201)\r
-    {\r
-        cv->mbtowc = utf16_mbtowc;\r
-        cv->wctomb = utf16_wctomb;\r
-        if (_stricmp(name, "UTF-16") == 0 || _stricmp(name, "UTF16") == 0)\r
-            cv->flags |= FLAG_USE_BOM;\r
-    }\r
-    else if (cv->codepage == 12000 || cv->codepage == 12001)\r
-    {\r
-        cv->mbtowc = utf32_mbtowc;\r
-        cv->wctomb = utf32_wctomb;\r
-        if (_stricmp(name, "UTF-32") == 0 || _stricmp(name, "UTF32") == 0)\r
-            cv->flags |= FLAG_USE_BOM;\r
-    }\r
-    else if (cv->codepage == 65001)\r
-    {\r
-        cv->mbtowc = kernel_mbtowc;\r
-        cv->wctomb = kernel_wctomb;\r
-        cv->mblen = utf8_mblen;\r
-    }\r
-    else if ((cv->codepage == 50220 || cv->codepage == 50221 || cv->codepage == 50222) && load_mlang())\r
-    {\r
-        cv->mbtowc = iso2022jp_mbtowc;\r
-        cv->wctomb = iso2022jp_wctomb;\r
-        cv->flush = iso2022jp_flush;\r
-    }\r
-    else if (cv->codepage == 51932 && load_mlang())\r
-    {\r
-        cv->mbtowc = mlang_mbtowc;\r
-        cv->wctomb = mlang_wctomb;\r
-        cv->mblen = eucjp_mblen;\r
-    }\r
-    else if (IsValidCodePage(cv->codepage)\r
-            && GetCPInfoEx(cv->codepage, 0, &cpinfoex) != 0)\r
-    {\r
-        cv->mbtowc = kernel_mbtowc;\r
-        cv->wctomb = kernel_wctomb;\r
-        if (cpinfoex.MaxCharSize == 1)\r
-            cv->mblen = sbcs_mblen;\r
-        else if (cpinfoex.MaxCharSize == 2)\r
-            cv->mblen = dbcs_mblen;\r
-       else\r
-           cv->mblen = mbcs_mblen;\r
-    }\r
-    else\r
-    {\r
-        /* not supported */\r
-        free(name);\r
-        errno = EINVAL;\r
-        return FALSE;\r
-    }\r
-\r
-    if (use_compat)\r
-    {\r
-        switch (cv->codepage)\r
-        {\r
-        case 932: cv->compat = cp932_compat; break;\r
-        case 20932: cv->compat = cp20932_compat; break;\r
-        case 51932: cv->compat = cp51932_compat; break;\r
-        case 50220: case 50221: case 50222: cv->compat = cp5022x_compat; break;\r
-        }\r
-    }\r
-\r
-    free(name);\r
-\r
-    return TRUE;\r
-}\r
-\r
-static int\r
-name_to_codepage(const char *name)\r
-{\r
-    int i;\r
-\r
-    if (*name == '\0' ||\r
-       strcmp(name, "char") == 0)\r
-        return GetACP();\r
-    else if (strcmp(name, "wchar_t") == 0)\r
-        return 1200;\r
-    else if (_strnicmp(name, "cp", 2) == 0)\r
-        return atoi(name + 2); /* CP123 */\r
-    else if ('0' <= name[0] && name[0] <= '9')\r
-        return atoi(name);     /* 123 */\r
-    else if (_strnicmp(name, "xx", 2) == 0)\r
-        return atoi(name + 2); /* XX123 for debug */\r
-\r
-    for (i = 0; codepage_alias[i].name != NULL; ++i)\r
-        if (_stricmp(name, codepage_alias[i].name) == 0)\r
-            return codepage_alias[i].codepage;\r
-    return -1;\r
-}\r
-\r
-/*\r
- * http://www.faqs.org/rfcs/rfc2781.html\r
- */\r
-static uint\r
-utf16_to_ucs4(const ushort *wbuf)\r
-{\r
-    uint wc = wbuf[0];\r
-    if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)\r
-        wc = ((wbuf[0] & 0x3FF) << 10) + (wbuf[1] & 0x3FF) + 0x10000;\r
-    return wc;\r
-}\r
-\r
-static void\r
-ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize)\r
-{\r
-    if (wc < 0x10000)\r
-    {\r
-        wbuf[0] = wc;\r
-        *wbufsize = 1;\r
-    }\r
-    else\r
-    {\r
-        wc -= 0x10000;\r
-        wbuf[0] = 0xD800 | ((wc >> 10) & 0x3FF);\r
-        wbuf[1] = 0xDC00 | (wc & 0x3FF);\r
-        *wbufsize = 2;\r
-    }\r
-}\r
-\r
-/*\r
- * Check if codepage is one of those for which the dwFlags parameter\r
- * to MultiByteToWideChar() must be zero. Return zero or\r
- * MB_ERR_INVALID_CHARS.  The docs in Platform SDK for for Windows\r
- * Server 2003 R2 claims that also codepage 65001 is one of these, but\r
- * that doesn't seem to be the case. The MSDN docs for MSVS2008 leave\r
- * out 65001 (UTF-8), and that indeed seems to be the case on XP, it\r
- * works fine to pass MB_ERR_INVALID_CHARS in dwFlags when converting\r
- * from UTF-8.\r
- */\r
-static int\r
-mbtowc_flags(int codepage)\r
-{\r
-    return (codepage == 50220 || codepage == 50221 ||\r
-           codepage == 50222 || codepage == 50225 ||\r
-           codepage == 50227 || codepage == 50229 ||\r
-           codepage == 52936 || codepage == 54936 ||\r
-           (codepage >= 57002 && codepage <= 57011) ||\r
-           codepage == 65000 || codepage == 42) ? 0 : MB_ERR_INVALID_CHARS;\r
-}\r
-\r
-/*\r
- * Check if codepage is one those for which the lpUsedDefaultChar\r
- * parameter to WideCharToMultiByte() must be NULL.  The docs in\r
- * Platform SDK for for Windows Server 2003 R2 claims that this is the\r
- * list below, while the MSDN docs for MSVS2008 claim that it is only\r
- * for 65000 (UTF-7) and 65001 (UTF-8). This time the earlier Platform\r
- * SDK seems to be correct, at least for XP.\r
- */\r
-static int\r
-must_use_null_useddefaultchar(int codepage)\r
-{\r
-    return (codepage == 65000 || codepage == 65001 ||\r
-            codepage == 50220 || codepage == 50221 ||\r
-            codepage == 50222 || codepage == 50225 ||\r
-            codepage == 50227 || codepage == 50229 ||\r
-            codepage == 52936 || codepage == 54936 ||\r
-            (codepage >= 57002 && codepage <= 57011) ||\r
-            codepage == 42);\r
-}\r
-\r
-static char *\r
-strrstr(const char *str, const char *token)\r
-{\r
-    int len = strlen(token);\r
-    const char *p = str + strlen(str);\r
-\r
-    while (str <= --p)\r
-        if (p[0] == token[0] && strncmp(p, token, len) == 0)\r
-            return (char *)p;\r
-    return NULL;\r
-}\r
-\r
-static char *\r
-xstrndup(const char *s, size_t n)\r
-{\r
-    char *p;\r
-\r
-    p = (char *)malloc(n + 1);\r
-    if (p == NULL)\r
-        return NULL;\r
-    memcpy(p, s, n);\r
-    p[n] = '\0';\r
-    return p;\r
-}\r
-\r
-static int\r
-seterror(int err)\r
-{\r
-    errno = err;\r
-    return -1;\r
-}\r
-\r
-#if defined(USE_LIBICONV_DLL)\r
-static int\r
-libiconv_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode)\r
-{\r
-    HMODULE hlibiconv = NULL;\r
-    HMODULE hmsvcrt = NULL;\r
-    char *dllname;\r
-    const char *p;\r
-    const char *e;\r
-    f_iconv_open _iconv_open;\r
-\r
-    /*\r
-     * always try to load dll, so that we can switch dll in runtime.\r
-     */\r
-\r
-    /* XXX: getenv() can't get variable set by SetEnvironmentVariable() */\r
-    p = getenv("WINICONV_LIBICONV_DLL");\r
-    if (p == NULL)\r
-        p = DEFAULT_LIBICONV_DLL;\r
-    /* parse comma separated value */\r
-    for ( ; *p != 0; p = (*e == ',') ? e + 1 : e)\r
-    {\r
-        e = strchr(p, ',');\r
-        if (p == e)\r
-            continue;\r
-        else if (e == NULL)\r
-            e = p + strlen(p);\r
-        dllname = xstrndup(p, e - p);\r
-        if (dllname == NULL)\r
-            return FALSE;\r
-        hlibiconv = LoadLibrary(dllname);\r
-        free(dllname);\r
-        if (hlibiconv != NULL)\r
-        {\r
-            if (hlibiconv == hwiniconv)\r
-            {\r
-                FreeLibrary(hlibiconv);\r
-                hlibiconv = NULL;\r
-                continue;\r
-            }\r
-            break;\r
-        }\r
-    }\r
-\r
-    if (hlibiconv == NULL)\r
-        goto failed;\r
-\r
-    hmsvcrt = find_imported_module_by_funcname(hlibiconv, "_errno");\r
-    if (hmsvcrt == NULL)\r
-        goto failed;\r
-\r
-    _iconv_open = (f_iconv_open)GetProcAddress(hlibiconv, "libiconv_open");\r
-    if (_iconv_open == NULL)\r
-        _iconv_open = (f_iconv_open)GetProcAddress(hlibiconv, "iconv_open");\r
-    cd->iconv_close = (f_iconv_close)GetProcAddress(hlibiconv, "libiconv_close");\r
-    if (cd->iconv_close == NULL)\r
-        cd->iconv_close = (f_iconv_close)GetProcAddress(hlibiconv, "iconv_close");\r
-    cd->iconv = (f_iconv)GetProcAddress(hlibiconv, "libiconv");\r
-    if (cd->iconv == NULL)\r
-        cd->iconv = (f_iconv)GetProcAddress(hlibiconv, "iconv");\r
-    cd->_errno = (f_errno)GetProcAddress(hmsvcrt, "_errno");\r
-    if (_iconv_open == NULL || cd->iconv_close == NULL\r
-            || cd->iconv == NULL || cd->_errno == NULL)\r
-        goto failed;\r
-\r
-    cd->cd = _iconv_open(tocode, fromcode);\r
-    if (cd->cd == (iconv_t)(-1))\r
-        goto failed;\r
-\r
-    cd->hlibiconv = hlibiconv;\r
-    return TRUE;\r
-\r
-failed:\r
-    if (hlibiconv != NULL)\r
-        FreeLibrary(hlibiconv);\r
-    /* do not free hmsvcrt which is obtained by GetModuleHandle() */\r
-    return FALSE;\r
-}\r
-\r
-/*\r
- * Reference:\r
- * http://forums.belution.com/ja/vc/000/234/78s.shtml\r
- * http://nienie.com/~masapico/api_ImageDirectoryEntryToData.html\r
- *\r
- * The formal way is\r
- *   imagehlp.h or dbghelp.h\r
- *   imagehlp.lib or dbghelp.lib\r
- *   ImageDirectoryEntryToData()\r
- */\r
-#define TO_DOS_HEADER(base) ((PIMAGE_DOS_HEADER)(base))\r
-#define TO_NT_HEADERS(base) ((PIMAGE_NT_HEADERS)((LPBYTE)(base) + TO_DOS_HEADER(base)->e_lfanew))\r
-static PVOID\r
-MyImageDirectoryEntryToData(LPVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size)\r
-{\r
-    /* TODO: MappedAsImage? */\r
-    PIMAGE_DATA_DIRECTORY p;\r
-    p = TO_NT_HEADERS(Base)->OptionalHeader.DataDirectory + DirectoryEntry;\r
-    if (p->VirtualAddress == 0) {\r
-      *Size = 0;\r
-      return NULL;\r
-    }\r
-    *Size = p->Size;\r
-    return (PVOID)((LPBYTE)Base + p->VirtualAddress);\r
-}\r
-\r
-static HMODULE\r
-find_imported_module_by_funcname(HMODULE hModule, const char *funcname)\r
-{\r
-    DWORD Base;\r
-    ULONG Size;\r
-    PIMAGE_IMPORT_DESCRIPTOR Imp;\r
-    PIMAGE_THUNK_DATA Name;         /* Import Name Table */\r
-    PIMAGE_IMPORT_BY_NAME ImpName;\r
-\r
-    Base = (DWORD)hModule;\r
-    Imp = MyImageDirectoryEntryToData(\r
-            (LPVOID)Base,\r
-            TRUE,\r
-            IMAGE_DIRECTORY_ENTRY_IMPORT,\r
-            &Size);\r
-    if (Imp == NULL)\r
-        return NULL;\r
-    for ( ; Imp->OriginalFirstThunk != 0; ++Imp)\r
-    {\r
-        Name = (PIMAGE_THUNK_DATA)(Base + Imp->OriginalFirstThunk);\r
-        for ( ; Name->u1.Ordinal != 0; ++Name)\r
-        {\r
-            if (!IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal))\r
-            {\r
-                ImpName = (PIMAGE_IMPORT_BY_NAME)\r
-                    (Base + (DWORD)Name->u1.AddressOfData);\r
-                if (strcmp((char *)ImpName->Name, funcname) == 0)\r
-                    return GetModuleHandle((char *)(Base + Imp->Name));\r
-            }\r
-        }\r
-    }\r
-    return NULL;\r
-}\r
-#endif\r
-\r
-static int\r
-sbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)\r
-{\r
-    return 1;\r
-}\r
-\r
-static int\r
-dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)\r
-{\r
-    int len = IsDBCSLeadByteEx(cv->codepage, buf[0]) ? 2 : 1;\r
-    if (bufsize < len)\r
-        return seterror(EINVAL);\r
-    return len;\r
-}\r
-\r
-static int\r
-mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)\r
-{\r
-    int len = 0;\r
-\r
-    if (cv->codepage == 54936) {\r
-       if (buf[0] <= 0x7F) len = 1;\r
-       else if (buf[0] >= 0x81 && buf[0] <= 0xFE &&\r
-                bufsize >= 2 &&\r
-                ((buf[1] >= 0x40 && buf[1] <= 0x7E) ||\r
-                 (buf[1] >= 0x80 && buf[1] <= 0xFE))) len = 2;\r
-       else if (buf[0] >= 0x81 && buf[0] <= 0xFE &&\r
-                bufsize >= 4 &&\r
-                buf[1] >= 0x30 && buf[1] <= 0x39) len = 4;\r
-       else\r
-           return seterror(EINVAL);\r
-       return len;\r
-    }\r
-    else\r
-       return seterror(EINVAL);\r
-}\r
-\r
-static int\r
-utf8_mblen(csconv_t *cv, const uchar *buf, int bufsize)\r
-{\r
-    int len = 0;\r
-\r
-    if (buf[0] < 0x80) len = 1;\r
-    else if ((buf[0] & 0xE0) == 0xC0) len = 2;\r
-    else if ((buf[0] & 0xF0) == 0xE0) len = 3;\r
-    else if ((buf[0] & 0xF8) == 0xF0) len = 4;\r
-    else if ((buf[0] & 0xFC) == 0xF8) len = 5;\r
-    else if ((buf[0] & 0xFE) == 0xFC) len = 6;\r
-\r
-    if (len == 0)\r
-        return seterror(EILSEQ);\r
-    else if (bufsize < len)\r
-        return seterror(EINVAL);\r
-    return len;\r
-}\r
-\r
-static int\r
-eucjp_mblen(csconv_t *cv, const uchar *buf, int bufsize)\r
-{\r
-    if (buf[0] < 0x80) /* ASCII */\r
-        return 1;\r
-    else if (buf[0] == 0x8E) /* JIS X 0201 */\r
-    {\r
-        if (bufsize < 2)\r
-            return seterror(EINVAL);\r
-        else if (!(0xA1 <= buf[1] && buf[1] <= 0xDF))\r
-            return seterror(EILSEQ);\r
-        return 2;\r
-    }\r
-    else if (buf[0] == 0x8F) /* JIS X 0212 */\r
-    {\r
-        if (bufsize < 3)\r
-            return seterror(EINVAL);\r
-        else if (!(0xA1 <= buf[1] && buf[1] <= 0xFE)\r
-                || !(0xA1 <= buf[2] && buf[2] <= 0xFE))\r
-            return seterror(EILSEQ);\r
-        return 3;\r
-    }\r
-    else /* JIS X 0208 */\r
-    {\r
-        if (bufsize < 2)\r
-            return seterror(EINVAL);\r
-        else if (!(0xA1 <= buf[0] && buf[0] <= 0xFE)\r
-                || !(0xA1 <= buf[1] && buf[1] <= 0xFE))\r
-            return seterror(EILSEQ);\r
-        return 2;\r
-    }\r
-}\r
-\r
-static int\r
-kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)\r
-{\r
-    int len;\r
-\r
-    len = cv->mblen(cv, buf, bufsize);\r
-    if (len == -1)\r
-        return -1;\r
-    *wbufsize = MultiByteToWideChar(cv->codepage, mbtowc_flags (cv->codepage),\r
-            (const char *)buf, len, (wchar_t *)wbuf, *wbufsize);\r
-    if (*wbufsize == 0)\r
-        return seterror(EILSEQ);\r
-    return len;\r
-}\r
-\r
-static int\r
-kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)\r
-{\r
-    BOOL usedDefaultChar = 0;\r
-    BOOL *p = NULL;\r
-    int flags = 0;\r
-    int len;\r
-\r
-    if (bufsize == 0)\r
-        return seterror(E2BIG);\r
-    if (!must_use_null_useddefaultchar(cv->codepage))\r
-    {\r
-        p = &usedDefaultChar;\r
-#ifdef WC_NO_BEST_FIT_CHARS\r
-        if (!(cv->flags & FLAG_TRANSLIT))\r
-            flags |= WC_NO_BEST_FIT_CHARS;\r
-#endif\r
-    }\r
-    len = WideCharToMultiByte(cv->codepage, flags,\r
-            (const wchar_t *)wbuf, wbufsize, (char *)buf, bufsize, NULL, p);\r
-    if (len == 0)\r
-    {\r
-        if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)\r
-            return seterror(E2BIG);\r
-        return seterror(EILSEQ);\r
-    }\r
-    else if (usedDefaultChar)\r
-        return seterror(EILSEQ);\r
-    else if (cv->mblen(cv, buf, len) != len) /* validate result */\r
-        return seterror(EILSEQ);\r
-    return len;\r
-}\r
-\r
-/*\r
- * It seems that the mode (cv->mode) is fixnum.\r
- * For example, when converting iso-2022-jp(cp50221) to unicode:\r
- *      in ascii sequence: mode=0xC42C0000\r
- *   in jisx0208 sequence: mode=0xC42C0001\r
- * "C42C" is same for each convert session.\r
- * It should be: ((codepage-1)<<16)|state\r
- */\r
-static int\r
-mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)\r
-{\r
-    int len;\r
-    int insize;\r
-    HRESULT hr;\r
-\r
-    len = cv->mblen(cv, buf, bufsize);\r
-    if (len == -1)\r
-        return -1;\r
-    insize = len;\r
-    hr = ConvertINetMultiByteToUnicode(&cv->mode, cv->codepage,\r
-            (const char *)buf, &insize, (wchar_t *)wbuf, wbufsize);\r
-    if (hr != S_OK || insize != len)\r
-        return seterror(EILSEQ);\r
-    return len;\r
-}\r
-\r
-static int\r
-mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)\r
-{\r
-    char tmpbuf[MB_CHAR_MAX]; /* enough room for one character */\r
-    int tmpsize = MB_CHAR_MAX;\r
-    int insize = wbufsize;\r
-    HRESULT hr;\r
-\r
-    hr = ConvertINetUnicodeToMultiByte(&cv->mode, cv->codepage,\r
-            (const wchar_t *)wbuf, &wbufsize, tmpbuf, &tmpsize);\r
-    if (hr != S_OK || insize != wbufsize)\r
-        return seterror(EILSEQ);\r
-    else if (bufsize < tmpsize)\r
-        return seterror(E2BIG);\r
-    else if (cv->mblen(cv, (uchar *)tmpbuf, tmpsize) != tmpsize)\r
-        return seterror(EILSEQ);\r
-    memcpy(buf, tmpbuf, tmpsize);\r
-    return tmpsize;\r
-}\r
-\r
-static int\r
-utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)\r
-{\r
-    int codepage = cv->codepage;\r
-\r
-    /* swap endian: 1200 <-> 1201 */\r
-    if (cv->mode & UNICODE_MODE_SWAPPED)\r
-        codepage ^= 1;\r
-\r
-    if (bufsize < 2)\r
-        return seterror(EINVAL);\r
-    if (codepage == 1200) /* little endian */\r
-        wbuf[0] = (buf[1] << 8) | buf[0];\r
-    else if (codepage == 1201) /* big endian */\r
-        wbuf[0] = (buf[0] << 8) | buf[1];\r
-\r
-    if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))\r
-    {\r
-        cv->mode |= UNICODE_MODE_BOM_DONE;\r
-        if (wbuf[0] == 0xFFFE)\r
-        {\r
-            cv->mode |= UNICODE_MODE_SWAPPED;\r
-            *wbufsize = 0;\r
-            return 2;\r
-        }\r
-        else if (wbuf[0] == 0xFEFF)\r
-        {\r
-            *wbufsize = 0;\r
-            return 2;\r
-        }\r
-    }\r
-\r
-    if (0xDC00 <= wbuf[0] && wbuf[0] <= 0xDFFF)\r
-        return seterror(EILSEQ);\r
-    if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)\r
-    {\r
-        if (bufsize < 4)\r
-            return seterror(EINVAL);\r
-        if (codepage == 1200) /* little endian */\r
-            wbuf[1] = (buf[3] << 8) | buf[2];\r
-        else if (codepage == 1201) /* big endian */\r
-            wbuf[1] = (buf[2] << 8) | buf[3];\r
-        if (!(0xDC00 <= wbuf[1] && wbuf[1] <= 0xDFFF))\r
-            return seterror(EILSEQ);\r
-        *wbufsize = 2;\r
-        return 4;\r
-    }\r
-    *wbufsize = 1;\r
-    return 2;\r
-}\r
-\r
-static int\r
-utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)\r
-{\r
-    if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))\r
-    {\r
-        int r;\r
-\r
-        cv->mode |= UNICODE_MODE_BOM_DONE;\r
-        if (bufsize < 2)\r
-            return seterror(E2BIG);\r
-        if (cv->codepage == 1200) /* little endian */\r
-            memcpy(buf, "\xFF\xFE", 2);\r
-        else if (cv->codepage == 1201) /* big endian */\r
-            memcpy(buf, "\xFE\xFF", 2);\r
-\r
-        r = utf16_wctomb(cv, wbuf, wbufsize, buf + 2, bufsize - 2);\r
-        if (r == -1)\r
-            return -1;\r
-        return r + 2;\r
-    }\r
-\r
-    if (bufsize < 2)\r
-        return seterror(E2BIG);\r
-    if (cv->codepage == 1200) /* little endian */\r
-    {\r
-        buf[0] = (wbuf[0] & 0x00FF);\r
-        buf[1] = (wbuf[0] & 0xFF00) >> 8;\r
-    }\r
-    else if (cv->codepage == 1201) /* big endian */\r
-    {\r
-        buf[0] = (wbuf[0] & 0xFF00) >> 8;\r
-        buf[1] = (wbuf[0] & 0x00FF);\r
-    }\r
-    if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)\r
-    {\r
-        if (bufsize < 4)\r
-            return seterror(E2BIG);\r
-        if (cv->codepage == 1200) /* little endian */\r
-        {\r
-            buf[2] = (wbuf[1] & 0x00FF);\r
-            buf[3] = (wbuf[1] & 0xFF00) >> 8;\r
-        }\r
-        else if (cv->codepage == 1201) /* big endian */\r
-        {\r
-            buf[2] = (wbuf[1] & 0xFF00) >> 8;\r
-            buf[3] = (wbuf[1] & 0x00FF);\r
-        }\r
-        return 4;\r
-    }\r
-    return 2;\r
-}\r
-\r
-static int\r
-utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)\r
-{\r
-    int codepage = cv->codepage;\r
-    uint wc;\r
-\r
-    /* swap endian: 12000 <-> 12001 */\r
-    if (cv->mode & UNICODE_MODE_SWAPPED)\r
-        codepage ^= 1;\r
-\r
-    if (bufsize < 4)\r
-        return seterror(EINVAL);\r
-    if (codepage == 12000) /* little endian */\r
-        wc = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];\r
-    else if (codepage == 12001) /* big endian */\r
-        wc = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];\r
-\r
-    if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))\r
-    {\r
-        cv->mode |= UNICODE_MODE_BOM_DONE;\r
-        if (wc == 0xFFFE0000)\r
-        {\r
-            cv->mode |= UNICODE_MODE_SWAPPED;\r
-            *wbufsize = 0;\r
-            return 4;\r
-        }\r
-        else if (wc == 0x0000FEFF)\r
-        {\r
-            *wbufsize = 0;\r
-            return 4;\r
-        }\r
-    }\r
-\r
-    if ((0xD800 <= wc && wc <= 0xDFFF) || 0x10FFFF < wc)\r
-        return seterror(EILSEQ);\r
-    ucs4_to_utf16(wc, wbuf, wbufsize);\r
-    return 4;\r
-}\r
-\r
-static int\r
-utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)\r
-{\r
-    uint wc;\r
-\r
-    if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))\r
-    {\r
-        int r;\r
-\r
-        cv->mode |= UNICODE_MODE_BOM_DONE;\r
-        if (bufsize < 4)\r
-            return seterror(E2BIG);\r
-        if (cv->codepage == 12000) /* little endian */\r
-            memcpy(buf, "\xFF\xFE\x00\x00", 4);\r
-        else if (cv->codepage == 12001) /* big endian */\r
-            memcpy(buf, "\x00\x00\xFE\xFF", 4);\r
-\r
-        r = utf32_wctomb(cv, wbuf, wbufsize, buf + 4, bufsize - 4);\r
-        if (r == -1)\r
-            return -1;\r
-        return r + 4;\r
-    }\r
-\r
-    if (bufsize < 4)\r
-        return seterror(E2BIG);\r
-    wc = utf16_to_ucs4(wbuf);\r
-    if (cv->codepage == 12000) /* little endian */\r
-    {\r
-        buf[0] = wc & 0x000000FF;\r
-        buf[1] = (wc & 0x0000FF00) >> 8;\r
-        buf[2] = (wc & 0x00FF0000) >> 16;\r
-        buf[3] = (wc & 0xFF000000) >> 24;\r
-    }\r
-    else if (cv->codepage == 12001) /* big endian */\r
-    {\r
-        buf[0] = (wc & 0xFF000000) >> 24;\r
-        buf[1] = (wc & 0x00FF0000) >> 16;\r
-        buf[2] = (wc & 0x0000FF00) >> 8;\r
-        buf[3] = wc & 0x000000FF;\r
-    }\r
-    return 4;\r
-}\r
-\r
-/*\r
- * 50220: ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS)\r
- * 50221: ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow\r
- *        1 byte Kana)\r
- * 50222: ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte\r
- *        Kana - SO/SI)\r
- *\r
- * MultiByteToWideChar() and WideCharToMultiByte() behave differently\r
- * depending on Windows version.  On XP, WideCharToMultiByte() doesn't\r
- * terminate result sequence with ascii escape.  But Vista does.\r
- * Use MLang instead.\r
- */\r
-\r
-#define ISO2022_MODE(cs, shift) (((cs) << 8) | (shift))\r
-#define ISO2022_MODE_CS(mode) (((mode) >> 8) & 0xFF)\r
-#define ISO2022_MODE_SHIFT(mode) ((mode) & 0xFF)\r
-\r
-#define ISO2022_SI  0\r
-#define ISO2022_SO  1\r
-\r
-/* shift in */\r
-static const char iso2022_SI_seq[] = "\x0F";\r
-/* shift out */\r
-static const char iso2022_SO_seq[] = "\x0E";\r
-\r
-typedef struct iso2022_esc_t iso2022_esc_t;\r
-struct iso2022_esc_t {\r
-    const char *esc;\r
-    int esc_len;\r
-    int len;\r
-    int cs;\r
-};\r
-\r
-#define ISO2022JP_CS_ASCII            0\r
-#define ISO2022JP_CS_JISX0201_ROMAN   1\r
-#define ISO2022JP_CS_JISX0201_KANA    2\r
-#define ISO2022JP_CS_JISX0208_1978    3\r
-#define ISO2022JP_CS_JISX0208_1983    4\r
-#define ISO2022JP_CS_JISX0212         5\r
-\r
-static iso2022_esc_t iso2022jp_esc[] = {\r
-    {"\x1B\x28\x42", 3, 1, ISO2022JP_CS_ASCII},\r
-    {"\x1B\x28\x4A", 3, 1, ISO2022JP_CS_JISX0201_ROMAN},\r
-    {"\x1B\x28\x49", 3, 1, ISO2022JP_CS_JISX0201_KANA},\r
-    {"\x1B\x24\x40", 3, 2, ISO2022JP_CS_JISX0208_1983}, /* unify 1978 with 1983 */\r
-    {"\x1B\x24\x42", 3, 2, ISO2022JP_CS_JISX0208_1983},\r
-    {"\x1B\x24\x28\x44", 4, 2, ISO2022JP_CS_JISX0212},\r
-    {NULL, 0, 0, 0}\r
-};\r
-\r
-static int\r
-iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)\r
-{\r
-    iso2022_esc_t *iesc = iso2022jp_esc;\r
-    char tmp[MB_CHAR_MAX];\r
-    int insize;\r
-    HRESULT hr;\r
-    DWORD dummy = 0;\r
-    int len;\r
-    int esc_len;\r
-    int cs;\r
-    int shift;\r
-    int i;\r
-\r
-    if (buf[0] == 0x1B)\r
-    {\r
-        for (i = 0; iesc[i].esc != NULL; ++i)\r
-        {\r
-            esc_len = iesc[i].esc_len;\r
-            if (bufsize < esc_len)\r
-            {\r
-                if (strncmp((char *)buf, iesc[i].esc, bufsize) == 0)\r
-                    return seterror(EINVAL);\r
-            }\r
-            else\r
-            {\r
-                if (strncmp((char *)buf, iesc[i].esc, esc_len) == 0)\r
-                {\r
-                    cv->mode = ISO2022_MODE(iesc[i].cs, ISO2022_SI);\r
-                    *wbufsize = 0;\r
-                    return esc_len;\r
-                }\r
-            }\r
-        }\r
-        /* not supported escape sequence */\r
-        return seterror(EILSEQ);\r
-    }\r
-    else if (buf[0] == iso2022_SO_seq[0])\r
-    {\r
-        cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SO);\r
-        *wbufsize = 0;\r
-        return 1;\r
-    }\r
-    else if (buf[0] == iso2022_SI_seq[0])\r
-    {\r
-        cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SI);\r
-        *wbufsize = 0;\r
-        return 1;\r
-    }\r
-\r
-    cs = ISO2022_MODE_CS(cv->mode);\r
-    shift = ISO2022_MODE_SHIFT(cv->mode);\r
-\r
-    /* reset the mode for informal sequence */\r
-    if (buf[0] < 0x20)\r
-    {\r
-        cs = ISO2022JP_CS_ASCII;\r
-        shift = ISO2022_SI;\r
-    }\r
-\r
-    len = iesc[cs].len;\r
-    if (bufsize < len)\r
-        return seterror(EINVAL);\r
-    for (i = 0; i < len; ++i)\r
-        if (!(buf[i] < 0x80))\r
-            return seterror(EILSEQ);\r
-    esc_len = iesc[cs].esc_len;\r
-    memcpy(tmp, iesc[cs].esc, esc_len);\r
-    if (shift == ISO2022_SO)\r
-    {\r
-        memcpy(tmp + esc_len, iso2022_SO_seq, 1);\r
-        esc_len += 1;\r
-    }\r
-    memcpy(tmp + esc_len, buf, len);\r
-\r
-    if ((cv->codepage == 50220 || cv->codepage == 50221\r
-                || cv->codepage == 50222) && shift == ISO2022_SO)\r
-    {\r
-        /* XXX: shift-out cannot be used for mbtowc (both kernel and\r
-         * mlang) */\r
-        esc_len = iesc[ISO2022JP_CS_JISX0201_KANA].esc_len;\r
-        memcpy(tmp, iesc[ISO2022JP_CS_JISX0201_KANA].esc, esc_len);\r
-        memcpy(tmp + esc_len, buf, len);\r
-    }\r
-\r
-    insize = len + esc_len;\r
-    hr = ConvertINetMultiByteToUnicode(&dummy, cv->codepage,\r
-            (const char *)tmp, &insize, (wchar_t *)wbuf, wbufsize);\r
-    if (hr != S_OK || insize != len + esc_len)\r
-        return seterror(EILSEQ);\r
-\r
-    /* Check for conversion error.  Assuming defaultChar is 0x3F. */\r
-    /* ascii should be converted from ascii */\r
-    if (wbuf[0] == buf[0]\r
-            && cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI))\r
-        return seterror(EILSEQ);\r
-\r
-    /* reset the mode for informal sequence */\r
-    if (cv->mode != ISO2022_MODE(cs, shift))\r
-        cv->mode = ISO2022_MODE(cs, shift);\r
-\r
-    return len;\r
-}\r
-\r
-static int\r
-iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)\r
-{\r
-    iso2022_esc_t *iesc = iso2022jp_esc;\r
-    char tmp[MB_CHAR_MAX];\r
-    int tmpsize = MB_CHAR_MAX;\r
-    int insize = wbufsize;\r
-    HRESULT hr;\r
-    DWORD dummy = 0;\r
-    int len;\r
-    int esc_len;\r
-    int cs;\r
-    int shift;\r
-    int i;\r
-\r
-    /*\r
-     * MultiByte = [escape sequence] + character + [escape sequence]\r
-     *\r
-     * Whether trailing escape sequence is added depends on which API is\r
-     * used (kernel or MLang, and its version).\r
-     */\r
-    hr = ConvertINetUnicodeToMultiByte(&dummy, cv->codepage,\r
-            (const wchar_t *)wbuf, &wbufsize, tmp, &tmpsize);\r
-    if (hr != S_OK || insize != wbufsize)\r
-        return seterror(EILSEQ);\r
-    else if (bufsize < tmpsize)\r
-        return seterror(E2BIG);\r
-\r
-    if (tmpsize == 1)\r
-    {\r
-        cs = ISO2022JP_CS_ASCII;\r
-        esc_len = 0;\r
-    }\r
-    else\r
-    {\r
-        for (i = 1; iesc[i].esc != NULL; ++i)\r
-        {\r
-            esc_len = iesc[i].esc_len;\r
-            if (strncmp(tmp, iesc[i].esc, esc_len) == 0)\r
-            {\r
-                cs = iesc[i].cs;\r
-                break;\r
-            }\r
-        }\r
-        if (iesc[i].esc == NULL)\r
-            /* not supported escape sequence */\r
-            return seterror(EILSEQ);\r
-    }\r
-\r
-    shift = ISO2022_SI;\r
-    if (tmp[esc_len] == iso2022_SO_seq[0])\r
-    {\r
-        shift = ISO2022_SO;\r
-        esc_len += 1;\r
-    }\r
-\r
-    len = iesc[cs].len;\r
-\r
-    /* Check for converting error.  Assuming defaultChar is 0x3F. */\r
-    /* ascii should be converted from ascii */\r
-    if (cs == ISO2022JP_CS_ASCII && !(wbuf[0] < 0x80))\r
-        return seterror(EILSEQ);\r
-    else if (tmpsize < esc_len + len)\r
-        return seterror(EILSEQ);\r
-\r
-    if (cv->mode == ISO2022_MODE(cs, shift))\r
-    {\r
-        /* remove escape sequence */\r
-        if (esc_len != 0)\r
-            memmove(tmp, tmp + esc_len, len);\r
-        esc_len = 0;\r
-    }\r
-    else\r
-    {\r
-        if (cs == ISO2022JP_CS_ASCII)\r
-        {\r
-            esc_len = iesc[ISO2022JP_CS_ASCII].esc_len;\r
-            memmove(tmp + esc_len, tmp, len);\r
-            memcpy(tmp, iesc[ISO2022JP_CS_ASCII].esc, esc_len);\r
-        }\r
-        if (ISO2022_MODE_SHIFT(cv->mode) == ISO2022_SO)\r
-        {\r
-            /* shift-in before changing to other mode */\r
-            memmove(tmp + 1, tmp, len + esc_len);\r
-            memcpy(tmp, iso2022_SI_seq, 1);\r
-            esc_len += 1;\r
-        }\r
-    }\r
-\r
-    if (bufsize < len + esc_len)\r
-        return seterror(E2BIG);\r
-    memcpy(buf, tmp, len + esc_len);\r
-    cv->mode = ISO2022_MODE(cs, shift);\r
-    return len + esc_len;\r
-}\r
-\r
-static int\r
-iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize)\r
-{\r
-    iso2022_esc_t *iesc = iso2022jp_esc;\r
-    int esc_len;\r
-\r
-    if (cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI))\r
-    {\r
-        esc_len = 0;\r
-        if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI)\r
-            esc_len += 1;\r
-        if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII)\r
-            esc_len += iesc[ISO2022JP_CS_ASCII].esc_len;\r
-        if (bufsize < esc_len)\r
-            return seterror(E2BIG);\r
-\r
-        esc_len = 0;\r
-        if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI)\r
-        {\r
-            memcpy(buf, iso2022_SI_seq, 1);\r
-            esc_len += 1;\r
-        }\r
-        if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII)\r
-        {\r
-            memcpy(buf + esc_len, iesc[ISO2022JP_CS_ASCII].esc,\r
-                    iesc[ISO2022JP_CS_ASCII].esc_len);\r
-            esc_len += iesc[ISO2022JP_CS_ASCII].esc_len;\r
-        }\r
-        return esc_len;\r
-    }\r
-    return 0;\r
-}\r
-\r
-#if defined(MAKE_DLL) && defined(USE_LIBICONV_DLL)\r
-BOOL WINAPI\r
-DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)\r
-{\r
-    switch( fdwReason )\r
-    {\r
-    case DLL_PROCESS_ATTACH:\r
-        hwiniconv = (HMODULE)hinstDLL;\r
-        break;\r
-    case DLL_THREAD_ATTACH:\r
-    case DLL_THREAD_DETACH:\r
-    case DLL_PROCESS_DETACH:\r
-        break;\r
-    }\r
-    return TRUE;\r
-}\r
-#endif\r
-\r
-#if defined(MAKE_EXE)\r
-#include <stdio.h>\r
-#include <fcntl.h>\r
-#include <io.h>\r
-int\r
-main(int argc, char **argv)\r
-{\r
-    char *fromcode = NULL;\r
-    char *tocode = NULL;\r
-    int i;\r
-    char inbuf[BUFSIZ];\r
-    char outbuf[BUFSIZ];\r
-    const char *pin;\r
-    char *pout;\r
-    size_t inbytesleft;\r
-    size_t outbytesleft;\r
-    size_t rest = 0;\r
-    iconv_t cd;\r
-    size_t r;\r
-    FILE *in = stdin;\r
-\r
-    _setmode(_fileno(stdin), _O_BINARY);\r
-    _setmode(_fileno(stdout), _O_BINARY);\r
-\r
-    for (i = 1; i < argc; ++i)\r
-    {\r
-        if (strcmp(argv[i], "-l") == 0)\r
-        {\r
-            for (i = 0; codepage_alias[i].name != NULL; ++i)\r
-                printf("%s\n", codepage_alias[i].name);\r
-            return 0;\r
-        }\r
-\r
-        if (strcmp(argv[i], "-f") == 0)\r
-            fromcode = argv[++i];\r
-        else if (strcmp(argv[i], "-t") == 0)\r
-            tocode = argv[++i];\r
-        else\r
-        {\r
-            in = fopen(argv[i], "rb");\r
-            if (in == NULL)\r
-            {\r
-                fprintf(stderr, "cannot open %s\n", argv[i]);\r
-                return 1;\r
-            }\r
-            break;\r
-        }\r
-    }\r
-\r
-    if (fromcode == NULL || tocode == NULL)\r
-    {\r
-        printf("usage: %s -f from-enc -t to-enc [file]\n", argv[0]);\r
-        return 0;\r
-    }\r
-\r
-    cd = iconv_open(tocode, fromcode);\r
-    if (cd == (iconv_t)(-1))\r
-    {\r
-        perror("iconv_open error");\r
-        return 1;\r
-    }\r
-\r
-    while ((inbytesleft = fread(inbuf + rest, 1, sizeof(inbuf) - rest, in)) != 0\r
-            || rest != 0)\r
-    {\r
-        inbytesleft += rest;\r
-        pin = inbuf;\r
-        pout = outbuf;\r
-        outbytesleft = sizeof(outbuf);\r
-        r = iconv(cd, &pin, &inbytesleft, &pout, &outbytesleft);\r
-        fwrite(outbuf, 1, sizeof(outbuf) - outbytesleft, stdout);\r
-        if (r == (size_t)(-1) && errno != E2BIG && (errno != EINVAL || feof(in)))\r
-        {\r
-            perror("conversion error");\r
-            return 1;\r
-        }\r
-        memmove(inbuf, pin, inbytesleft);\r
-        rest = inbytesleft;\r
-    }\r
-    pout = outbuf;\r
-    outbytesleft = sizeof(outbuf);\r
-    r = iconv(cd, NULL, NULL, &pout, &outbytesleft);\r
-    fwrite(outbuf, 1, sizeof(outbuf) - outbytesleft, stdout);\r
-    if (r == (size_t)(-1))\r
-    {\r
-        perror("conversion error");\r
-        return 1;\r
-    }\r
-\r
-    iconv_close(cd);\r
-\r
-    return 0;\r
-}\r
-#endif\r
-\r
+/*
+ * iconv library using Win32 API to conversion.
+ *
+ * This file is placed in the public domain.
+ *
+ * Last Change: 2009-07-06
+ *
+ * ENVIRONMENT VARIABLE:
+ *     WINICONV_LIBICONV_DLL
+ *         If $WINICONV_LIBICONV_DLL is set, win_iconv uses the DLL.  If
+ *         loading the DLL or iconv_open() failed, falls back to internal
+ *         conversion.  If a few DLL are specified as comma separated list,
+ *         the first loadable DLL is used.  The DLL should have iconv_open(),
+ *         iconv_close() and iconv().  Or libiconv_open(), libiconv_close()
+ *         and libiconv().
+ *         (only available when USE_LIBICONV_DLL is defined at compile time)
+ *
+ * Win32 API does not support strict encoding conversion for some
+ * codepage.  And MLang function drop or replace invalid bytes and does
+ * not return useful error status as iconv.  This implementation cannot
+ * be used for encoding validation purpose.
+ */
+
+/* for WC_NO_BEST_FIT_CHARS */
+#ifndef WINVER
+# define WINVER 0x0500
+#endif
+
+#include <windows.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#if 0
+# define MAKE_EXE
+# define MAKE_DLL
+# define USE_LIBICONV_DLL
+#endif
+
+#if !defined(DEFAULT_LIBICONV_DLL)
+# define DEFAULT_LIBICONV_DLL ""
+#endif
+
+#define MB_CHAR_MAX 16
+
+#define UNICODE_MODE_BOM_DONE   1
+#define UNICODE_MODE_SWAPPED    2
+
+#define FLAG_USE_BOM            1
+#define FLAG_TRANSLIT           2 /* //TRANSLIT */
+#define FLAG_IGNORE             4 /* //IGNORE (not implemented) */
+
+typedef unsigned char uchar;
+typedef unsigned short ushort;
+typedef unsigned int uint;
+
+typedef void* iconv_t;
+
+iconv_t iconv_open(const char *tocode, const char *fromcode);
+int iconv_close(iconv_t cd);
+size_t iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
+
+/* libiconv interface for vim */
+#if defined(MAKE_DLL)
+int
+iconvctl (iconv_t cd, int request, void* argument)
+{
+    /* not supported */
+    return 0;
+}
+#endif
+
+typedef struct compat_t compat_t;
+typedef struct csconv_t csconv_t;
+typedef struct rec_iconv_t rec_iconv_t;
+
+typedef iconv_t (*f_iconv_open)(const char *tocode, const char *fromcode);
+typedef int (*f_iconv_close)(iconv_t cd);
+typedef size_t (*f_iconv)(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
+typedef int* (*f_errno)(void);
+typedef int (*f_mbtowc)(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
+typedef int (*f_wctomb)(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
+typedef int (*f_mblen)(csconv_t *cv, const uchar *buf, int bufsize);
+typedef int (*f_flush)(csconv_t *cv, uchar *buf, int bufsize);
+
+#define COMPAT_IN   1
+#define COMPAT_OUT  2
+
+/* unicode mapping for compatibility with other conversion table. */
+struct compat_t {
+    uint in;
+    uint out;
+    uint flag;
+};
+
+struct csconv_t {
+    int codepage;
+    int flags;
+    f_mbtowc mbtowc;
+    f_wctomb wctomb;
+    f_mblen mblen;
+    f_flush flush;
+    DWORD mode;
+    compat_t *compat;
+};
+
+struct rec_iconv_t {
+    iconv_t cd;
+    f_iconv_close iconv_close;
+    f_iconv iconv;
+    f_errno _errno;
+    csconv_t from;
+    csconv_t to;
+#if defined(USE_LIBICONV_DLL)
+    HMODULE hlibiconv;
+#endif
+};
+
+static int win_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode);
+static int win_iconv_close(iconv_t cd);
+static size_t win_iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
+
+static int load_mlang();
+static int make_csconv(const char *name, csconv_t *cv);
+static int name_to_codepage(const char *name);
+static uint utf16_to_ucs4(const ushort *wbuf);
+static void ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize);
+static int mbtowc_flags(int codepage);
+static int must_use_null_useddefaultchar(int codepage);
+static char *strrstr(const char *str, const char *token);
+static char *xstrndup(const char *s, size_t n);
+static int seterror(int err);
+
+#if defined(USE_LIBICONV_DLL)
+static int libiconv_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode);
+static PVOID MyImageDirectoryEntryToData(LPVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size);
+static HMODULE find_imported_module_by_funcname(HMODULE hModule, const char *funcname);
+
+static HMODULE hwiniconv;
+#endif
+
+static int sbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);
+static int dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);
+static int mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);
+static int utf8_mblen(csconv_t *cv, const uchar *buf, int bufsize);
+static int eucjp_mblen(csconv_t *cv, const uchar *buf, int bufsize);
+
+static int kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
+static int kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
+static int mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
+static int mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
+static int utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
+static int utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
+static int utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
+static int utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
+static int iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
+static int iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
+static int iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize);
+
+static struct {
+    int codepage;
+    const char *name;
+} codepage_alias[] = {
+    {65001, "CP65001"},
+    {65001, "UTF8"},
+    {65001, "UTF-8"},
+
+    {1200, "CP1200"},
+    {1200, "UTF16LE"},
+    {1200, "UTF-16LE"},
+    {1200, "UCS-2LE"},
+
+    {1201, "CP1201"},
+    {1201, "UTF16BE"},
+    {1201, "UTF-16BE"},
+    {1201, "UCS-2BE"},
+    {1201, "unicodeFFFE"},
+
+    {12000, "CP12000"},
+    {12000, "UTF32LE"},
+    {12000, "UTF-32LE"},
+
+    {12001, "CP12001"},
+    {12001, "UTF32BE"},
+    {12001, "UTF-32BE"},
+
+#ifndef GLIB_COMPILATION
+    /*
+     * Default is big endian.
+     * See rfc2781 4.3 Interpreting text labelled as UTF-16.
+     */
+    {1201, "UTF16"},
+    {1201, "UTF-16"},
+    {12001, "UTF32"},
+    {12001, "UTF-32"},
+#else
+    /* Default is little endian, because the platform is */
+    {1200, "UTF16"},
+    {1200, "UTF-16"},
+    {1200, "UCS-2"},
+    {12000, "UTF32"},
+    {12000, "UTF-32"},
+#endif
+
+    /* copy from libiconv `iconv -l` */
+    /* !IsValidCodePage(367) */
+    {20127, "ANSI_X3.4-1968"},
+    {20127, "ANSI_X3.4-1986"},
+    {20127, "ASCII"},
+    {20127, "CP367"},
+    {20127, "IBM367"},
+    {20127, "ISO-IR-6"},
+    {20127, "ISO646-US"},
+    {20127, "ISO_646.IRV:1991"},
+    {20127, "US"},
+    {20127, "US-ASCII"},
+    {20127, "CSASCII"},
+
+    /* !IsValidCodePage(819) */
+    {1252, "CP819"},
+    {1252, "IBM819"},
+    {28591, "ISO-8859-1"},
+    {28591, "ISO-IR-100"},
+    {28591, "ISO8859-1"},
+    {28591, "ISO_8859-1"},
+    {28591, "ISO_8859-1:1987"},
+    {28591, "L1"},
+    {28591, "LATIN1"},
+    {28591, "CSISOLATIN1"},
+
+    {1250, "CP1250"},
+    {1250, "MS-EE"},
+    {1250, "WINDOWS-1250"},
+
+    {1251, "CP1251"},
+    {1251, "MS-CYRL"},
+    {1251, "WINDOWS-1251"},
+
+    {1252, "CP1252"},
+    {1252, "MS-ANSI"},
+    {1252, "WINDOWS-1252"},
+
+    {1253, "CP1253"},
+    {1253, "MS-GREEK"},
+    {1253, "WINDOWS-1253"},
+
+    {1254, "CP1254"},
+    {1254, "MS-TURK"},
+    {1254, "WINDOWS-1254"},
+
+    {1255, "CP1255"},
+    {1255, "MS-HEBR"},
+    {1255, "WINDOWS-1255"},
+
+    {1256, "CP1256"},
+    {1256, "MS-ARAB"},
+    {1256, "WINDOWS-1256"},
+
+    {1257, "CP1257"},
+    {1257, "WINBALTRIM"},
+    {1257, "WINDOWS-1257"},
+
+    {1258, "CP1258"},
+    {1258, "WINDOWS-1258"},
+
+    {850, "850"},
+    {850, "CP850"},
+    {850, "IBM850"},
+    {850, "CSPC850MULTILINGUAL"},
+
+    /* !IsValidCodePage(862) */
+    {862, "862"},
+    {862, "CP862"},
+    {862, "IBM862"},
+    {862, "CSPC862LATINHEBREW"},
+
+    {866, "866"},
+    {866, "CP866"},
+    {866, "IBM866"},
+    {866, "CSIBM866"},
+
+    /* !IsValidCodePage(154) */
+    {154, "CP154"},
+    {154, "CYRILLIC-ASIAN"},
+    {154, "PT154"},
+    {154, "PTCP154"},
+    {154, "CSPTCP154"},
+
+    /* !IsValidCodePage(1133) */
+    {1133, "CP1133"},
+    {1133, "IBM-CP1133"},
+
+    {874, "CP874"},
+    {874, "WINDOWS-874"},
+
+    /* !IsValidCodePage(51932) */
+    {51932, "CP51932"},
+    {51932, "MS51932"},
+    {51932, "WINDOWS-51932"},
+    {51932, "EUC-JP"},
+
+    {932, "CP932"},
+    {932, "MS932"},
+    {932, "SHIFFT_JIS"},
+    {932, "SHIFFT_JIS-MS"},
+    {932, "SJIS"},
+    {932, "SJIS-MS"},
+    {932, "SJIS-OPEN"},
+    {932, "SJIS-WIN"},
+    {932, "WINDOWS-31J"},
+    {932, "WINDOWS-932"},
+    {932, "CSWINDOWS31J"},
+
+    {50221, "CP50221"},
+    {50221, "ISO-2022-JP"},
+    {50221, "ISO-2022-JP-MS"},
+    {50221, "ISO2022-JP"},
+    {50221, "ISO2022-JP-MS"},
+    {50221, "MS50221"},
+    {50221, "WINDOWS-50221"},
+
+    {936, "CP936"},
+    {936, "GBK"},
+    {936, "MS936"},
+    {936, "WINDOWS-936"},
+
+    {950, "CP950"},
+    {950, "BIG5"},
+
+    {949, "CP949"},
+    {949, "UHC"},
+    {949, "EUC-KR"},
+
+    {1361, "CP1361"},
+    {1361, "JOHAB"},
+
+    {437, "437"},
+    {437, "CP437"},
+    {437, "IBM437"},
+    {437, "CSPC8CODEPAGE437"},
+
+    {737, "CP737"},
+
+    {775, "CP775"},
+    {775, "IBM775"},
+    {775, "CSPC775BALTIC"},
+
+    {852, "852"},
+    {852, "CP852"},
+    {852, "IBM852"},
+    {852, "CSPCP852"},
+
+    /* !IsValidCodePage(853) */
+    {853, "CP853"},
+
+    {855, "855"},
+    {855, "CP855"},
+    {855, "IBM855"},
+    {855, "CSIBM855"},
+
+    {857, "857"},
+    {857, "CP857"},
+    {857, "IBM857"},
+    {857, "CSIBM857"},
+
+    /* !IsValidCodePage(858) */
+    {858, "CP858"},
+
+    {860, "860"},
+    {860, "CP860"},
+    {860, "IBM860"},
+    {860, "CSIBM860"},
+
+    {861, "861"},
+    {861, "CP-IS"},
+    {861, "CP861"},
+    {861, "IBM861"},
+    {861, "CSIBM861"},
+
+    {863, "863"},
+    {863, "CP863"},
+    {863, "IBM863"},
+    {863, "CSIBM863"},
+
+    {864, "CP864"},
+    {864, "IBM864"},
+    {864, "CSIBM864"},
+
+    {865, "865"},
+    {865, "CP865"},
+    {865, "IBM865"},
+    {865, "CSIBM865"},
+
+    {869, "869"},
+    {869, "CP-GR"},
+    {869, "CP869"},
+    {869, "IBM869"},
+    {869, "CSIBM869"},
+
+    /* !IsValidCodePage(1152) */
+    {1125, "CP1125"},
+
+    /*
+     * Code Page Identifiers
+     * http://msdn2.microsoft.com/en-us/library/ms776446.aspx
+     */
+    {37, "IBM037"}, /* IBM EBCDIC US-Canada */
+    {437, "IBM437"}, /* OEM United States */
+    {500, "IBM500"}, /* IBM EBCDIC International */
+    {708, "ASMO-708"}, /* Arabic (ASMO 708) */
+    /* 709             Arabic (ASMO-449+, BCON V4) */
+    /* 710             Arabic - Transparent Arabic */
+    {720, "DOS-720"}, /* Arabic (Transparent ASMO); Arabic (DOS) */
+    {737, "ibm737"}, /* OEM Greek (formerly 437G); Greek (DOS) */
+    {775, "ibm775"}, /* OEM Baltic; Baltic (DOS) */
+    {850, "ibm850"}, /* OEM Multilingual Latin 1; Western European (DOS) */
+    {852, "ibm852"}, /* OEM Latin 2; Central European (DOS) */
+    {855, "IBM855"}, /* OEM Cyrillic (primarily Russian) */
+    {857, "ibm857"}, /* OEM Turkish; Turkish (DOS) */
+    {858, "IBM00858"}, /* OEM Multilingual Latin 1 + Euro symbol */
+    {860, "IBM860"}, /* OEM Portuguese; Portuguese (DOS) */
+    {861, "ibm861"}, /* OEM Icelandic; Icelandic (DOS) */
+    {862, "DOS-862"}, /* OEM Hebrew; Hebrew (DOS) */
+    {863, "IBM863"}, /* OEM French Canadian; French Canadian (DOS) */
+    {864, "IBM864"}, /* OEM Arabic; Arabic (864) */
+    {865, "IBM865"}, /* OEM Nordic; Nordic (DOS) */
+    {866, "cp866"}, /* OEM Russian; Cyrillic (DOS) */
+    {869, "ibm869"}, /* OEM Modern Greek; Greek, Modern (DOS) */
+    {870, "IBM870"}, /* IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2 */
+    {874, "windows-874"}, /* ANSI/OEM Thai (same as 28605, ISO 8859-15); Thai (Windows) */
+    {875, "cp875"}, /* IBM EBCDIC Greek Modern */
+    {932, "shift_jis"}, /* ANSI/OEM Japanese; Japanese (Shift-JIS) */
+    {932, "shift-jis"}, /* alternative name for it */
+    {936, "gb2312"}, /* ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312) */
+    {949, "ks_c_5601-1987"}, /* ANSI/OEM Korean (Unified Hangul Code) */
+    {950, "big5"}, /* ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5) */
+    {1026, "IBM1026"}, /* IBM EBCDIC Turkish (Latin 5) */
+    {1047, "IBM01047"}, /* IBM EBCDIC Latin 1/Open System */
+    {1140, "IBM01140"}, /* IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro) */
+    {1141, "IBM01141"}, /* IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro) */
+    {1142, "IBM01142"}, /* IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro) */
+    {1143, "IBM01143"}, /* IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro) */
+    {1144, "IBM01144"}, /* IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro) */
+    {1145, "IBM01145"}, /* IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro) */
+    {1146, "IBM01146"}, /* IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro) */
+    {1147, "IBM01147"}, /* IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro) */
+    {1148, "IBM01148"}, /* IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro) */
+    {1149, "IBM01149"}, /* IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro) */
+    {1250, "windows-1250"}, /* ANSI Central European; Central European (Windows) */
+    {1251, "windows-1251"}, /* ANSI Cyrillic; Cyrillic (Windows) */
+    {1252, "windows-1252"}, /* ANSI Latin 1; Western European (Windows) */
+    {1253, "windows-1253"}, /* ANSI Greek; Greek (Windows) */
+    {1254, "windows-1254"}, /* ANSI Turkish; Turkish (Windows) */
+    {1255, "windows-1255"}, /* ANSI Hebrew; Hebrew (Windows) */
+    {1256, "windows-1256"}, /* ANSI Arabic; Arabic (Windows) */
+    {1257, "windows-1257"}, /* ANSI Baltic; Baltic (Windows) */
+    {1258, "windows-1258"}, /* ANSI/OEM Vietnamese; Vietnamese (Windows) */
+    {1361, "Johab"}, /* Korean (Johab) */
+    {10000, "macintosh"}, /* MAC Roman; Western European (Mac) */
+    {10001, "x-mac-japanese"}, /* Japanese (Mac) */
+    {10002, "x-mac-chinesetrad"}, /* MAC Traditional Chinese (Big5); Chinese Traditional (Mac) */
+    {10003, "x-mac-korean"}, /* Korean (Mac) */
+    {10004, "x-mac-arabic"}, /* Arabic (Mac) */
+    {10005, "x-mac-hebrew"}, /* Hebrew (Mac) */
+    {10006, "x-mac-greek"}, /* Greek (Mac) */
+    {10007, "x-mac-cyrillic"}, /* Cyrillic (Mac) */
+    {10008, "x-mac-chinesesimp"}, /* MAC Simplified Chinese (GB 2312); Chinese Simplified (Mac) */
+    {10010, "x-mac-romanian"}, /* Romanian (Mac) */
+    {10017, "x-mac-ukrainian"}, /* Ukrainian (Mac) */
+    {10021, "x-mac-thai"}, /* Thai (Mac) */
+    {10029, "x-mac-ce"}, /* MAC Latin 2; Central European (Mac) */
+    {10079, "x-mac-icelandic"}, /* Icelandic (Mac) */
+    {10081, "x-mac-turkish"}, /* Turkish (Mac) */
+    {10082, "x-mac-croatian"}, /* Croatian (Mac) */
+    {20000, "x-Chinese_CNS"}, /* CNS Taiwan; Chinese Traditional (CNS) */
+    {20001, "x-cp20001"}, /* TCA Taiwan */
+    {20002, "x_Chinese-Eten"}, /* Eten Taiwan; Chinese Traditional (Eten) */
+    {20003, "x-cp20003"}, /* IBM5550 Taiwan */
+    {20004, "x-cp20004"}, /* TeleText Taiwan */
+    {20005, "x-cp20005"}, /* Wang Taiwan */
+    {20105, "x-IA5"}, /* IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5) */
+    {20106, "x-IA5-German"}, /* IA5 German (7-bit) */
+    {20107, "x-IA5-Swedish"}, /* IA5 Swedish (7-bit) */
+    {20108, "x-IA5-Norwegian"}, /* IA5 Norwegian (7-bit) */
+    {20127, "us-ascii"}, /* US-ASCII (7-bit) */
+    {20261, "x-cp20261"}, /* T.61 */
+    {20269, "x-cp20269"}, /* ISO 6937 Non-Spacing Accent */
+    {20273, "IBM273"}, /* IBM EBCDIC Germany */
+    {20277, "IBM277"}, /* IBM EBCDIC Denmark-Norway */
+    {20278, "IBM278"}, /* IBM EBCDIC Finland-Sweden */
+    {20280, "IBM280"}, /* IBM EBCDIC Italy */
+    {20284, "IBM284"}, /* IBM EBCDIC Latin America-Spain */
+    {20285, "IBM285"}, /* IBM EBCDIC United Kingdom */
+    {20290, "IBM290"}, /* IBM EBCDIC Japanese Katakana Extended */
+    {20297, "IBM297"}, /* IBM EBCDIC France */
+    {20420, "IBM420"}, /* IBM EBCDIC Arabic */
+    {20423, "IBM423"}, /* IBM EBCDIC Greek */
+    {20424, "IBM424"}, /* IBM EBCDIC Hebrew */
+    {20833, "x-EBCDIC-KoreanExtended"}, /* IBM EBCDIC Korean Extended */
+    {20838, "IBM-Thai"}, /* IBM EBCDIC Thai */
+    {20866, "koi8-r"}, /* Russian (KOI8-R); Cyrillic (KOI8-R) */
+    {20871, "IBM871"}, /* IBM EBCDIC Icelandic */
+    {20880, "IBM880"}, /* IBM EBCDIC Cyrillic Russian */
+    {20905, "IBM905"}, /* IBM EBCDIC Turkish */
+    {20924, "IBM00924"}, /* IBM EBCDIC Latin 1/Open System (1047 + Euro symbol) */
+    {20932, "EUC-JP"}, /* Japanese (JIS 0208-1990 and 0121-1990) */
+    {20936, "x-cp20936"}, /* Simplified Chinese (GB2312); Chinese Simplified (GB2312-80) */
+    {20949, "x-cp20949"}, /* Korean Wansung */
+    {21025, "cp1025"}, /* IBM EBCDIC Cyrillic Serbian-Bulgarian */
+    /* 21027           (deprecated) */
+    {21866, "koi8-u"}, /* Ukrainian (KOI8-U); Cyrillic (KOI8-U) */
+    {28591, "iso-8859-1"}, /* ISO 8859-1 Latin 1; Western European (ISO) */
+    {28591, "iso8859-1"}, /* ISO 8859-1 Latin 1; Western European (ISO) */
+    {28592, "iso-8859-2"}, /* ISO 8859-2 Central European; Central European (ISO) */
+    {28592, "iso8859-2"}, /* ISO 8859-2 Central European; Central European (ISO) */
+    {28593, "iso-8859-3"}, /* ISO 8859-3 Latin 3 */
+    {28593, "iso8859-3"}, /* ISO 8859-3 Latin 3 */
+    {28594, "iso-8859-4"}, /* ISO 8859-4 Baltic */
+    {28594, "iso8859-4"}, /* ISO 8859-4 Baltic */
+    {28595, "iso-8859-5"}, /* ISO 8859-5 Cyrillic */
+    {28595, "iso8859-5"}, /* ISO 8859-5 Cyrillic */
+    {28596, "iso-8859-6"}, /* ISO 8859-6 Arabic */
+    {28596, "iso8859-6"}, /* ISO 8859-6 Arabic */
+    {28597, "iso-8859-7"}, /* ISO 8859-7 Greek */
+    {28597, "iso8859-7"}, /* ISO 8859-7 Greek */
+    {28598, "iso-8859-8"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */
+    {28598, "iso8859-8"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */
+    {28599, "iso-8859-9"}, /* ISO 8859-9 Turkish */
+    {28599, "iso8859-9"}, /* ISO 8859-9 Turkish */
+    {28603, "iso-8859-13"}, /* ISO 8859-13 Estonian */
+    {28603, "iso8859-13"}, /* ISO 8859-13 Estonian */
+    {28605, "iso-8859-15"}, /* ISO 8859-15 Latin 9 */
+    {28605, "iso8859-15"}, /* ISO 8859-15 Latin 9 */
+    {29001, "x-Europa"}, /* Europa 3 */
+    {38598, "iso-8859-8-i"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */
+    {38598, "iso8859-8-i"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */
+    {50220, "iso-2022-jp"}, /* ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS) */
+    {50221, "csISO2022JP"}, /* ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana) */
+    {50222, "iso-2022-jp"}, /* ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI) */
+    {50225, "iso-2022-kr"}, /* ISO 2022 Korean */
+    {50225, "iso2022-kr"}, /* ISO 2022 Korean */
+    {50227, "x-cp50227"}, /* ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022) */
+    /* 50229           ISO 2022 Traditional Chinese */
+    /* 50930           EBCDIC Japanese (Katakana) Extended */
+    /* 50931           EBCDIC US-Canada and Japanese */
+    /* 50933           EBCDIC Korean Extended and Korean */
+    /* 50935           EBCDIC Simplified Chinese Extended and Simplified Chinese */
+    /* 50936           EBCDIC Simplified Chinese */
+    /* 50937           EBCDIC US-Canada and Traditional Chinese */
+    /* 50939           EBCDIC Japanese (Latin) Extended and Japanese */
+    {51932, "euc-jp"}, /* EUC Japanese */
+    {51936, "EUC-CN"}, /* EUC Simplified Chinese; Chinese Simplified (EUC) */
+    {51949, "euc-kr"}, /* EUC Korean */
+    /* 51950           EUC Traditional Chinese */
+    {52936, "hz-gb-2312"}, /* HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ) */
+    {54936, "GB18030"}, /* Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030) */
+    {57002, "x-iscii-de"}, /* ISCII Devanagari */
+    {57003, "x-iscii-be"}, /* ISCII Bengali */
+    {57004, "x-iscii-ta"}, /* ISCII Tamil */
+    {57005, "x-iscii-te"}, /* ISCII Telugu */
+    {57006, "x-iscii-as"}, /* ISCII Assamese */
+    {57007, "x-iscii-or"}, /* ISCII Oriya */
+    {57008, "x-iscii-ka"}, /* ISCII Kannada */
+    {57009, "x-iscii-ma"}, /* ISCII Malayalam */
+    {57010, "x-iscii-gu"}, /* ISCII Gujarati */
+    {57011, "x-iscii-pa"}, /* ISCII Punjabi */
+
+    {0, NULL}
+};
+
+/*
+ * SJIS SHIFTJIS table              CP932 table
+ * ---- --------------------------- --------------------------------
+ *   5C U+00A5 YEN SIGN             U+005C REVERSE SOLIDUS
+ *   7E U+203E OVERLINE             U+007E TILDE
+ * 815C U+2014 EM DASH              U+2015 HORIZONTAL BAR
+ * 815F U+005C REVERSE SOLIDUS      U+FF3C FULLWIDTH REVERSE SOLIDUS
+ * 8160 U+301C WAVE DASH            U+FF5E FULLWIDTH TILDE
+ * 8161 U+2016 DOUBLE VERTICAL LINE U+2225 PARALLEL TO
+ * 817C U+2212 MINUS SIGN           U+FF0D FULLWIDTH HYPHEN-MINUS
+ * 8191 U+00A2 CENT SIGN            U+FFE0 FULLWIDTH CENT SIGN
+ * 8192 U+00A3 POUND SIGN           U+FFE1 FULLWIDTH POUND SIGN
+ * 81CA U+00AC NOT SIGN             U+FFE2 FULLWIDTH NOT SIGN
+ *
+ * EUC-JP and ISO-2022-JP should be compatible with CP932.
+ *
+ * Kernel and MLang have different Unicode mapping table.  Make sure
+ * which API is used.
+ */
+static compat_t cp932_compat[] = {
+    {0x00A5, 0x005C, COMPAT_OUT},
+    {0x203E, 0x007E, COMPAT_OUT},
+    {0x2014, 0x2015, COMPAT_OUT},
+    {0x301C, 0xFF5E, COMPAT_OUT},
+    {0x2016, 0x2225, COMPAT_OUT},
+    {0x2212, 0xFF0D, COMPAT_OUT},
+    {0x00A2, 0xFFE0, COMPAT_OUT},
+    {0x00A3, 0xFFE1, COMPAT_OUT},
+    {0x00AC, 0xFFE2, COMPAT_OUT},
+    {0, 0, 0}
+};
+
+static compat_t cp20932_compat[] = {
+    {0x00A5, 0x005C, COMPAT_OUT},
+    {0x203E, 0x007E, COMPAT_OUT},
+    {0x2014, 0x2015, COMPAT_OUT},
+    {0xFF5E, 0x301C, COMPAT_OUT|COMPAT_IN},
+    {0x2225, 0x2016, COMPAT_OUT|COMPAT_IN},
+    {0xFF0D, 0x2212, COMPAT_OUT|COMPAT_IN},
+    {0xFFE0, 0x00A2, COMPAT_OUT|COMPAT_IN},
+    {0xFFE1, 0x00A3, COMPAT_OUT|COMPAT_IN},
+    {0xFFE2, 0x00AC, COMPAT_OUT|COMPAT_IN},
+    {0, 0, 0}
+};
+
+static compat_t *cp51932_compat = cp932_compat;
+
+/* cp20932_compat for kernel.  cp932_compat for mlang. */
+static compat_t *cp5022x_compat = cp932_compat;
+
+typedef HRESULT (WINAPI *CONVERTINETSTRING)(
+    LPDWORD lpdwMode,
+    DWORD dwSrcEncoding,
+    DWORD dwDstEncoding,
+    LPCSTR lpSrcStr,
+    LPINT lpnSrcSize,
+    LPBYTE lpDstStr,
+    LPINT lpnDstSize
+);
+typedef HRESULT (WINAPI *CONVERTINETMULTIBYTETOUNICODE)(
+    LPDWORD lpdwMode,
+    DWORD dwSrcEncoding,
+    LPCSTR lpSrcStr,
+    LPINT lpnMultiCharCount,
+    LPWSTR lpDstStr,
+    LPINT lpnWideCharCount
+);
+typedef HRESULT (WINAPI *CONVERTINETUNICODETOMULTIBYTE)(
+    LPDWORD lpdwMode,
+    DWORD dwEncoding,
+    LPCWSTR lpSrcStr,
+    LPINT lpnWideCharCount,
+    LPSTR lpDstStr,
+    LPINT lpnMultiCharCount
+);
+typedef HRESULT (WINAPI *ISCONVERTINETSTRINGAVAILABLE)(
+    DWORD dwSrcEncoding,
+    DWORD dwDstEncoding
+);
+typedef HRESULT (WINAPI *LCIDTORFC1766A)(
+    LCID Locale,
+    LPSTR pszRfc1766,
+    int nChar
+);
+typedef HRESULT (WINAPI *LCIDTORFC1766W)(
+    LCID Locale,
+    LPWSTR pszRfc1766,
+    int nChar
+);
+typedef HRESULT (WINAPI *RFC1766TOLCIDA)(
+    LCID *pLocale,
+    LPSTR pszRfc1766
+);
+typedef HRESULT (WINAPI *RFC1766TOLCIDW)(
+    LCID *pLocale,
+    LPWSTR pszRfc1766
+);
+static CONVERTINETSTRING ConvertINetString;
+static CONVERTINETMULTIBYTETOUNICODE ConvertINetMultiByteToUnicode;
+static CONVERTINETUNICODETOMULTIBYTE ConvertINetUnicodeToMultiByte;
+static ISCONVERTINETSTRINGAVAILABLE IsConvertINetStringAvailable;
+static LCIDTORFC1766A LcidToRfc1766A;
+static RFC1766TOLCIDA Rfc1766ToLcidA;
+
+static int
+load_mlang()
+{
+    HMODULE h;
+    if (ConvertINetString != NULL)
+        return TRUE;
+    h = LoadLibrary("mlang.dll");
+    if (!h)
+        return FALSE;
+    ConvertINetString = (CONVERTINETSTRING)GetProcAddress(h, "ConvertINetString");
+    ConvertINetMultiByteToUnicode = (CONVERTINETMULTIBYTETOUNICODE)GetProcAddress(h, "ConvertINetMultiByteToUnicode");
+    ConvertINetUnicodeToMultiByte = (CONVERTINETUNICODETOMULTIBYTE)GetProcAddress(h, "ConvertINetUnicodeToMultiByte");
+    IsConvertINetStringAvailable = (ISCONVERTINETSTRINGAVAILABLE)GetProcAddress(h, "IsConvertINetStringAvailable");
+    LcidToRfc1766A = (LCIDTORFC1766A)GetProcAddress(h, "LcidToRfc1766A");
+    Rfc1766ToLcidA = (RFC1766TOLCIDA)GetProcAddress(h, "Rfc1766ToLcidA");
+    return TRUE;
+}
+
+iconv_t
+iconv_open(const char *tocode, const char *fromcode)
+{
+    rec_iconv_t *cd;
+
+    cd = (rec_iconv_t *)calloc(1, sizeof(rec_iconv_t));
+    if (cd == NULL)
+        return (iconv_t)(-1);
+
+#if defined(USE_LIBICONV_DLL)
+    errno = 0;
+    if (libiconv_iconv_open(cd, tocode, fromcode))
+        return (iconv_t)cd;
+#endif
+
+    /* reset the errno to prevent reporting wrong error code.
+     * 0 for unsorted error. */
+    errno = 0;
+    if (win_iconv_open(cd, tocode, fromcode))
+        return (iconv_t)cd;
+
+    free(cd);
+
+    return (iconv_t)(-1);
+}
+
+int
+iconv_close(iconv_t _cd)
+{
+    rec_iconv_t *cd = (rec_iconv_t *)_cd;
+    int r = cd->iconv_close(cd->cd);
+    int e = *(cd->_errno());
+#if defined(USE_LIBICONV_DLL)
+    if (cd->hlibiconv != NULL)
+        FreeLibrary(cd->hlibiconv);
+#endif
+    free(cd);
+    errno = e;
+    return r;
+}
+
+size_t
+iconv(iconv_t _cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
+{
+    rec_iconv_t *cd = (rec_iconv_t *)_cd;
+    size_t r = cd->iconv(cd->cd, inbuf, inbytesleft, outbuf, outbytesleft);
+    errno = *(cd->_errno());
+    return r;
+}
+
+static int
+win_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode)
+{
+    if (!make_csconv(fromcode, &cd->from) || !make_csconv(tocode, &cd->to))
+        return FALSE;
+    cd->iconv_close = win_iconv_close;
+    cd->iconv = win_iconv;
+    cd->_errno = _errno;
+    cd->cd = (iconv_t)cd;
+    return TRUE;
+}
+
+static int
+win_iconv_close(iconv_t cd)
+{
+    return 0;
+}
+
+static size_t
+win_iconv(iconv_t _cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
+{
+    rec_iconv_t *cd = (rec_iconv_t *)_cd;
+    ushort wbuf[MB_CHAR_MAX]; /* enough room for one character */
+    int insize;
+    int outsize;
+    int wsize;
+    DWORD frommode;
+    DWORD tomode;
+    uint wc;
+    compat_t *cp;
+    int i;
+
+    if (inbuf == NULL || *inbuf == NULL)
+    {
+        if (outbuf != NULL && *outbuf != NULL && cd->to.flush != NULL)
+        {
+            tomode = cd->to.mode;
+            outsize = cd->to.flush(&cd->to, (uchar *)*outbuf, *outbytesleft);
+            if (outsize == -1)
+            {
+                cd->to.mode = tomode;
+                return (size_t)(-1);
+            }
+            *outbuf += outsize;
+            *outbytesleft -= outsize;
+        }
+        cd->from.mode = 0;
+        cd->to.mode = 0;
+        return 0;
+    }
+
+    while (*inbytesleft != 0)
+    {
+        frommode = cd->from.mode;
+        tomode = cd->to.mode;
+        wsize = MB_CHAR_MAX;
+
+        insize = cd->from.mbtowc(&cd->from, (const uchar *)*inbuf, *inbytesleft, wbuf, &wsize);
+        if (insize == -1)
+        {
+            cd->from.mode = frommode;
+            return (size_t)(-1);
+        }
+
+        if (wsize == 0)
+        {
+            *inbuf += insize;
+            *inbytesleft -= insize;
+            continue;
+        }
+
+        if (cd->from.compat != NULL)
+        {
+            wc = utf16_to_ucs4(wbuf);
+            cp = cd->from.compat;
+            for (i = 0; cp[i].in != 0; ++i)
+            {
+                if ((cp[i].flag & COMPAT_IN) && cp[i].out == wc)
+                {
+                    ucs4_to_utf16(cp[i].in, wbuf, &wsize);
+                    break;
+                }
+            }
+        }
+
+        if (cd->to.compat != NULL)
+        {
+            wc = utf16_to_ucs4(wbuf);
+            cp = cd->to.compat;
+            for (i = 0; cp[i].in != 0; ++i)
+            {
+                if ((cp[i].flag & COMPAT_OUT) && cp[i].in == wc)
+                {
+                    ucs4_to_utf16(cp[i].out, wbuf, &wsize);
+                    break;
+                }
+            }
+        }
+
+        outsize = cd->to.wctomb(&cd->to, wbuf, wsize, (uchar *)*outbuf, *outbytesleft);
+        if (outsize == -1)
+        {
+            cd->from.mode = frommode;
+            cd->to.mode = tomode;
+            return (size_t)(-1);
+        }
+
+        *inbuf += insize;
+        *outbuf += outsize;
+        *inbytesleft -= insize;
+        *outbytesleft -= outsize;
+    }
+
+    return 0;
+}
+
+static int
+make_csconv(const char *_name, csconv_t *cv)
+{
+    CPINFOEX cpinfoex;
+    int use_compat = TRUE;
+    int flag = 0;
+    char *name;
+    char *p;
+
+    name = xstrndup(_name, strlen(_name));
+    if (name == NULL)
+        return FALSE;
+
+    /* check for option "enc_name//opt1//opt2" */
+    while ((p = strrstr(name, "//")) != NULL)
+    {
+        if (_stricmp(p + 2, "nocompat") == 0)
+            use_compat = FALSE;
+        else if (_stricmp(p + 2, "translit") == 0)
+            flag |= FLAG_TRANSLIT;
+        else if (_stricmp(p + 2, "ignore") == 0)
+            flag |= FLAG_IGNORE;
+        *p = 0;
+    }
+
+    cv->mode = 0;
+    cv->flags = flag;
+    cv->mblen = NULL;
+    cv->flush = NULL;
+    cv->compat = NULL;
+    cv->codepage = name_to_codepage(name);
+    if (cv->codepage == 1200 || cv->codepage == 1201)
+    {
+        cv->mbtowc = utf16_mbtowc;
+        cv->wctomb = utf16_wctomb;
+        if (_stricmp(name, "UTF-16") == 0 || _stricmp(name, "UTF16") == 0)
+            cv->flags |= FLAG_USE_BOM;
+    }
+    else if (cv->codepage == 12000 || cv->codepage == 12001)
+    {
+        cv->mbtowc = utf32_mbtowc;
+        cv->wctomb = utf32_wctomb;
+        if (_stricmp(name, "UTF-32") == 0 || _stricmp(name, "UTF32") == 0)
+            cv->flags |= FLAG_USE_BOM;
+    }
+    else if (cv->codepage == 65001)
+    {
+        cv->mbtowc = kernel_mbtowc;
+        cv->wctomb = kernel_wctomb;
+        cv->mblen = utf8_mblen;
+    }
+    else if ((cv->codepage == 50220 || cv->codepage == 50221 || cv->codepage == 50222) && load_mlang())
+    {
+        cv->mbtowc = iso2022jp_mbtowc;
+        cv->wctomb = iso2022jp_wctomb;
+        cv->flush = iso2022jp_flush;
+    }
+    else if (cv->codepage == 51932 && load_mlang())
+    {
+        cv->mbtowc = mlang_mbtowc;
+        cv->wctomb = mlang_wctomb;
+        cv->mblen = eucjp_mblen;
+    }
+    else if (IsValidCodePage(cv->codepage)
+            && GetCPInfoEx(cv->codepage, 0, &cpinfoex) != 0)
+    {
+        cv->mbtowc = kernel_mbtowc;
+        cv->wctomb = kernel_wctomb;
+        if (cpinfoex.MaxCharSize == 1)
+            cv->mblen = sbcs_mblen;
+        else if (cpinfoex.MaxCharSize == 2)
+            cv->mblen = dbcs_mblen;
+       else
+           cv->mblen = mbcs_mblen;
+    }
+    else
+    {
+        /* not supported */
+        free(name);
+        errno = EINVAL;
+        return FALSE;
+    }
+
+    if (use_compat)
+    {
+        switch (cv->codepage)
+        {
+        case 932: cv->compat = cp932_compat; break;
+        case 20932: cv->compat = cp20932_compat; break;
+        case 51932: cv->compat = cp51932_compat; break;
+        case 50220: case 50221: case 50222: cv->compat = cp5022x_compat; break;
+        }
+    }
+
+    free(name);
+
+    return TRUE;
+}
+
+static int
+name_to_codepage(const char *name)
+{
+    int i;
+
+    if (*name == '\0' ||
+       strcmp(name, "char") == 0)
+        return GetACP();
+    else if (strcmp(name, "wchar_t") == 0)
+        return 1200;
+    else if (_strnicmp(name, "cp", 2) == 0)
+        return atoi(name + 2); /* CP123 */
+    else if ('0' <= name[0] && name[0] <= '9')
+        return atoi(name);     /* 123 */
+    else if (_strnicmp(name, "xx", 2) == 0)
+        return atoi(name + 2); /* XX123 for debug */
+
+    for (i = 0; codepage_alias[i].name != NULL; ++i)
+        if (_stricmp(name, codepage_alias[i].name) == 0)
+            return codepage_alias[i].codepage;
+    return -1;
+}
+
+/*
+ * http://www.faqs.org/rfcs/rfc2781.html
+ */
+static uint
+utf16_to_ucs4(const ushort *wbuf)
+{
+    uint wc = wbuf[0];
+    if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)
+        wc = ((wbuf[0] & 0x3FF) << 10) + (wbuf[1] & 0x3FF) + 0x10000;
+    return wc;
+}
+
+static void
+ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize)
+{
+    if (wc < 0x10000)
+    {
+        wbuf[0] = wc;
+        *wbufsize = 1;
+    }
+    else
+    {
+        wc -= 0x10000;
+        wbuf[0] = 0xD800 | ((wc >> 10) & 0x3FF);
+        wbuf[1] = 0xDC00 | (wc & 0x3FF);
+        *wbufsize = 2;
+    }
+}
+
+/*
+ * Check if codepage is one of those for which the dwFlags parameter
+ * to MultiByteToWideChar() must be zero. Return zero or
+ * MB_ERR_INVALID_CHARS.  The docs in Platform SDK for for Windows
+ * Server 2003 R2 claims that also codepage 65001 is one of these, but
+ * that doesn't seem to be the case. The MSDN docs for MSVS2008 leave
+ * out 65001 (UTF-8), and that indeed seems to be the case on XP, it
+ * works fine to pass MB_ERR_INVALID_CHARS in dwFlags when converting
+ * from UTF-8.
+ */
+static int
+mbtowc_flags(int codepage)
+{
+    return (codepage == 50220 || codepage == 50221 ||
+           codepage == 50222 || codepage == 50225 ||
+           codepage == 50227 || codepage == 50229 ||
+           codepage == 52936 || codepage == 54936 ||
+           (codepage >= 57002 && codepage <= 57011) ||
+           codepage == 65000 || codepage == 42) ? 0 : MB_ERR_INVALID_CHARS;
+}
+
+/*
+ * Check if codepage is one those for which the lpUsedDefaultChar
+ * parameter to WideCharToMultiByte() must be NULL.  The docs in
+ * Platform SDK for for Windows Server 2003 R2 claims that this is the
+ * list below, while the MSDN docs for MSVS2008 claim that it is only
+ * for 65000 (UTF-7) and 65001 (UTF-8). This time the earlier Platform
+ * SDK seems to be correct, at least for XP.
+ */
+static int
+must_use_null_useddefaultchar(int codepage)
+{
+    return (codepage == 65000 || codepage == 65001 ||
+            codepage == 50220 || codepage == 50221 ||
+            codepage == 50222 || codepage == 50225 ||
+            codepage == 50227 || codepage == 50229 ||
+            codepage == 52936 || codepage == 54936 ||
+            (codepage >= 57002 && codepage <= 57011) ||
+            codepage == 42);
+}
+
+static char *
+strrstr(const char *str, const char *token)
+{
+    int len = strlen(token);
+    const char *p = str + strlen(str);
+
+    while (str <= --p)
+        if (p[0] == token[0] && strncmp(p, token, len) == 0)
+            return (char *)p;
+    return NULL;
+}
+
+static char *
+xstrndup(const char *s, size_t n)
+{
+    char *p;
+
+    p = (char *)malloc(n + 1);
+    if (p == NULL)
+        return NULL;
+    memcpy(p, s, n);
+    p[n] = '\0';
+    return p;
+}
+
+static int
+seterror(int err)
+{
+    errno = err;
+    return -1;
+}
+
+#if defined(USE_LIBICONV_DLL)
+static int
+libiconv_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode)
+{
+    HMODULE hlibiconv = NULL;
+    HMODULE hmsvcrt = NULL;
+    char *dllname;
+    const char *p;
+    const char *e;
+    f_iconv_open _iconv_open;
+
+    /*
+     * always try to load dll, so that we can switch dll in runtime.
+     */
+
+    /* XXX: getenv() can't get variable set by SetEnvironmentVariable() */
+    p = getenv("WINICONV_LIBICONV_DLL");
+    if (p == NULL)
+        p = DEFAULT_LIBICONV_DLL;
+    /* parse comma separated value */
+    for ( ; *p != 0; p = (*e == ',') ? e + 1 : e)
+    {
+        e = strchr(p, ',');
+        if (p == e)
+            continue;
+        else if (e == NULL)
+            e = p + strlen(p);
+        dllname = xstrndup(p, e - p);
+        if (dllname == NULL)
+            return FALSE;
+        hlibiconv = LoadLibrary(dllname);
+        free(dllname);
+        if (hlibiconv != NULL)
+        {
+            if (hlibiconv == hwiniconv)
+            {
+                FreeLibrary(hlibiconv);
+                hlibiconv = NULL;
+                continue;
+            }
+            break;
+        }
+    }
+
+    if (hlibiconv == NULL)
+        goto failed;
+
+    hmsvcrt = find_imported_module_by_funcname(hlibiconv, "_errno");
+    if (hmsvcrt == NULL)
+        goto failed;
+
+    _iconv_open = (f_iconv_open)GetProcAddress(hlibiconv, "libiconv_open");
+    if (_iconv_open == NULL)
+        _iconv_open = (f_iconv_open)GetProcAddress(hlibiconv, "iconv_open");
+    cd->iconv_close = (f_iconv_close)GetProcAddress(hlibiconv, "libiconv_close");
+    if (cd->iconv_close == NULL)
+        cd->iconv_close = (f_iconv_close)GetProcAddress(hlibiconv, "iconv_close");
+    cd->iconv = (f_iconv)GetProcAddress(hlibiconv, "libiconv");
+    if (cd->iconv == NULL)
+        cd->iconv = (f_iconv)GetProcAddress(hlibiconv, "iconv");
+    cd->_errno = (f_errno)GetProcAddress(hmsvcrt, "_errno");
+    if (_iconv_open == NULL || cd->iconv_close == NULL
+            || cd->iconv == NULL || cd->_errno == NULL)
+        goto failed;
+
+    cd->cd = _iconv_open(tocode, fromcode);
+    if (cd->cd == (iconv_t)(-1))
+        goto failed;
+
+    cd->hlibiconv = hlibiconv;
+    return TRUE;
+
+failed:
+    if (hlibiconv != NULL)
+        FreeLibrary(hlibiconv);
+    /* do not free hmsvcrt which is obtained by GetModuleHandle() */
+    return FALSE;
+}
+
+/*
+ * Reference:
+ * http://forums.belution.com/ja/vc/000/234/78s.shtml
+ * http://nienie.com/~masapico/api_ImageDirectoryEntryToData.html
+ *
+ * The formal way is
+ *   imagehlp.h or dbghelp.h
+ *   imagehlp.lib or dbghelp.lib
+ *   ImageDirectoryEntryToData()
+ */
+#define TO_DOS_HEADER(base) ((PIMAGE_DOS_HEADER)(base))
+#define TO_NT_HEADERS(base) ((PIMAGE_NT_HEADERS)((LPBYTE)(base) + TO_DOS_HEADER(base)->e_lfanew))
+static PVOID
+MyImageDirectoryEntryToData(LPVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size)
+{
+    /* TODO: MappedAsImage? */
+    PIMAGE_DATA_DIRECTORY p;
+    p = TO_NT_HEADERS(Base)->OptionalHeader.DataDirectory + DirectoryEntry;
+    if (p->VirtualAddress == 0) {
+      *Size = 0;
+      return NULL;
+    }
+    *Size = p->Size;
+    return (PVOID)((LPBYTE)Base + p->VirtualAddress);
+}
+
+static HMODULE
+find_imported_module_by_funcname(HMODULE hModule, const char *funcname)
+{
+    DWORD Base;
+    ULONG Size;
+    PIMAGE_IMPORT_DESCRIPTOR Imp;
+    PIMAGE_THUNK_DATA Name;         /* Import Name Table */
+    PIMAGE_IMPORT_BY_NAME ImpName;
+
+    Base = (DWORD)hModule;
+    Imp = MyImageDirectoryEntryToData(
+            (LPVOID)Base,
+            TRUE,
+            IMAGE_DIRECTORY_ENTRY_IMPORT,
+            &Size);
+    if (Imp == NULL)
+        return NULL;
+    for ( ; Imp->OriginalFirstThunk != 0; ++Imp)
+    {
+        Name = (PIMAGE_THUNK_DATA)(Base + Imp->OriginalFirstThunk);
+        for ( ; Name->u1.Ordinal != 0; ++Name)
+        {
+            if (!IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal))
+            {
+                ImpName = (PIMAGE_IMPORT_BY_NAME)
+                    (Base + (DWORD)Name->u1.AddressOfData);
+                if (strcmp((char *)ImpName->Name, funcname) == 0)
+                    return GetModuleHandle((char *)(Base + Imp->Name));
+            }
+        }
+    }
+    return NULL;
+}
+#endif
+
+static int
+sbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)
+{
+    return 1;
+}
+
+static int
+dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)
+{
+    int len = IsDBCSLeadByteEx(cv->codepage, buf[0]) ? 2 : 1;
+    if (bufsize < len)
+        return seterror(EINVAL);
+    return len;
+}
+
+static int
+mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)
+{
+    int len = 0;
+
+    if (cv->codepage == 54936) {
+       if (buf[0] <= 0x7F) len = 1;
+       else if (buf[0] >= 0x81 && buf[0] <= 0xFE &&
+                bufsize >= 2 &&
+                ((buf[1] >= 0x40 && buf[1] <= 0x7E) ||
+                 (buf[1] >= 0x80 && buf[1] <= 0xFE))) len = 2;
+       else if (buf[0] >= 0x81 && buf[0] <= 0xFE &&
+                bufsize >= 4 &&
+                buf[1] >= 0x30 && buf[1] <= 0x39) len = 4;
+       else
+           return seterror(EINVAL);
+       return len;
+    }
+    else
+       return seterror(EINVAL);
+}
+
+static int
+utf8_mblen(csconv_t *cv, const uchar *buf, int bufsize)
+{
+    int len = 0;
+
+    if (buf[0] < 0x80) len = 1;
+    else if ((buf[0] & 0xE0) == 0xC0) len = 2;
+    else if ((buf[0] & 0xF0) == 0xE0) len = 3;
+    else if ((buf[0] & 0xF8) == 0xF0) len = 4;
+    else if ((buf[0] & 0xFC) == 0xF8) len = 5;
+    else if ((buf[0] & 0xFE) == 0xFC) len = 6;
+
+    if (len == 0)
+        return seterror(EILSEQ);
+    else if (bufsize < len)
+        return seterror(EINVAL);
+    return len;
+}
+
+static int
+eucjp_mblen(csconv_t *cv, const uchar *buf, int bufsize)
+{
+    if (buf[0] < 0x80) /* ASCII */
+        return 1;
+    else if (buf[0] == 0x8E) /* JIS X 0201 */
+    {
+        if (bufsize < 2)
+            return seterror(EINVAL);
+        else if (!(0xA1 <= buf[1] && buf[1] <= 0xDF))
+            return seterror(EILSEQ);
+        return 2;
+    }
+    else if (buf[0] == 0x8F) /* JIS X 0212 */
+    {
+        if (bufsize < 3)
+            return seterror(EINVAL);
+        else if (!(0xA1 <= buf[1] && buf[1] <= 0xFE)
+                || !(0xA1 <= buf[2] && buf[2] <= 0xFE))
+            return seterror(EILSEQ);
+        return 3;
+    }
+    else /* JIS X 0208 */
+    {
+        if (bufsize < 2)
+            return seterror(EINVAL);
+        else if (!(0xA1 <= buf[0] && buf[0] <= 0xFE)
+                || !(0xA1 <= buf[1] && buf[1] <= 0xFE))
+            return seterror(EILSEQ);
+        return 2;
+    }
+}
+
+static int
+kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
+{
+    int len;
+
+    len = cv->mblen(cv, buf, bufsize);
+    if (len == -1)
+        return -1;
+    *wbufsize = MultiByteToWideChar(cv->codepage, mbtowc_flags (cv->codepage),
+            (const char *)buf, len, (wchar_t *)wbuf, *wbufsize);
+    if (*wbufsize == 0)
+        return seterror(EILSEQ);
+    return len;
+}
+
+static int
+kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
+{
+    BOOL usedDefaultChar = 0;
+    BOOL *p = NULL;
+    int flags = 0;
+    int len;
+
+    if (bufsize == 0)
+        return seterror(E2BIG);
+    if (!must_use_null_useddefaultchar(cv->codepage))
+    {
+        p = &usedDefaultChar;
+#ifdef WC_NO_BEST_FIT_CHARS
+        if (!(cv->flags & FLAG_TRANSLIT))
+            flags |= WC_NO_BEST_FIT_CHARS;
+#endif
+    }
+    len = WideCharToMultiByte(cv->codepage, flags,
+            (const wchar_t *)wbuf, wbufsize, (char *)buf, bufsize, NULL, p);
+    if (len == 0)
+    {
+        if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+            return seterror(E2BIG);
+        return seterror(EILSEQ);
+    }
+    else if (usedDefaultChar)
+        return seterror(EILSEQ);
+    else if (cv->mblen(cv, buf, len) != len) /* validate result */
+        return seterror(EILSEQ);
+    return len;
+}
+
+/*
+ * It seems that the mode (cv->mode) is fixnum.
+ * For example, when converting iso-2022-jp(cp50221) to unicode:
+ *      in ascii sequence: mode=0xC42C0000
+ *   in jisx0208 sequence: mode=0xC42C0001
+ * "C42C" is same for each convert session.
+ * It should be: ((codepage-1)<<16)|state
+ */
+static int
+mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
+{
+    int len;
+    int insize;
+    HRESULT hr;
+
+    len = cv->mblen(cv, buf, bufsize);
+    if (len == -1)
+        return -1;
+    insize = len;
+    hr = ConvertINetMultiByteToUnicode(&cv->mode, cv->codepage,
+            (const char *)buf, &insize, (wchar_t *)wbuf, wbufsize);
+    if (hr != S_OK || insize != len)
+        return seterror(EILSEQ);
+    return len;
+}
+
+static int
+mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
+{
+    char tmpbuf[MB_CHAR_MAX]; /* enough room for one character */
+    int tmpsize = MB_CHAR_MAX;
+    int insize = wbufsize;
+    HRESULT hr;
+
+    hr = ConvertINetUnicodeToMultiByte(&cv->mode, cv->codepage,
+            (const wchar_t *)wbuf, &wbufsize, tmpbuf, &tmpsize);
+    if (hr != S_OK || insize != wbufsize)
+        return seterror(EILSEQ);
+    else if (bufsize < tmpsize)
+        return seterror(E2BIG);
+    else if (cv->mblen(cv, (uchar *)tmpbuf, tmpsize) != tmpsize)
+        return seterror(EILSEQ);
+    memcpy(buf, tmpbuf, tmpsize);
+    return tmpsize;
+}
+
+static int
+utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
+{
+    int codepage = cv->codepage;
+
+    /* swap endian: 1200 <-> 1201 */
+    if (cv->mode & UNICODE_MODE_SWAPPED)
+        codepage ^= 1;
+
+    if (bufsize < 2)
+        return seterror(EINVAL);
+    if (codepage == 1200) /* little endian */
+        wbuf[0] = (buf[1] << 8) | buf[0];
+    else if (codepage == 1201) /* big endian */
+        wbuf[0] = (buf[0] << 8) | buf[1];
+
+    if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))
+    {
+        cv->mode |= UNICODE_MODE_BOM_DONE;
+        if (wbuf[0] == 0xFFFE)
+        {
+            cv->mode |= UNICODE_MODE_SWAPPED;
+            *wbufsize = 0;
+            return 2;
+        }
+        else if (wbuf[0] == 0xFEFF)
+        {
+            *wbufsize = 0;
+            return 2;
+        }
+    }
+
+    if (0xDC00 <= wbuf[0] && wbuf[0] <= 0xDFFF)
+        return seterror(EILSEQ);
+    if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)
+    {
+        if (bufsize < 4)
+            return seterror(EINVAL);
+        if (codepage == 1200) /* little endian */
+            wbuf[1] = (buf[3] << 8) | buf[2];
+        else if (codepage == 1201) /* big endian */
+            wbuf[1] = (buf[2] << 8) | buf[3];
+        if (!(0xDC00 <= wbuf[1] && wbuf[1] <= 0xDFFF))
+            return seterror(EILSEQ);
+        *wbufsize = 2;
+        return 4;
+    }
+    *wbufsize = 1;
+    return 2;
+}
+
+static int
+utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
+{
+    if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))
+    {
+        int r;
+
+        cv->mode |= UNICODE_MODE_BOM_DONE;
+        if (bufsize < 2)
+            return seterror(E2BIG);
+        if (cv->codepage == 1200) /* little endian */
+            memcpy(buf, "\xFF\xFE", 2);
+        else if (cv->codepage == 1201) /* big endian */
+            memcpy(buf, "\xFE\xFF", 2);
+
+        r = utf16_wctomb(cv, wbuf, wbufsize, buf + 2, bufsize - 2);
+        if (r == -1)
+            return -1;
+        return r + 2;
+    }
+
+    if (bufsize < 2)
+        return seterror(E2BIG);
+    if (cv->codepage == 1200) /* little endian */
+    {
+        buf[0] = (wbuf[0] & 0x00FF);
+        buf[1] = (wbuf[0] & 0xFF00) >> 8;
+    }
+    else if (cv->codepage == 1201) /* big endian */
+    {
+        buf[0] = (wbuf[0] & 0xFF00) >> 8;
+        buf[1] = (wbuf[0] & 0x00FF);
+    }
+    if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)
+    {
+        if (bufsize < 4)
+            return seterror(E2BIG);
+        if (cv->codepage == 1200) /* little endian */
+        {
+            buf[2] = (wbuf[1] & 0x00FF);
+            buf[3] = (wbuf[1] & 0xFF00) >> 8;
+        }
+        else if (cv->codepage == 1201) /* big endian */
+        {
+            buf[2] = (wbuf[1] & 0xFF00) >> 8;
+            buf[3] = (wbuf[1] & 0x00FF);
+        }
+        return 4;
+    }
+    return 2;
+}
+
+static int
+utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
+{
+    int codepage = cv->codepage;
+    uint wc;
+
+    /* swap endian: 12000 <-> 12001 */
+    if (cv->mode & UNICODE_MODE_SWAPPED)
+        codepage ^= 1;
+
+    if (bufsize < 4)
+        return seterror(EINVAL);
+    if (codepage == 12000) /* little endian */
+        wc = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+    else if (codepage == 12001) /* big endian */
+        wc = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+
+    if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))
+    {
+        cv->mode |= UNICODE_MODE_BOM_DONE;
+        if (wc == 0xFFFE0000)
+        {
+            cv->mode |= UNICODE_MODE_SWAPPED;
+            *wbufsize = 0;
+            return 4;
+        }
+        else if (wc == 0x0000FEFF)
+        {
+            *wbufsize = 0;
+            return 4;
+        }
+    }
+
+    if ((0xD800 <= wc && wc <= 0xDFFF) || 0x10FFFF < wc)
+        return seterror(EILSEQ);
+    ucs4_to_utf16(wc, wbuf, wbufsize);
+    return 4;
+}
+
+static int
+utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
+{
+    uint wc;
+
+    if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))
+    {
+        int r;
+
+        cv->mode |= UNICODE_MODE_BOM_DONE;
+        if (bufsize < 4)
+            return seterror(E2BIG);
+        if (cv->codepage == 12000) /* little endian */
+            memcpy(buf, "\xFF\xFE\x00\x00", 4);
+        else if (cv->codepage == 12001) /* big endian */
+            memcpy(buf, "\x00\x00\xFE\xFF", 4);
+
+        r = utf32_wctomb(cv, wbuf, wbufsize, buf + 4, bufsize - 4);
+        if (r == -1)
+            return -1;
+        return r + 4;
+    }
+
+    if (bufsize < 4)
+        return seterror(E2BIG);
+    wc = utf16_to_ucs4(wbuf);
+    if (cv->codepage == 12000) /* little endian */
+    {
+        buf[0] = wc & 0x000000FF;
+        buf[1] = (wc & 0x0000FF00) >> 8;
+        buf[2] = (wc & 0x00FF0000) >> 16;
+        buf[3] = (wc & 0xFF000000) >> 24;
+    }
+    else if (cv->codepage == 12001) /* big endian */
+    {
+        buf[0] = (wc & 0xFF000000) >> 24;
+        buf[1] = (wc & 0x00FF0000) >> 16;
+        buf[2] = (wc & 0x0000FF00) >> 8;
+        buf[3] = wc & 0x000000FF;
+    }
+    return 4;
+}
+
+/*
+ * 50220: ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS)
+ * 50221: ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow
+ *        1 byte Kana)
+ * 50222: ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte
+ *        Kana - SO/SI)
+ *
+ * MultiByteToWideChar() and WideCharToMultiByte() behave differently
+ * depending on Windows version.  On XP, WideCharToMultiByte() doesn't
+ * terminate result sequence with ascii escape.  But Vista does.
+ * Use MLang instead.
+ */
+
+#define ISO2022_MODE(cs, shift) (((cs) << 8) | (shift))
+#define ISO2022_MODE_CS(mode) (((mode) >> 8) & 0xFF)
+#define ISO2022_MODE_SHIFT(mode) ((mode) & 0xFF)
+
+#define ISO2022_SI  0
+#define ISO2022_SO  1
+
+/* shift in */
+static const char iso2022_SI_seq[] = "\x0F";
+/* shift out */
+static const char iso2022_SO_seq[] = "\x0E";
+
+typedef struct iso2022_esc_t iso2022_esc_t;
+struct iso2022_esc_t {
+    const char *esc;
+    int esc_len;
+    int len;
+    int cs;
+};
+
+#define ISO2022JP_CS_ASCII            0
+#define ISO2022JP_CS_JISX0201_ROMAN   1
+#define ISO2022JP_CS_JISX0201_KANA    2
+#define ISO2022JP_CS_JISX0208_1978    3
+#define ISO2022JP_CS_JISX0208_1983    4
+#define ISO2022JP_CS_JISX0212         5
+
+static iso2022_esc_t iso2022jp_esc[] = {
+    {"\x1B\x28\x42", 3, 1, ISO2022JP_CS_ASCII},
+    {"\x1B\x28\x4A", 3, 1, ISO2022JP_CS_JISX0201_ROMAN},
+    {"\x1B\x28\x49", 3, 1, ISO2022JP_CS_JISX0201_KANA},
+    {"\x1B\x24\x40", 3, 2, ISO2022JP_CS_JISX0208_1983}, /* unify 1978 with 1983 */
+    {"\x1B\x24\x42", 3, 2, ISO2022JP_CS_JISX0208_1983},
+    {"\x1B\x24\x28\x44", 4, 2, ISO2022JP_CS_JISX0212},
+    {NULL, 0, 0, 0}
+};
+
+static int
+iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
+{
+    iso2022_esc_t *iesc = iso2022jp_esc;
+    char tmp[MB_CHAR_MAX];
+    int insize;
+    HRESULT hr;
+    DWORD dummy = 0;
+    int len;
+    int esc_len;
+    int cs;
+    int shift;
+    int i;
+
+    if (buf[0] == 0x1B)
+    {
+        for (i = 0; iesc[i].esc != NULL; ++i)
+        {
+            esc_len = iesc[i].esc_len;
+            if (bufsize < esc_len)
+            {
+                if (strncmp((char *)buf, iesc[i].esc, bufsize) == 0)
+                    return seterror(EINVAL);
+            }
+            else
+            {
+                if (strncmp((char *)buf, iesc[i].esc, esc_len) == 0)
+                {
+                    cv->mode = ISO2022_MODE(iesc[i].cs, ISO2022_SI);
+                    *wbufsize = 0;
+                    return esc_len;
+                }
+            }
+        }
+        /* not supported escape sequence */
+        return seterror(EILSEQ);
+    }
+    else if (buf[0] == iso2022_SO_seq[0])
+    {
+        cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SO);
+        *wbufsize = 0;
+        return 1;
+    }
+    else if (buf[0] == iso2022_SI_seq[0])
+    {
+        cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SI);
+        *wbufsize = 0;
+        return 1;
+    }
+
+    cs = ISO2022_MODE_CS(cv->mode);
+    shift = ISO2022_MODE_SHIFT(cv->mode);
+
+    /* reset the mode for informal sequence */
+    if (buf[0] < 0x20)
+    {
+        cs = ISO2022JP_CS_ASCII;
+        shift = ISO2022_SI;
+    }
+
+    len = iesc[cs].len;
+    if (bufsize < len)
+        return seterror(EINVAL);
+    for (i = 0; i < len; ++i)
+        if (!(buf[i] < 0x80))
+            return seterror(EILSEQ);
+    esc_len = iesc[cs].esc_len;
+    memcpy(tmp, iesc[cs].esc, esc_len);
+    if (shift == ISO2022_SO)
+    {
+        memcpy(tmp + esc_len, iso2022_SO_seq, 1);
+        esc_len += 1;
+    }
+    memcpy(tmp + esc_len, buf, len);
+
+    if ((cv->codepage == 50220 || cv->codepage == 50221
+                || cv->codepage == 50222) && shift == ISO2022_SO)
+    {
+        /* XXX: shift-out cannot be used for mbtowc (both kernel and
+         * mlang) */
+        esc_len = iesc[ISO2022JP_CS_JISX0201_KANA].esc_len;
+        memcpy(tmp, iesc[ISO2022JP_CS_JISX0201_KANA].esc, esc_len);
+        memcpy(tmp + esc_len, buf, len);
+    }
+
+    insize = len + esc_len;
+    hr = ConvertINetMultiByteToUnicode(&dummy, cv->codepage,
+            (const char *)tmp, &insize, (wchar_t *)wbuf, wbufsize);
+    if (hr != S_OK || insize != len + esc_len)
+        return seterror(EILSEQ);
+
+    /* Check for conversion error.  Assuming defaultChar is 0x3F. */
+    /* ascii should be converted from ascii */
+    if (wbuf[0] == buf[0]
+            && cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI))
+        return seterror(EILSEQ);
+
+    /* reset the mode for informal sequence */
+    if (cv->mode != ISO2022_MODE(cs, shift))
+        cv->mode = ISO2022_MODE(cs, shift);
+
+    return len;
+}
+
+static int
+iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
+{
+    iso2022_esc_t *iesc = iso2022jp_esc;
+    char tmp[MB_CHAR_MAX];
+    int tmpsize = MB_CHAR_MAX;
+    int insize = wbufsize;
+    HRESULT hr;
+    DWORD dummy = 0;
+    int len;
+    int esc_len;
+    int cs;
+    int shift;
+    int i;
+
+    /*
+     * MultiByte = [escape sequence] + character + [escape sequence]
+     *
+     * Whether trailing escape sequence is added depends on which API is
+     * used (kernel or MLang, and its version).
+     */
+    hr = ConvertINetUnicodeToMultiByte(&dummy, cv->codepage,
+            (const wchar_t *)wbuf, &wbufsize, tmp, &tmpsize);
+    if (hr != S_OK || insize != wbufsize)
+        return seterror(EILSEQ);
+    else if (bufsize < tmpsize)
+        return seterror(E2BIG);
+
+    if (tmpsize == 1)
+    {
+        cs = ISO2022JP_CS_ASCII;
+        esc_len = 0;
+    }
+    else
+    {
+        for (i = 1; iesc[i].esc != NULL; ++i)
+        {
+            esc_len = iesc[i].esc_len;
+            if (strncmp(tmp, iesc[i].esc, esc_len) == 0)
+            {
+                cs = iesc[i].cs;
+                break;
+            }
+        }
+        if (iesc[i].esc == NULL)
+            /* not supported escape sequence */
+            return seterror(EILSEQ);
+    }
+
+    shift = ISO2022_SI;
+    if (tmp[esc_len] == iso2022_SO_seq[0])
+    {
+        shift = ISO2022_SO;
+        esc_len += 1;
+    }
+
+    len = iesc[cs].len;
+
+    /* Check for converting error.  Assuming defaultChar is 0x3F. */
+    /* ascii should be converted from ascii */
+    if (cs == ISO2022JP_CS_ASCII && !(wbuf[0] < 0x80))
+        return seterror(EILSEQ);
+    else if (tmpsize < esc_len + len)
+        return seterror(EILSEQ);
+
+    if (cv->mode == ISO2022_MODE(cs, shift))
+    {
+        /* remove escape sequence */
+        if (esc_len != 0)
+            memmove(tmp, tmp + esc_len, len);
+        esc_len = 0;
+    }
+    else
+    {
+        if (cs == ISO2022JP_CS_ASCII)
+        {
+            esc_len = iesc[ISO2022JP_CS_ASCII].esc_len;
+            memmove(tmp + esc_len, tmp, len);
+            memcpy(tmp, iesc[ISO2022JP_CS_ASCII].esc, esc_len);
+        }
+        if (ISO2022_MODE_SHIFT(cv->mode) == ISO2022_SO)
+        {
+            /* shift-in before changing to other mode */
+            memmove(tmp + 1, tmp, len + esc_len);
+            memcpy(tmp, iso2022_SI_seq, 1);
+            esc_len += 1;
+        }
+    }
+
+    if (bufsize < len + esc_len)
+        return seterror(E2BIG);
+    memcpy(buf, tmp, len + esc_len);
+    cv->mode = ISO2022_MODE(cs, shift);
+    return len + esc_len;
+}
+
+static int
+iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize)
+{
+    iso2022_esc_t *iesc = iso2022jp_esc;
+    int esc_len;
+
+    if (cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI))
+    {
+        esc_len = 0;
+        if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI)
+            esc_len += 1;
+        if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII)
+            esc_len += iesc[ISO2022JP_CS_ASCII].esc_len;
+        if (bufsize < esc_len)
+            return seterror(E2BIG);
+
+        esc_len = 0;
+        if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI)
+        {
+            memcpy(buf, iso2022_SI_seq, 1);
+            esc_len += 1;
+        }
+        if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII)
+        {
+            memcpy(buf + esc_len, iesc[ISO2022JP_CS_ASCII].esc,
+                    iesc[ISO2022JP_CS_ASCII].esc_len);
+            esc_len += iesc[ISO2022JP_CS_ASCII].esc_len;
+        }
+        return esc_len;
+    }
+    return 0;
+}
+
+#if defined(MAKE_DLL) && defined(USE_LIBICONV_DLL)
+BOOL WINAPI
+DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
+{
+    switch( fdwReason )
+    {
+    case DLL_PROCESS_ATTACH:
+        hwiniconv = (HMODULE)hinstDLL;
+        break;
+    case DLL_THREAD_ATTACH:
+    case DLL_THREAD_DETACH:
+    case DLL_PROCESS_DETACH:
+        break;
+    }
+    return TRUE;
+}
+#endif
+
+#if defined(MAKE_EXE)
+#include <stdio.h>
+#include <fcntl.h>
+#include <io.h>
+int
+main(int argc, char **argv)
+{
+    char *fromcode = NULL;
+    char *tocode = NULL;
+    int i;
+    char inbuf[BUFSIZ];
+    char outbuf[BUFSIZ];
+    const char *pin;
+    char *pout;
+    size_t inbytesleft;
+    size_t outbytesleft;
+    size_t rest = 0;
+    iconv_t cd;
+    size_t r;
+    FILE *in = stdin;
+
+    _setmode(_fileno(stdin), _O_BINARY);
+    _setmode(_fileno(stdout), _O_BINARY);
+
+    for (i = 1; i < argc; ++i)
+    {
+        if (strcmp(argv[i], "-l") == 0)
+        {
+            for (i = 0; codepage_alias[i].name != NULL; ++i)
+                printf("%s\n", codepage_alias[i].name);
+            return 0;
+        }
+
+        if (strcmp(argv[i], "-f") == 0)
+            fromcode = argv[++i];
+        else if (strcmp(argv[i], "-t") == 0)
+            tocode = argv[++i];
+        else
+        {
+            in = fopen(argv[i], "rb");
+            if (in == NULL)
+            {
+                fprintf(stderr, "cannot open %s\n", argv[i]);
+                return 1;
+            }
+            break;
+        }
+    }
+
+    if (fromcode == NULL || tocode == NULL)
+    {
+        printf("usage: %s -f from-enc -t to-enc [file]\n", argv[0]);
+        return 0;
+    }
+
+    cd = iconv_open(tocode, fromcode);
+    if (cd == (iconv_t)(-1))
+    {
+        perror("iconv_open error");
+        return 1;
+    }
+
+    while ((inbytesleft = fread(inbuf + rest, 1, sizeof(inbuf) - rest, in)) != 0
+            || rest != 0)
+    {
+        inbytesleft += rest;
+        pin = inbuf;
+        pout = outbuf;
+        outbytesleft = sizeof(outbuf);
+        r = iconv(cd, &pin, &inbytesleft, &pout, &outbytesleft);
+        fwrite(outbuf, 1, sizeof(outbuf) - outbytesleft, stdout);
+        if (r == (size_t)(-1) && errno != E2BIG && (errno != EINVAL || feof(in)))
+        {
+            perror("conversion error");
+            return 1;
+        }
+        memmove(inbuf, pin, inbytesleft);
+        rest = inbytesleft;
+    }
+    pout = outbuf;
+    outbytesleft = sizeof(outbuf);
+    r = iconv(cd, NULL, NULL, &pout, &outbytesleft);
+    fwrite(outbuf, 1, sizeof(outbuf) - outbytesleft, stdout);
+    if (r == (size_t)(-1))
+    {
+        perror("conversion error");
+        return 1;
+    }
+
+    iconv_close(cd);
+
+    return 0;
+}
+#endif
+
index 25b5574fa6d6fdcdb683fdf119f447390386a694..b2aafa4a57cae89a9cf9f9017eec3f8e8de9f316 100644 (file)
-\r
-#include "win_iconv.c"\r
-#include <stdio.h>\r
-\r
-const char *\r
-tohex(const char *str, int size)\r
-{\r
-    static char buf[BUFSIZ];\r
-    char *pbuf = buf;\r
-    int i;\r
-    buf[0] = 0;\r
-    for (i = 0; i < size; ++i)\r
-        pbuf += sprintf(pbuf, "%02X", str[i] & 0xFF);\r
-    return buf;\r
-}\r
-\r
-const char *\r
-errstr(int errcode)\r
-{\r
-    static char buf[BUFSIZ];\r
-    switch (errcode)\r
-    {\r
-    case 0: return "NOERROR";\r
-    case EINVAL: return "EINVAL";\r
-    case EILSEQ: return "EILSEQ";\r
-    case E2BIG: return "E2BIG";\r
-    }\r
-    sprintf(buf, "%d\n", errcode);\r
-    return buf;\r
-}\r
-\r
-#ifdef USE_LIBICONV_DLL\r
-int use_dll;\r
-\r
-int\r
-setdll(const char *dllpath)\r
-{\r
-    char buf[BUFSIZ];\r
-    rec_iconv_t cd;\r
-\r
-    sprintf(buf, "WINICONV_LIBICONV_DLL=%s", dllpath);\r
-    putenv(buf);\r
-    if (libiconv_iconv_open(&cd, "ascii", "ascii"))\r
-    {\r
-        FreeLibrary(cd.hlibiconv);\r
-        use_dll = TRUE;\r
-        return TRUE;\r
-    }\r
-    use_dll = FALSE;\r
-    return FALSE;\r
-}\r
-#endif\r
-\r
-/*\r
- * We can test the codepage that is installed in the system.\r
- */\r
-int\r
-check_enc(const char *encname, int codepage)\r
-{\r
-    iconv_t cd;\r
-    int cp;\r
-    cd = iconv_open("utf-8", encname);\r
-    if (cd == (iconv_t)(-1))\r
-    {\r
-        printf("%s(%d) IS NOT SUPPORTED: SKIP THE TEST\n", encname, codepage);\r
-        return FALSE;\r
-    }\r
-    cp = ((rec_iconv_t *)cd)->from.codepage;\r
-    if (cp != codepage)\r
-    {\r
-        printf("%s(%d) ALIAS IS MAPPED TO DIFFERENT CODEPAGE (%d)\n", encname, codepage, cp);\r
-        exit(1);\r
-    }\r
-    iconv_close(cd);\r
-    return TRUE;\r
-}\r
-\r
-int use_dll;\r
-\r
-void\r
-test(const char *from, const char *fromstr, int fromsize, const char *to, const char *tostr, int tosize, int errcode, int bufsize, int line)\r
-{\r
-    char outbuf[BUFSIZ];\r
-    const char *pin;\r
-    char *pout;\r
-    size_t inbytesleft;\r
-    size_t outbytesleft;\r
-    iconv_t cd;\r
-    size_t r;\r
-    char dllpath[_MAX_PATH];\r
-\r
-    cd = iconv_open(to, from);\r
-    if (cd == (iconv_t)(-1))\r
-    {\r
-        printf("%s -> %s: NG: INVALID ENCODING NAME: line=%d\n", from, to, line);\r
-        exit(1);\r
-    }\r
-\r
-#ifdef USE_LIBICONV_DLL\r
-    if (((rec_iconv_t *)cd)->hlibiconv != NULL)\r
-        GetModuleFileName(((rec_iconv_t *)cd)->hlibiconv, dllpath, sizeof(dllpath));\r
-\r
-    if (use_dll && ((rec_iconv_t *)cd)->hlibiconv == NULL)\r
-    {\r
-        printf("%s: %s -> %s: NG: FAILED TO USE DLL: line=%d\n", dllpath, from, to, line);\r
-        exit(1);\r
-    }\r
-    else if (!use_dll && ((rec_iconv_t *)cd)->hlibiconv != NULL)\r
-    {\r
-        printf("%s: %s -> %s: NG: DLL IS LOADED UNEXPECTEDLY: line=%d\n", dllpath, from, to, line);\r
-        exit(1);\r
-    }\r
-#endif\r
-\r
-    errno = 0;\r
-\r
-    pin = fromstr;\r
-    pout = outbuf;\r
-    inbytesleft = fromsize;\r
-    outbytesleft = bufsize;\r
-    r = iconv(cd, &pin, &inbytesleft, &pout, &outbytesleft);\r
-    if (r != (size_t)(-1))\r
-        r = iconv(cd, NULL, NULL, &pout, &outbytesleft);\r
-    *pout = 0;\r
-\r
-#ifdef USE_LIBICONV_DLL\r
-    if (use_dll)\r
-        printf("%s: ", dllpath);\r
-#endif\r
-    printf("%s(%s) -> ", from, tohex(fromstr, fromsize));\r
-    printf("%s(%s%s%s): ", to, tohex(tostr, tosize),\r
-            errcode == 0 ? "" : ":",\r
-            errcode == 0 ? "" : errstr(errcode));\r
-    if (strcmp(outbuf, tostr) == 0 && errno == errcode)\r
-        printf("OK\n");\r
-    else\r
-    {\r
-        printf("RESULT(%s:%s): ", tohex(outbuf, sizeof(outbuf) - outbytesleft),\r
-                errstr(errno));\r
-        printf("NG: line=%d\n", line);\r
-        exit(1);\r
-    }\r
-}\r
-\r
-#define STATIC_STRLEN(arr) (sizeof(arr) - 1)\r
-\r
-#define success(from, fromstr, to, tostr) test(from, fromstr, STATIC_STRLEN(fromstr), to, tostr, STATIC_STRLEN(tostr), 0, BUFSIZ, __LINE__)\r
-#define einval(from, fromstr, to, tostr) test(from, fromstr, STATIC_STRLEN(fromstr), to, tostr, STATIC_STRLEN(tostr), EINVAL, BUFSIZ, __LINE__)\r
-#define eilseq(from, fromstr, to, tostr) test(from, fromstr, STATIC_STRLEN(fromstr), to, tostr, STATIC_STRLEN(tostr), EILSEQ, BUFSIZ, __LINE__)\r
-#define e2big(from, fromstr, to, tostr, bufsize) test(from, fromstr, STATIC_STRLEN(fromstr), to, tostr, STATIC_STRLEN(tostr), E2BIG, bufsize, __LINE__)\r
-\r
-int\r
-main(int argc, char **argv)\r
-{\r
-#ifdef USE_LIBICONV_DLL\r
-    /* test use of dll if $DEFAULT_LIBICONV_DLL was defined. */\r
-    if (setdll(""))\r
-    {\r
-        success("ascii", "ABC", "ascii", "ABC");\r
-        success("ascii", "ABC", "utf-16be", "\x00\x41\x00\x42\x00\x43");\r
-    }\r
-    else\r
-    {\r
-        printf("\nDLL TEST IS SKIPPED\n\n");\r
-    }\r
-\r
-    setdll("none");\r
-#endif\r
-\r
-    if (check_enc("ascii", 20127))\r
-    {\r
-        success("ascii", "ABC", "ascii", "ABC");\r
-        /* MSB is dropped.  Hmm... */\r
-        success("ascii", "\x80\xFF", "ascii", "\x00\x7F");\r
-    }\r
-\r
-    /* unicode (CP1200 CP1201 CP12000 CP12001 CP65001) */\r
-    if (check_enc("utf-8", 65001)\r
-            && check_enc("utf-16be", 1201) && check_enc("utf-16le", 1200)\r
-            && check_enc("utf-32be", 12001) && check_enc("utf-32le", 12000)\r
-            )\r
-    {\r
-        /* Test the BOM behavior\r
-         * 1. Remove the BOM when "fromcode" is utf-16 or utf-32.\r
-         * 2. Add the BOM when "tocode" is utf-16 or utf-32.  */\r
-        success("utf-16", "\xFE\xFF\x01\x02", "utf-16be", "\x01\x02");\r
-        success("utf-16", "\xFF\xFE\x02\x01", "utf-16be", "\x01\x02");\r
-        success("utf-32", "\x00\x00\xFE\xFF\x00\x00\x01\x02", "utf-32be", "\x00\x00\x01\x02");\r
-        success("utf-32", "\xFF\xFE\x00\x00\x02\x01\x00\x00", "utf-32be", "\x00\x00\x01\x02");\r
-        success("utf-16", "\xFE\xFF\x00\x01", "utf-8", "\x01");\r
-#ifndef GLIB_COMPILATION\r
-        success("utf-8", "\x01", "utf-16", "\xFE\xFF\x00\x01");\r
-        success("utf-8", "\x01", "utf-32", "\x00\x00\xFE\xFF\x00\x00\x00\x01");\r
-#else\r
-        success("utf-8", "\x01", "utf-16", "\xFF\xFE\x01\x00");\r
-        success("utf-8", "\x01", "utf-32", "\xFF\xFE\x00\x00\x01\x00\x00\x00");\r
-#endif\r
-\r
-        success("utf-16be", "\xFE\xFF\x01\x02", "utf-16be", "\xFE\xFF\x01\x02");\r
-        success("utf-16le", "\xFF\xFE\x02\x01", "utf-16be", "\xFE\xFF\x01\x02");\r
-        success("utf-32be", "\x00\x00\xFE\xFF\x00\x00\x01\x02", "utf-32be", "\x00\x00\xFE\xFF\x00\x00\x01\x02");\r
-        success("utf-32le", "\xFF\xFE\x00\x00\x02\x01\x00\x00", "utf-32be", "\x00\x00\xFE\xFF\x00\x00\x01\x02");\r
-        success("utf-16be", "\xFE\xFF\x00\x01", "utf-8", "\xEF\xBB\xBF\x01");\r
-        success("utf-8", "\xEF\xBB\xBF\x01", "utf-8", "\xEF\xBB\xBF\x01");\r
-\r
-        success("utf-16be", "\x01\x02", "utf-16le", "\x02\x01");\r
-        success("utf-16le", "\x02\x01", "utf-16be", "\x01\x02");\r
-        success("utf-16be", "\xFE\xFF", "utf-16le", "\xFF\xFE");\r
-        success("utf-16le", "\xFF\xFE", "utf-16be", "\xFE\xFF");\r
-        success("utf-32be", "\x00\x00\x03\x04", "utf-32le", "\x04\x03\x00\x00");\r
-        success("utf-32le", "\x04\x03\x00\x00", "utf-32be", "\x00\x00\x03\x04");\r
-        success("utf-32be", "\x00\x00\xFF\xFF", "utf-16be", "\xFF\xFF");\r
-        success("utf-16be", "\xFF\xFF", "utf-32be", "\x00\x00\xFF\xFF");\r
-        success("utf-32be", "\x00\x01\x00\x00", "utf-16be", "\xD8\x00\xDC\x00");\r
-        success("utf-16be", "\xD8\x00\xDC\x00", "utf-32be", "\x00\x01\x00\x00");\r
-        success("utf-32be", "\x00\x10\xFF\xFF", "utf-16be", "\xDB\xFF\xDF\xFF");\r
-        success("utf-16be", "\xDB\xFF\xDF\xFF", "utf-32be", "\x00\x10\xFF\xFF");\r
-        eilseq("utf-32be", "\x00\x11\x00\x00", "utf-16be", "");\r
-        eilseq("utf-16be", "\xDB\xFF\xE0\x00", "utf-32be", "");\r
-        success("utf-8", "\xE3\x81\x82", "utf-16be", "\x30\x42");\r
-        einval("utf-8", "\xE3", "utf-16be", "");\r
-    }\r
-\r
-    /* Japanese (CP932 CP20932 CP50220 CP50221 CP50222 CP51932) */\r
-    if (check_enc("cp932", 932)\r
-            && check_enc("cp20932", 20932) && check_enc("euc-jp", 51932)\r
-            && check_enc("cp50220", 50220) && check_enc("cp50221", 50221)\r
-            && check_enc("cp50222", 50222) && check_enc("iso-2022-jp", 50221))\r
-    {\r
-        /* Test the compatibility for each other Japanese codepage.\r
-         * And validate the escape sequence handling for iso-2022-jp. */\r
-        success("utf-16be", "\xFF\x5E", "cp932", "\x81\x60");\r
-        success("utf-16be", "\x30\x1C", "cp932", "\x81\x60");\r
-        success("utf-16be", "\xFF\x5E", "cp932//nocompat", "\x81\x60");\r
-        eilseq("utf-16be", "\x30\x1C", "cp932//nocompat", "");\r
-        success("euc-jp", "\xA4\xA2", "utf-16be", "\x30\x42");\r
-        einval("euc-jp", "\xA4\xA2\xA4", "utf-16be", "\x30\x42");\r
-        eilseq("euc-jp", "\xA4\xA2\xFF\xFF", "utf-16be", "\x30\x42");\r
-        success("cp932", "\x81\x60", "iso-2022-jp", "\x1B\x24\x42\x21\x41\x1B\x28\x42");\r
-        success("UTF-16BE", "\xFF\x5E", "iso-2022-jp", "\x1B\x24\x42\x21\x41\x1B\x28\x42");\r
-        eilseq("UTF-16BE", "\x30\x1C", "iso-2022-jp//nocompat", "");\r
-        success("UTF-16BE", "\x30\x42\x30\x44", "iso-2022-jp", "\x1B\x24\x42\x24\x22\x24\x24\x1B\x28\x42");\r
-        success("iso-2022-jp", "\x1B\x24\x42\x21\x41\x1B\x28\x42", "UTF-16BE", "\xFF\x5E");\r
-    }\r
-\r
-    /*\r
-     * test for //translit\r
-     * U+FF41 (FULLWIDTH LATIN SMALL LETTER A) <-> U+0062 (LATIN SMALL LETTER A)\r
-     */\r
-    eilseq("UTF-16BE", "\xFF\x41", "iso-8859-1", "");\r
-    success("UTF-16BE", "\xFF\x41", "iso-8859-1//translit", "a");\r
-\r
-    /*\r
-     * TODO:\r
-     * Test for state after iconv() failed.\r
-     * Ensure iconv() error is safe and continuable.\r
-     */\r
-\r
-    return 0;\r
-}\r
-\r
+
+#include "win_iconv.c"
+#include <stdio.h>
+
+const char *
+tohex(const char *str, int size)
+{
+    static char buf[BUFSIZ];
+    char *pbuf = buf;
+    int i;
+    buf[0] = 0;
+    for (i = 0; i < size; ++i)
+        pbuf += sprintf(pbuf, "%02X", str[i] & 0xFF);
+    return buf;
+}
+
+const char *
+errstr(int errcode)
+{
+    static char buf[BUFSIZ];
+    switch (errcode)
+    {
+    case 0: return "NOERROR";
+    case EINVAL: return "EINVAL";
+    case EILSEQ: return "EILSEQ";
+    case E2BIG: return "E2BIG";
+    }
+    sprintf(buf, "%d\n", errcode);
+    return buf;
+}
+
+#ifdef USE_LIBICONV_DLL
+int use_dll;
+
+int
+setdll(const char *dllpath)
+{
+    char buf[BUFSIZ];
+    rec_iconv_t cd;
+
+    sprintf(buf, "WINICONV_LIBICONV_DLL=%s", dllpath);
+    putenv(buf);
+    if (libiconv_iconv_open(&cd, "ascii", "ascii"))
+    {
+        FreeLibrary(cd.hlibiconv);
+        use_dll = TRUE;
+        return TRUE;
+    }
+    use_dll = FALSE;
+    return FALSE;
+}
+#endif
+
+/*
+ * We can test the codepage that is installed in the system.
+ */
+int
+check_enc(const char *encname, int codepage)
+{
+    iconv_t cd;
+    int cp;
+    cd = iconv_open("utf-8", encname);
+    if (cd == (iconv_t)(-1))
+    {
+        printf("%s(%d) IS NOT SUPPORTED: SKIP THE TEST\n", encname, codepage);
+        return FALSE;
+    }
+    cp = ((rec_iconv_t *)cd)->from.codepage;
+    if (cp != codepage)
+    {
+        printf("%s(%d) ALIAS IS MAPPED TO DIFFERENT CODEPAGE (%d)\n", encname, codepage, cp);
+        exit(1);
+    }
+    iconv_close(cd);
+    return TRUE;
+}
+
+int use_dll;
+
+void
+test(const char *from, const char *fromstr, int fromsize, const char *to, const char *tostr, int tosize, int errcode, int bufsize, int line)
+{
+    char outbuf[BUFSIZ];
+    const char *pin;
+    char *pout;
+    size_t inbytesleft;
+    size_t outbytesleft;
+    iconv_t cd;
+    size_t r;
+    char dllpath[_MAX_PATH];
+
+    cd = iconv_open(to, from);
+    if (cd == (iconv_t)(-1))
+    {
+        printf("%s -> %s: NG: INVALID ENCODING NAME: line=%d\n", from, to, line);
+        exit(1);
+    }
+
+#ifdef USE_LIBICONV_DLL
+    if (((rec_iconv_t *)cd)->hlibiconv != NULL)
+        GetModuleFileName(((rec_iconv_t *)cd)->hlibiconv, dllpath, sizeof(dllpath));
+
+    if (use_dll && ((rec_iconv_t *)cd)->hlibiconv == NULL)
+    {
+        printf("%s: %s -> %s: NG: FAILED TO USE DLL: line=%d\n", dllpath, from, to, line);
+        exit(1);
+    }
+    else if (!use_dll && ((rec_iconv_t *)cd)->hlibiconv != NULL)
+    {
+        printf("%s: %s -> %s: NG: DLL IS LOADED UNEXPECTEDLY: line=%d\n", dllpath, from, to, line);
+        exit(1);
+    }
+#endif
+
+    errno = 0;
+
+    pin = fromstr;
+    pout = outbuf;
+    inbytesleft = fromsize;
+    outbytesleft = bufsize;
+    r = iconv(cd, &pin, &inbytesleft, &pout, &outbytesleft);
+    if (r != (size_t)(-1))
+        r = iconv(cd, NULL, NULL, &pout, &outbytesleft);
+    *pout = 0;
+
+#ifdef USE_LIBICONV_DLL
+    if (use_dll)
+        printf("%s: ", dllpath);
+#endif
+    printf("%s(%s) -> ", from, tohex(fromstr, fromsize));
+    printf("%s(%s%s%s): ", to, tohex(tostr, tosize),
+            errcode == 0 ? "" : ":",
+            errcode == 0 ? "" : errstr(errcode));
+    if (strcmp(outbuf, tostr) == 0 && errno == errcode)
+        printf("OK\n");
+    else
+    {
+        printf("RESULT(%s:%s): ", tohex(outbuf, sizeof(outbuf) - outbytesleft),
+                errstr(errno));
+        printf("NG: line=%d\n", line);
+        exit(1);
+    }
+}
+
+#define STATIC_STRLEN(arr) (sizeof(arr) - 1)
+
+#define success(from, fromstr, to, tostr) test(from, fromstr, STATIC_STRLEN(fromstr), to, tostr, STATIC_STRLEN(tostr), 0, BUFSIZ, __LINE__)
+#define einval(from, fromstr, to, tostr) test(from, fromstr, STATIC_STRLEN(fromstr), to, tostr, STATIC_STRLEN(tostr), EINVAL, BUFSIZ, __LINE__)
+#define eilseq(from, fromstr, to, tostr) test(from, fromstr, STATIC_STRLEN(fromstr), to, tostr, STATIC_STRLEN(tostr), EILSEQ, BUFSIZ, __LINE__)
+#define e2big(from, fromstr, to, tostr, bufsize) test(from, fromstr, STATIC_STRLEN(fromstr), to, tostr, STATIC_STRLEN(tostr), E2BIG, bufsize, __LINE__)
+
+int
+main(int argc, char **argv)
+{
+#ifdef USE_LIBICONV_DLL
+    /* test use of dll if $DEFAULT_LIBICONV_DLL was defined. */
+    if (setdll(""))
+    {
+        success("ascii", "ABC", "ascii", "ABC");
+        success("ascii", "ABC", "utf-16be", "\x00\x41\x00\x42\x00\x43");
+    }
+    else
+    {
+        printf("\nDLL TEST IS SKIPPED\n\n");
+    }
+
+    setdll("none");
+#endif
+
+    if (check_enc("ascii", 20127))
+    {
+        success("ascii", "ABC", "ascii", "ABC");
+        /* MSB is dropped.  Hmm... */
+        success("ascii", "\x80\xFF", "ascii", "\x00\x7F");
+    }
+
+    /* unicode (CP1200 CP1201 CP12000 CP12001 CP65001) */
+    if (check_enc("utf-8", 65001)
+            && check_enc("utf-16be", 1201) && check_enc("utf-16le", 1200)
+            && check_enc("utf-32be", 12001) && check_enc("utf-32le", 12000)
+            )
+    {
+        /* Test the BOM behavior
+         * 1. Remove the BOM when "fromcode" is utf-16 or utf-32.
+         * 2. Add the BOM when "tocode" is utf-16 or utf-32.  */
+        success("utf-16", "\xFE\xFF\x01\x02", "utf-16be", "\x01\x02");
+        success("utf-16", "\xFF\xFE\x02\x01", "utf-16be", "\x01\x02");
+        success("utf-32", "\x00\x00\xFE\xFF\x00\x00\x01\x02", "utf-32be", "\x00\x00\x01\x02");
+        success("utf-32", "\xFF\xFE\x00\x00\x02\x01\x00\x00", "utf-32be", "\x00\x00\x01\x02");
+        success("utf-16", "\xFE\xFF\x00\x01", "utf-8", "\x01");
+#ifndef GLIB_COMPILATION
+        success("utf-8", "\x01", "utf-16", "\xFE\xFF\x00\x01");
+        success("utf-8", "\x01", "utf-32", "\x00\x00\xFE\xFF\x00\x00\x00\x01");
+#else
+        success("utf-8", "\x01", "utf-16", "\xFF\xFE\x01\x00");
+        success("utf-8", "\x01", "utf-32", "\xFF\xFE\x00\x00\x01\x00\x00\x00");
+#endif
+
+        success("utf-16be", "\xFE\xFF\x01\x02", "utf-16be", "\xFE\xFF\x01\x02");
+        success("utf-16le", "\xFF\xFE\x02\x01", "utf-16be", "\xFE\xFF\x01\x02");
+        success("utf-32be", "\x00\x00\xFE\xFF\x00\x00\x01\x02", "utf-32be", "\x00\x00\xFE\xFF\x00\x00\x01\x02");
+        success("utf-32le", "\xFF\xFE\x00\x00\x02\x01\x00\x00", "utf-32be", "\x00\x00\xFE\xFF\x00\x00\x01\x02");
+        success("utf-16be", "\xFE\xFF\x00\x01", "utf-8", "\xEF\xBB\xBF\x01");
+        success("utf-8", "\xEF\xBB\xBF\x01", "utf-8", "\xEF\xBB\xBF\x01");
+
+        success("utf-16be", "\x01\x02", "utf-16le", "\x02\x01");
+        success("utf-16le", "\x02\x01", "utf-16be", "\x01\x02");
+        success("utf-16be", "\xFE\xFF", "utf-16le", "\xFF\xFE");
+        success("utf-16le", "\xFF\xFE", "utf-16be", "\xFE\xFF");
+        success("utf-32be", "\x00\x00\x03\x04", "utf-32le", "\x04\x03\x00\x00");
+        success("utf-32le", "\x04\x03\x00\x00", "utf-32be", "\x00\x00\x03\x04");
+        success("utf-32be", "\x00\x00\xFF\xFF", "utf-16be", "\xFF\xFF");
+        success("utf-16be", "\xFF\xFF", "utf-32be", "\x00\x00\xFF\xFF");
+        success("utf-32be", "\x00\x01\x00\x00", "utf-16be", "\xD8\x00\xDC\x00");
+        success("utf-16be", "\xD8\x00\xDC\x00", "utf-32be", "\x00\x01\x00\x00");
+        success("utf-32be", "\x00\x10\xFF\xFF", "utf-16be", "\xDB\xFF\xDF\xFF");
+        success("utf-16be", "\xDB\xFF\xDF\xFF", "utf-32be", "\x00\x10\xFF\xFF");
+        eilseq("utf-32be", "\x00\x11\x00\x00", "utf-16be", "");
+        eilseq("utf-16be", "\xDB\xFF\xE0\x00", "utf-32be", "");
+        success("utf-8", "\xE3\x81\x82", "utf-16be", "\x30\x42");
+        einval("utf-8", "\xE3", "utf-16be", "");
+    }
+
+    /* Japanese (CP932 CP20932 CP50220 CP50221 CP50222 CP51932) */
+    if (check_enc("cp932", 932)
+            && check_enc("cp20932", 20932) && check_enc("euc-jp", 51932)
+            && check_enc("cp50220", 50220) && check_enc("cp50221", 50221)
+            && check_enc("cp50222", 50222) && check_enc("iso-2022-jp", 50221))
+    {
+        /* Test the compatibility for each other Japanese codepage.
+         * And validate the escape sequence handling for iso-2022-jp. */
+        success("utf-16be", "\xFF\x5E", "cp932", "\x81\x60");
+        success("utf-16be", "\x30\x1C", "cp932", "\x81\x60");
+        success("utf-16be", "\xFF\x5E", "cp932//nocompat", "\x81\x60");
+        eilseq("utf-16be", "\x30\x1C", "cp932//nocompat", "");
+        success("euc-jp", "\xA4\xA2", "utf-16be", "\x30\x42");
+        einval("euc-jp", "\xA4\xA2\xA4", "utf-16be", "\x30\x42");
+        eilseq("euc-jp", "\xA4\xA2\xFF\xFF", "utf-16be", "\x30\x42");
+        success("cp932", "\x81\x60", "iso-2022-jp", "\x1B\x24\x42\x21\x41\x1B\x28\x42");
+        success("UTF-16BE", "\xFF\x5E", "iso-2022-jp", "\x1B\x24\x42\x21\x41\x1B\x28\x42");
+        eilseq("UTF-16BE", "\x30\x1C", "iso-2022-jp//nocompat", "");
+        success("UTF-16BE", "\x30\x42\x30\x44", "iso-2022-jp", "\x1B\x24\x42\x24\x22\x24\x24\x1B\x28\x42");
+        success("iso-2022-jp", "\x1B\x24\x42\x21\x41\x1B\x28\x42", "UTF-16BE", "\xFF\x5E");
+    }
+
+    /*
+     * test for //translit
+     * U+FF41 (FULLWIDTH LATIN SMALL LETTER A) <-> U+0062 (LATIN SMALL LETTER A)
+     */
+    eilseq("UTF-16BE", "\xFF\x41", "iso-8859-1", "");
+    success("UTF-16BE", "\xFF\x41", "iso-8859-1//translit", "a");
+
+    /*
+     * TODO:
+     * Test for state after iconv() failed.
+     * Ensure iconv() error is safe and continuable.
+     */
+
+    return 0;
+}
+
index 7d97c29b51b82e52e998e585c1d4760d004e03f7..c844df7052f6494aa4451a020907db78af1a14c8 100644 (file)
-/* Opal endpoint interface for Freeswitch Modular Media Switching Software Library /\r
- * Soft-Switch Application\r
- *\r
- * Version: MPL 1.1\r
- *\r
- * Copyright (c) 2007 Tuyan Ozipek (tuyanozipek@gmail.com)\r
- * Copyright (c) 2008-2012 Vox Lucida Pty. Ltd. (robertj@voxlucida.com.au)\r
- *\r
- * The contents of this file are subject to the Mozilla Public License Version\r
- * 1.1 (the "License"); you may not use this file except in compliance with\r
- * the License. You may obtain a copy of the License at\r
- * http://www.mozilla.org/MPL/\r
- *\r
- * Software distributed under the License is distributed on an "AS IS" basis,\r
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\r
- * for the specific language governing rights and limitations under the\r
- * License.\r
- *\r
- * Contributor(s):\r
- * Tuyan Ozipek   (tuyanozipek@gmail.com)\r
- * Lukasz Zwierko (lzwierko@gmail.com)\r
- * Robert Jongbloed (robertj@voxlucida.com.au)\r
- *\r
- */\r
-\r
-#include "mod_opal.h"\r
-#include <opal/patch.h>\r
-#include <rtp/rtp.h>\r
-#if PTLIB_CHECK_VERSION(2,11,1)\r
-#include <rtp/rtp_session.h>\r
-#endif\r
-#include <h323/h323pdu.h>\r
-#include <h323/gkclient.h>\r
-\r
-\r
-/* FreeSWITCH does not correctly handle an H.323 subtely, that is that a\r
-   MAXIMUM audio frames per packet is negotiated, and there is no\r
-   requirement for the remote to actually send that many. So, in say GSM, we\r
-   negotiate up to 3 frames or 60ms of data and the remote actually sends one\r
-   (20ms) frame per packet. Perfectly legal but blows up the media handling\r
-   in FS.\r
-\r
-   Eventually we will get around to bundling the packets, but not yet. This\r
-   compile flag will just force one frame/packet for all audio codecs.\r
- */\r
-#define IMPLEMENT_MULTI_FAME_AUDIO 0\r
-\r
-\r
-static switch_call_cause_t create_outgoing_channel(switch_core_session_t   *session,\r
-                                                   switch_event_t          *var_event,\r
-                                                   switch_caller_profile_t *outbound_profile,\r
-                                                   switch_core_session_t  **new_session,\r
-                                                   switch_memory_pool_t   **pool,\r
-                                                   switch_originate_flag_t  flags,\r
-                                                   switch_call_cause_t     *cancel_cause);\r
-\r
-\r
-static FSProcess *opal_process = NULL;\r
-\r
-\r
-static PConstString const ModuleName("opal");\r
-static char const ConfigFile[] = "opal.conf";\r
-#define FS_PREFIX "fs"\r
-\r
-\r
-static switch_io_routines_t opalfs_io_routines = {\r
-    /*.outgoing_channel */ create_outgoing_channel,\r
-    /*.read_frame */ FSConnection::read_audio_frame,\r
-    /*.write_frame */ FSConnection::write_audio_frame,\r
-    /*.kill_channel */ FSConnection::kill_channel,\r
-    /*.send_dtmf */ FSConnection::send_dtmf,\r
-    /*.receive_message */ FSConnection::receive_message,\r
-    /*.receive_event */ FSConnection::receive_event,\r
-    /*.state_change */ FSConnection::state_change,\r
-    /*.read_video_frame */ FSConnection::read_video_frame,\r
-    /*.write_video_frame */ FSConnection::write_video_frame\r
-};\r
-\r
-static switch_state_handler_table_t opalfs_event_handlers = {\r
-    /*.on_init */ FSConnection::on_init,\r
-    /*.on_routing */ FSConnection::on_routing,\r
-    /*.on_execute */ FSConnection::on_execute,\r
-    /*.on_hangup */ FSConnection::on_hangup,\r
-    /*.on_exchange_media */ FSConnection::on_exchange_media,\r
-    /*.on_soft_execute */ FSConnection::on_soft_execute,\r
-    /*.on_consume_media*/ NULL,\r
-    /*.on_hibernate*/ NULL,\r
-    /*.on_reset*/ NULL,\r
-    /*.on_park*/ NULL,\r
-    /*.on_reporting*/ NULL,\r
-    /*.on_destroy*/ FSConnection::on_destroy\r
-};\r
-\r
-\r
-SWITCH_BEGIN_EXTERN_C\r
-/*******************************************************************************/\r
-\r
-SWITCH_MODULE_LOAD_FUNCTION(mod_opal_load);\r
-SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_opal_shutdown);\r
-SWITCH_MODULE_DEFINITION(mod_opal, mod_opal_load, mod_opal_shutdown, NULL);\r
-\r
-SWITCH_MODULE_LOAD_FUNCTION(mod_opal_load)\r
-{\r
-    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Starting loading mod_opal\n");\r
-\r
-    /* Prevent the loading of OPAL codecs via "plug ins", this is a directory\r
-       full of DLLs that will be loaded automatically. */\r
-    (void)putenv((char *)"PTLIBPLUGINDIR=/no/thanks");\r
-\r
-\r
-    *module_interface = switch_loadable_module_create_module_interface(pool, modname);\r
-    if (!*module_interface) {\r
-        return SWITCH_STATUS_MEMERR;\r
-    }\r
-\r
-    opal_process = new FSProcess();\r
-    if (opal_process == NULL) {\r
-        return SWITCH_STATUS_MEMERR;\r
-    }\r
-\r
-    if (opal_process->Initialise(*module_interface)) {\r
-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Opal manager initialized and running\n");\r
-        //unloading causes a seg in linux\r
-        //return SWITCH_STATUS_UNLOAD;\r
-        return SWITCH_STATUS_SUCCESS;\r
-    }\r
-\r
-    delete opal_process;\r
-    opal_process = NULL;\r
-    return SWITCH_STATUS_FALSE;\r
-}\r
-\r
-\r
-SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_opal_shutdown)\r
-{\r
-    delete opal_process;\r
-    opal_process = NULL;\r
-    return SWITCH_STATUS_SUCCESS;\r
-}\r
-\r
-SWITCH_END_EXTERN_C\r
-/*******************************************************************************/\r
-\r
-///////////////////////////////////////////////////////////////////////\r
-\r
-#if PTRACING\r
-\r
-class FSTrace : public std::ostream\r
-{\r
-private:\r
-  class Buffer : public std::stringbuf\r
-  {\r
-    virtual int sync()\r
-    {\r
-      std::string s = str();\r
-      if (s.empty())\r
-        return 0;\r
-\r
-      //Due to explicit setting of flags we know exactly what we are getting\r
-  #define THREAD_ID_INDEX 2\r
-  #define FILE_NAME_INDEX 3\r
-  #define FILE_LINE_INDEX 4\r
-#if PTLIB_CHECK_VERSION(2,11,1)\r
-  #define CONTEXT_ID_REGEX "([0-9]+|- - - - - - -)\t"\r
-  #define LOG_PRINTF_FORMAT "{%s,%s} %s"\r
-  #define FULL_TEXT_INDEX 6\r
-#else\r
-  #define CONTEXT_ID_REGEX\r
-  #define LOG_PRINTF_FORMAT "{%s} %s"\r
-  #define FULL_TEXT_INDEX 5\r
-#endif\r
-      PStringArray fields(7);\r
-      static PRegularExpression logRE("^([0-9]+)\t *(.+)\t *([^(]+)\\(([0-9]+)\\)\t"CONTEXT_ID_REGEX"(.*)",\r
-                                      PRegularExpression::Extended);\r
-      if (!logRE.Execute(s.c_str(), fields)) {\r
-        fields[1] = "4";\r
-        fields[THREAD_ID_INDEX] = "unknown";\r
-        fields[FILE_NAME_INDEX] = __FILE__;\r
-        fields[FILE_LINE_INDEX] = __LINE__;\r
-        fields[FULL_TEXT_INDEX] = s;\r
-      }\r
-\r
-      switch_log_level_t level;\r
-      switch (fields[1].AsUnsigned()) {\r
-        case 0 :\r
-          level = SWITCH_LOG_ALERT;\r
-          break;\r
-        case 1 :\r
-          level = SWITCH_LOG_ERROR;\r
-          break;\r
-        case 2 :\r
-          level = SWITCH_LOG_WARNING;\r
-          break;\r
-        case 3 :\r
-          level = SWITCH_LOG_INFO;\r
-          break;\r
-        default :\r
-          level = SWITCH_LOG_DEBUG;\r
-          break;\r
-      }\r
-\r
-      fields[4].Replace("\t", " ", true);\r
-#if PTLIB_CHECK_VERSION(2,11,1)\r
-      fields[5].Replace("- - - - - - -", "-"),\r
-#endif\r
-      switch_log_printf(SWITCH_CHANNEL_ID_LOG,\r
-                        fields[FILE_NAME_INDEX],\r
-                        "PTLib-OPAL",\r
-                        fields[FILE_LINE_INDEX].AsUnsigned(),\r
-                        NULL,\r
-                        level,\r
-                        LOG_PRINTF_FORMAT,\r
-                        fields[THREAD_ID_INDEX].GetPointer(),\r
-#if PTLIB_CHECK_VERSION(2,11,1)\r
-                        fields[5].GetPointer(),\r
-#endif\r
-                        fields[FULL_TEXT_INDEX].GetPointer());\r
-\r
-      // Reset string\r
-      str(std::string());\r
-      return 0;\r
-    }\r
-  } buffer;\r
-\r
-public:\r
-  FSTrace()\r
-    : ostream(&buffer)\r
-  {\r
-  }\r
-};\r
-\r
-#endif // PTRACING\r
-\r
-\r
-///////////////////////////////////////////////////////////////////////\r
-\r
-FSProcess::FSProcess()\r
-  : PLibraryProcess("Vox Lucida Pty. Ltd.", MODNAME, 1, 1, BetaCode, 1)\r
-  , m_manager(NULL)\r
-{\r
-}\r
-\r
-\r
-FSProcess::~FSProcess()\r
-{\r
-  delete m_manager;\r
-#if PTRACING\r
-    PTrace::SetStream(NULL); // This will delete the FSTrace object\r
-#endif\r
-}\r
-\r
-\r
-bool FSProcess::Initialise(switch_loadable_module_interface_t *iface)\r
-{\r
-    m_manager = new FSManager();\r
-    return m_manager != NULL && m_manager->Initialise(iface);\r
-}\r
-\r
-\r
-///////////////////////////////////////////////////////////////////////\r
-\r
-FSManager::FSManager()\r
-  : m_context("default")\r
-  , m_dialplan("XML")\r
-{\r
-    // These are deleted by the OpalManager class, no need to have destructor\r
-    m_h323ep = new H323EndPoint(*this);\r
-    m_iaxep = new IAX2EndPoint(*this);\r
-    m_fsep = new FSEndPoint(*this);\r
-}\r
-\r
-\r
-bool FSManager::Initialise(switch_loadable_module_interface_t *iface)\r
-{\r
-    ReadConfig(false);\r
-\r
-    m_FreeSwitch = (switch_endpoint_interface_t *) switch_loadable_module_create_interface(iface, SWITCH_ENDPOINT_INTERFACE);\r
-    m_FreeSwitch->interface_name = ModuleName;\r
-    m_FreeSwitch->io_routines = &opalfs_io_routines;\r
-    m_FreeSwitch->state_handler = &opalfs_event_handlers;\r
-\r
-    silenceDetectParams.m_mode = OpalSilenceDetector::NoSilenceDetection;\r
-\r
-    if (m_listeners.empty()) {\r
-        m_h323ep->StartListener("");\r
-    } else {\r
-        for (std::list < FSListener >::iterator it = m_listeners.begin(); it != m_listeners.end(); ++it) {\r
-            if (!m_h323ep->StartListener(OpalTransportAddress(it->m_address, it->m_port))) {\r
-                PTRACE(2, "mod_opal\tCannot start listener for " << it->m_name);\r
-            }\r
-        }\r
-    }\r
-\r
-    AddRouteEntry("h323:.* = "FS_PREFIX":<da>");  // config option for direct routing\r
-    AddRouteEntry("iax2:.* = "FS_PREFIX":<da>");  // config option for direct routing\r
-    AddRouteEntry(FS_PREFIX":.* = h323:<da>");  // config option for direct routing\r
-\r
-    // Make sure all known codecs are instantiated,\r
-    // these are ones we know how to translate into H.323 capabilities\r
-    GetOpalG728();\r
-    GetOpalG729();\r
-    GetOpalG729A();\r
-    GetOpalG729B();\r
-    GetOpalG729AB();\r
-    GetOpalG7231_6k3();\r
-    GetOpalG7231_5k3();\r
-    GetOpalG7231A_6k3();\r
-    GetOpalG7231A_5k3();\r
-    GetOpalGSM0610();\r
-    GetOpalGSMAMR();\r
-    GetOpaliLBC();\r
-\r
-#if !IMPLEMENT_MULTI_FAME_AUDIO\r
-    OpalMediaFormatList allCodecs = OpalMediaFormat::GetAllRegisteredMediaFormats();\r
-    for (OpalMediaFormatList::iterator it = allCodecs.begin(); it != allCodecs.end(); ++it) {\r
-      if (it->GetMediaType() == OpalMediaType::Audio()) {\r
-        int ms_per_frame = it->GetFrameTime()/it->GetTimeUnits();\r
-        int frames_in_20_ms = (ms_per_frame+19)/ms_per_frame;\r
-        it->SetOptionInteger(OpalAudioFormat::RxFramesPerPacketOption(), frames_in_20_ms);\r
-        it->SetOptionInteger(OpalAudioFormat::TxFramesPerPacketOption(), frames_in_20_ms);\r
-        OpalMediaFormat::SetRegisteredMediaFormat(*it);\r
-        PTRACE(4, "mod_opal\tSet " << *it << " to " << frames_in_20_ms << "frames/packet");\r
-      }\r
-    }\r
-#endif // IMPLEMENT_MULTI_FAME_AUDIO\r
-\r
-    OpalMediaFormat t38 = OpalT38;\r
-    t38.SetOptionBoolean("UDPTL-Raw-Mode", true);\r
-    OpalMediaFormat::SetRegisteredMediaFormat(t38);\r
-\r
-    if (!m_gkAddress.IsEmpty()) {\r
-      if (m_h323ep->UseGatekeeper(m_gkAddress, m_gkIdentifer, m_gkInterface))\r
-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Started gatekeeper: %s\n",\r
-                          (const char *)m_h323ep->GetGatekeeper()->GetName());\r
-      else\r
-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,\r
-                          "Could not start gatekeeper: addr=\"%s\", id=\"%s\", if=\"%s\"\n",\r
-                          (const char *)m_gkAddress,\r
-                          (const char *)m_gkIdentifer,\r
-                          (const char *)m_gkInterface);\r
-    }\r
-\r
-    return TRUE;\r
-}\r
-\r
-\r
-switch_status_t FSManager::ReadConfig(int reload)\r
-{\r
-    switch_event_t *request_params = NULL;\r
-    switch_event_create(&request_params, SWITCH_EVENT_REQUEST_PARAMS);\r
-    switch_assert(request_params);\r
-    switch_event_add_header_string(request_params, SWITCH_STACK_BOTTOM, "profile", switch_str_nil(""));\r
-\r
-    switch_xml_t cfg;\r
-    switch_xml_t xml = switch_xml_open_cfg(ConfigFile, &cfg, request_params);\r
-    if (xml == NULL) {\r
-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", ConfigFile);\r
-        return SWITCH_STATUS_FALSE;\r
-    }\r
-\r
-    switch_xml_t xmlSettings = switch_xml_child(cfg, "settings");\r
-    if (xmlSettings) {\r
-        for (switch_xml_t xmlParam = switch_xml_child(xmlSettings, "param"); xmlParam != NULL; xmlParam = xmlParam->next) {\r
-            PConstCaselessString const var(switch_xml_attr_soft(xmlParam, "name"));\r
-            PConstString const val(switch_xml_attr_soft(xmlParam, "value"));\r
-\r
-            if (var == "context") {\r
-                m_context = val;\r
-            } else if (var == "dialplan") {\r
-                m_dialplan = val;\r
-            } else if (var == "codec-prefs") {\r
-                m_codecPrefs = val;\r
-            } else if (var == "disable-transcoding") {\r
-                m_disableTranscoding = switch_true(val);\r
-            } else if (var == "dtmf-type") {\r
-                if (val == "string")\r
-                  m_h323ep->SetSendUserInputMode(OpalConnection::SendUserInputAsString);\r
-                else if (val == "signal")\r
-                  m_h323ep->SetSendUserInputMode(OpalConnection::SendUserInputAsTone);\r
-                else if (val == "rfc2833")\r
-                  m_h323ep->SetSendUserInputMode(OpalConnection::SendUserInputAsRFC2833);\r
-                else if (val == "in-band")\r
-                  m_h323ep->SetSendUserInputMode(OpalConnection::SendUserInputInBand);\r
-            } else if (var == "jitter-size") {\r
-                SetAudioJitterDelay(val.AsUnsigned(), val.Mid(val.Find(',')+1).AsUnsigned()); // In milliseconds\r
-            } else if (var == "gk-address") {\r
-                m_gkAddress = val;\r
-            } else if (var == "gk-identifer") {\r
-                m_gkIdentifer = val;\r
-            } else if (var == "gk-interface") {\r
-                m_gkInterface = val;\r
-#if PTRACING\r
-            } else if (var == "trace-level") {\r
-                unsigned level = val.AsUnsigned();\r
-                if (level > 0) {\r
-                    PTrace::SetLevel(level);\r
-                    PTrace::ClearOptions(0xffffffff); // Everything off\r
-                    PTrace::SetOptions(               // Except these\r
-                      PTrace::TraceLevel|PTrace::FileAndLine|PTrace::Thread\r
-#if PTLIB_CHECK_VERSION(2,11,1)\r
-                      |PTrace::ContextIdentifier\r
-#endif\r
-                    );\r
-                    PTrace::SetStream(new FSTrace);\r
-                }\r
-#endif\r
-            }\r
-        }\r
-    }\r
-\r
-    switch_xml_t xmlListeners = switch_xml_child(cfg, "listeners");\r
-    if (xmlListeners != NULL) {\r
-        for (switch_xml_t xmlListener = switch_xml_child(xmlListeners, "listener"); xmlListener != NULL; xmlListener = xmlListener->next) {\r
-\r
-            m_listeners.push_back(FSListener());\r
-            FSListener & listener = m_listeners.back();\r
-\r
-            listener.m_name = switch_xml_attr_soft(xmlListener, "name");\r
-            if (listener.m_name.IsEmpty())\r
-                listener.m_name = "unnamed";\r
-\r
-            for (switch_xml_t xmlParam = switch_xml_child(xmlListener, "param"); xmlParam != NULL; xmlParam = xmlParam->next) {\r
-                PConstCaselessString const var(switch_xml_attr_soft(xmlParam, "name"));\r
-                PConstString const val(switch_xml_attr_soft(xmlParam, "value"));\r
-                if (var == "h323-ip")\r
-                    listener.m_address = val;\r
-                else if (var == "h323-port")\r
-                    listener.m_port = (uint16_t)val.AsUnsigned();\r
-            }\r
-\r
-            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Created Listener '%s'\n", (const char *) listener.m_name);\r
-        }\r
-    }\r
-\r
-    switch_event_destroy(&request_params);\r
-\r
-    if (xml)\r
-        switch_xml_free(xml);\r
-\r
-    return SWITCH_STATUS_SUCCESS;\r
-}\r
-\r
-\r
-static switch_call_cause_t create_outgoing_channel(switch_core_session_t   *session,\r
-                                                   switch_event_t          *var_event,\r
-                                                   switch_caller_profile_t *outbound_profile,\r
-                                                   switch_core_session_t  **new_session,\r
-                                                   switch_memory_pool_t   **pool,\r
-                                                   switch_originate_flag_t  flags,\r
-                                                   switch_call_cause_t     *cancel_cause)\r
-{\r
-    if (opal_process == NULL)\r
-      return SWITCH_CAUSE_CRASH;\r
-\r
-    FSConnection::outgoing_params params;\r
-    params.var_event        = var_event;\r
-    params.outbound_profile = outbound_profile;\r
-    params.new_session      = new_session;\r
-    params.pool             = pool;\r
-    params.flags            = flags;\r
-    params.cancel_cause     = cancel_cause;\r
-    params.fail_cause       = SWITCH_CAUSE_INVALID_NUMBER_FORMAT;\r
-\r
-    if (opal_process->GetManager().SetUpCall(FS_PREFIX":", outbound_profile->destination_number, &params) != NULL)\r
-        return SWITCH_CAUSE_SUCCESS;\r
-\r
-    if (*new_session != NULL)\r
-        switch_core_session_destroy(new_session);\r
-    return params.fail_cause;\r
-}\r
-\r
-\r
-///////////////////////////////////////////////////////////////////////\r
-\r
-FSEndPoint::FSEndPoint(FSManager & manager)\r
-  : OpalLocalEndPoint(manager, FS_PREFIX)\r
-  , m_manager(manager)\r
-{\r
-    PTRACE(4, "mod_opal\tFSEndPoint created.");\r
-}\r
-\r
-\r
-OpalLocalConnection *FSEndPoint::CreateConnection(OpalCall & call, void *userData, unsigned options, OpalConnection::StringOptions* stringOptions)\r
-{\r
-    return new FSConnection(call, *this, options, stringOptions, (FSConnection::outgoing_params *)userData);\r
-}\r
-\r
-\r
-///////////////////////////////////////////////////////////////////////\r
-\r
-FSConnection::FSConnection(OpalCall & call,\r
-                           FSEndPoint & endpoint,\r
-                           unsigned options,\r
-                           OpalConnection::StringOptions* stringOptions,\r
-                           outgoing_params * params)\r
-  : OpalLocalConnection(call, endpoint, NULL, options, stringOptions)\r
-  , m_endpoint(endpoint)\r
-  , m_fsSession(NULL)\r
-  , m_fsChannel(NULL)\r
-  , m_flushAudio(false)\r
-  , m_udptl(false)\r
-{\r
-    memset(&m_read_timer, 0, sizeof(m_read_timer));\r
-    memset(&m_read_codec, 0, sizeof(m_read_codec));\r
-    memset(&m_write_codec, 0, sizeof(m_write_codec));\r
-    memset(&m_vid_read_timer, 0, sizeof(m_vid_read_timer));\r
-    memset(&m_vid_read_codec, 0, sizeof(m_vid_read_codec));\r
-    memset(&m_vid_write_codec, 0, sizeof(m_vid_write_codec));\r
-    memset(&m_dummy_frame, 0, sizeof(m_dummy_frame));\r
-    m_dummy_frame.flags = SFF_CNG;\r
-\r
-    if (params != NULL) {\r
-        // If we fail, this is the cause\r
-        params->fail_cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;\r
-\r
-        if ((m_fsSession = switch_core_session_request(endpoint.GetManager().GetSwitchInterface(),\r
-                                      SWITCH_CALL_DIRECTION_OUTBOUND, params->flags, params->pool)) == NULL) {\r
-            PTRACE(1, "mod_opal\tCannot create session for outgoing call.");\r
-            return;\r
-        }\r
-    }\r
-    else {\r
-      if ((m_fsSession = switch_core_session_request(endpoint.GetManager().GetSwitchInterface(),\r
-                                                     SWITCH_CALL_DIRECTION_INBOUND, SOF_NONE, NULL)) == NULL) {\r
-            PTRACE(1, "mod_opal\tCannot create session for incoming call.");\r
-            return;\r
-      }\r
-    }\r
-\r
-    if ((m_fsChannel = switch_core_session_get_channel(m_fsSession)) == NULL) {\r
-        switch_core_session_destroy(&m_fsSession);\r
-        return;\r
-    }\r
-\r
-    switch_core_session_set_private(m_fsSession, this);\r
-    SafeReference(); // Make sure cannot be deleted until on_destroy()\r
-\r
-    if (params != NULL) {\r
-        switch_caller_profile_t *caller_profile = switch_caller_profile_clone(m_fsSession, params->outbound_profile);\r
-        switch_channel_set_caller_profile(m_fsChannel, caller_profile);\r
-        SetLocalPartyName(caller_profile->caller_id_number);\r
-        SetDisplayName(caller_profile->caller_id_name);\r
-\r
-        *params->new_session = m_fsSession;\r
-    }\r
-\r
-    switch_channel_set_state(m_fsChannel, CS_INIT);\r
-}\r
-\r
-\r
-bool FSConnection::OnOutgoingSetUp()\r
-{\r
-    if (m_fsSession == NULL || m_fsChannel == NULL) {\r
-        PTRACE(1, "mod_opal\tSession request failed.");\r
-        return false;\r
-    }\r
-\r
-    // Transfer FS caller_id_number & caller_id_name from the FSConnection\r
-    // to the protocol connection (e.g. H.323) so gets sent correctly\r
-    // in outgoing packets\r
-    PSafePtr<OpalConnection> proto = GetOtherPartyConnection();\r
-    if (proto == NULL) {\r
-        PTRACE(1, "mod_opal\tNo protocol connection in call.");\r
-        return false;\r
-    }\r
-\r
-    proto->SetLocalPartyName(GetLocalPartyName());\r
-    proto->SetDisplayName(GetDisplayName());\r
-\r
-    switch_channel_set_name(m_fsChannel, ModuleName + '/' + GetRemotePartyURL());\r
-    return true;\r
-}\r
-\r
-\r
-bool FSConnection::OnIncoming()\r
-{\r
-    if (m_fsSession == NULL || m_fsChannel == NULL) {\r
-        PTRACE(1, "mod_opal\tSession request failed.");\r
-        return false;\r
-    }\r
-\r
-    switch_core_session_add_stream(m_fsSession, NULL);\r
-\r
-    PURL url = GetRemotePartyURL();\r
-    switch_caller_profile_t *caller_profile = switch_caller_profile_new(\r
-          switch_core_session_get_pool(m_fsSession),\r
-          url.GetUserName(),      /** username */\r
-          m_endpoint.GetManager().GetDialPlan(), /** dial plan */\r
-          GetRemotePartyName(),   /** caller_id_name */\r
-          GetRemotePartyNumber(), /** caller_id_number */\r
-          url.GetHostName(),      /** network addr */\r
-          NULL,                   /** ANI */\r
-          NULL,                   /** ANI II */\r
-          NULL,                   /** RDNIS */\r
-          ModuleName,             /** source */\r
-          m_endpoint.GetManager().GetContext(), /** set context  */\r
-          GetCalledPartyNumber()  /** destination_number */\r
-    );\r
-    if (caller_profile == NULL) {\r
-        PTRACE(1, "mod_opal\tCould not create caller profile");\r
-        return false;\r
-    }\r
-\r
-    PTRACE(4, "mod_opal\tCreated switch caller profile:\n"\r
-              "  username          = " << caller_profile->username << "\n"\r
-              "  dialplan          = " << caller_profile->dialplan << "\n"\r
-              "  caller_id_name    = " << caller_profile->caller_id_name << "\n"\r
-              "  caller_id_number  = " << caller_profile->caller_id_number << "\n"\r
-              "  network_addr      = " << caller_profile->network_addr << "\n"\r
-              "  source            = " << caller_profile->source << "\n"\r
-              "  context           = " << caller_profile->context << "\n"\r
-              "  destination_number= " << caller_profile->destination_number);\r
-    switch_channel_set_caller_profile(m_fsChannel, caller_profile);\r
-\r
-    switch_channel_set_name(m_fsChannel, ModuleName + '/' + url.GetScheme() + ':' + caller_profile->destination_number);\r
-\r
-    if (switch_core_session_thread_launch(m_fsSession) != SWITCH_STATUS_SUCCESS) {\r
-        PTRACE(1, "mod_opal\tCould not launch session thread");\r
-        switch_core_session_destroy(&m_fsSession);\r
-        m_fsChannel = NULL;\r
-        return false;\r
-    }\r
-\r
-    return true;\r
-}\r
-\r
-\r
-void FSConnection::OnEstablished()\r
-{\r
-  OpalLocalConnection::OnEstablished();\r
-\r
-  if (switch_channel_direction(m_fsChannel) == SWITCH_CALL_DIRECTION_OUTBOUND) {\r
-    PTRACE(4, "mod_opal\tOnEstablished for outbound call, checking for media");\r
-    if (GetMediaStream(OpalMediaType::Audio(), true) != NULL && GetMediaStream(OpalMediaType::Audio(), false) != NULL) {\r
-      PTRACE(3, "mod_opal\tOnEstablished for outbound call, making call answered");\r
-      switch_channel_mark_answered(m_fsChannel);\r
-    }\r
-  }\r
-}\r
-\r
-\r
-void FSConnection::OnReleased()\r
-{\r
-    m_rxAudioOpened.Signal();   // Just in case\r
-    m_txAudioOpened.Signal();\r
-\r
-    if (m_fsChannel != NULL) {\r
-        PTRACE(3, "mod_opal\tHanging up FS side");\r
-        switch_channel_hangup(m_fsChannel, (switch_call_cause_t)callEndReason.q931);\r
-    }\r
-\r
-    OpalLocalConnection::OnReleased();\r
-}\r
-\r
-\r
-PBoolean FSConnection::SetAlerting(const PString & calleeName, PBoolean withMedia)\r
-{\r
-    if (PAssertNULL(m_fsChannel) == NULL)\r
-        return false;\r
-\r
-    switch_channel_mark_ring_ready(m_fsChannel);\r
-    return OpalLocalConnection::SetAlerting(calleeName, withMedia);\r
-}\r
-\r
-\r
-PBoolean FSConnection::SendUserInputTone(char tone, unsigned duration)\r
-{\r
-    if (PAssertNULL(m_fsChannel) == NULL)\r
-        return false;\r
-\r
-    switch_dtmf_t dtmf = { tone, duration };\r
-    PTRACE(4, "mod_opal\tSending DTMF to FS: tone=" << tone << ", duration=" << duration);\r
-    return switch_channel_queue_dtmf(m_fsChannel, &dtmf) == SWITCH_STATUS_SUCCESS;\r
-}\r
-\r
-\r
-OpalMediaFormatList FSConnection::GetMediaFormats() const\r
-{\r
-    if (m_switchMediaFormats.IsEmpty()) {\r
-        const_cast<FSConnection *>(this)->SetCodecs();\r
-    }\r
-\r
-    return m_switchMediaFormats;\r
-}\r
-\r
-\r
-void FSConnection::SetCodecs()\r
-{\r
-    int numCodecs = 0;\r
-    const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS];\r
-\r
-    PString codec_string = switch_channel_get_variable(m_fsChannel, "absolute_codec_string");\r
-    if (codec_string.IsEmpty()) {\r
-        codec_string = switch_channel_get_variable(m_fsChannel, "codec_string");\r
-        if (codec_string.IsEmpty()) {\r
-            codec_string = m_endpoint.GetManager().GetCodecPrefs();\r
-            if (codec_string.IsEmpty()) {\r
-                numCodecs = switch_loadable_module_get_codecs(codecs, sizeof(codecs) / sizeof(codecs[0]));\r
-                for (int i = 0; i < numCodecs; i++) {\r
-                  if (i > 0)\r
-                    codec_string += ',';\r
-                  codec_string += codecs[i]->iananame;\r
-                }\r
-                PTRACE(4, "mod_opal\tDefault to all loaded codecs=" << codec_string);\r
-            }\r
-            else {\r
-                PTRACE(4, "mod_opal\tSettings codec-prefs=" << codec_string);\r
-            }\r
-        }\r
-        else {\r
-            PTRACE(4, "mod_opal\tChannel codec_string=" << codec_string);\r
-        }\r
-\r
-        PString orig_codec = switch_channel_get_variable(m_fsChannel, SWITCH_ORIGINATOR_CODEC_VARIABLE);\r
-        if (!orig_codec.IsEmpty()) {\r
-          if (m_endpoint.GetManager().GetDisableTranscoding()) {\r
-              codec_string = orig_codec;\r
-              PTRACE(4, "mod_opal\tNo transcoding, forced to originator codec=" << orig_codec);\r
-          }\r
-          else {\r
-              codec_string.Splice(orig_codec+',', 0);\r
-              PTRACE(4, "mod_opal\tSetting preference to originator codec=" << orig_codec);\r
-          }\r
-        }\r
-    }\r
-    else {\r
-        PTRACE(4, "mod_opal\tChannel absolute_codec_string=" << codec_string);\r
-    }\r
-\r
-    {\r
-        char *codec_order[SWITCH_MAX_CODECS];\r
-        int codec_order_last = switch_separate_string((char *)codec_string.GetPointer(), ',', codec_order, SWITCH_MAX_CODECS);\r
-        numCodecs = switch_loadable_module_get_codecs_sorted(codecs, SWITCH_MAX_CODECS, codec_order, codec_order_last);\r
-    }\r
-\r
-    for (int i = 0; i < numCodecs; i++) {\r
-        const switch_codec_implementation_t *codec = codecs[i];\r
-\r
-        // See if we have a match by PayloadType/rate/name\r
-        OpalMediaFormat switchFormat((RTP_DataFrame::PayloadTypes)codec->ianacode,\r
-                                     codec->samples_per_second,\r
-                                     codec->iananame);\r
-        if (!switchFormat.IsValid()) {\r
-            // See if we have a match by name alone\r
-            switchFormat = codec->iananame;\r
-            if (!switchFormat.IsValid()) {\r
-              PTRACE(2, "mod_opal\tCould not match FS codec "\r
-                     << codec->iananame << '@' << codec->samples_per_second\r
-                     << " (pt=" << (unsigned)codec->ianacode << ")"\r
-                        " to an OPAL media format.");\r
-              continue;\r
-            }\r
-        }\r
-\r
-        PTRACE(4, "mod_opal\tMatched FS codec " << codec->iananame << " to OPAL media format " << switchFormat);\r
-\r
-#if IMPLEMENT_MULTI_FAME_AUDIO\r
-        // Did we match or create a new media format?\r
-        if (switchFormat.IsValid() && codec->codec_type == SWITCH_CODEC_TYPE_AUDIO) {\r
-            // Calculate frames per packet, do not use codec->codec_frames_per_packet as that field\r
-            // has slightly different semantics when used in streamed codecs such as G.711\r
-            int fpp = codec->samples_per_packet/switchFormat.GetFrameTime();\r
-\r
-            /* Set the frames/packet to maximum of what is in the FS table. The OPAL negotiations will\r
-               drop the value from there. This might fail if there are "holes" in the FS table, e.g.\r
-               if for some reason G.723.1 has 30ms and 90ms but not 60ms, then the OPAL negotiations\r
-               could end up with 60ms and the codec cannot be created. The "holes" are unlikely in\r
-               all but streamed codecs such as G.711, where it is theoretically possible for OPAL to\r
-               come up with 32ms and there is only 30ms and 40ms in the FS table. We deem these\r
-               scenarios sufficiently rare that we can safely ignore them ... for now. */\r
-\r
-            if (fpp > switchFormat.GetOptionInteger(OpalAudioFormat::RxFramesPerPacketOption())) {\r
-                switchFormat.SetOptionInteger(OpalAudioFormat::RxFramesPerPacketOption(), fpp);\r
-            }\r
-\r
-            if (fpp > switchFormat.GetOptionInteger(OpalAudioFormat::TxFramesPerPacketOption())) {\r
-                switchFormat.SetOptionInteger(OpalAudioFormat::TxFramesPerPacketOption(), fpp);\r
-            }\r
-        }\r
-#endif // IMPLEMENT_MULTI_FAME_AUDIO\r
-\r
-        m_switchMediaFormats += switchFormat;\r
-    }\r
-\r
-#if HAVE_T38\r
-    OpalMediaFormat t38 = OpalT38;\r
-\r
-    /* We need to have a T.38 options for TCS, but may be before the\r
-       spandsp_mod has set it us. So, if not, we actually give to spandsp_mod. */\r
-    switch_t38_options_t *t38_options = (switch_t38_options_t *)switch_channel_get_private(m_fsChannel, "t38_options");\r
-    if (t38_options == NULL)\r
-      SetT38OptionsFromMediaFormat(t38, "_preconfigured_t38_options");\r
-    else {\r
-      t38.SetOptionInteger("T38FaxVersion", t38_options->T38FaxVersion);\r
-      t38.SetOptionInteger("T38MaxBitRate", t38_options->T38MaxBitRate);\r
-      t38.SetOptionBoolean("T38FaxFillBitRemoval", t38_options->T38FaxFillBitRemoval);\r
-      t38.SetOptionBoolean("T38FaxTranscodingMMR", t38_options->T38FaxTranscodingMMR);\r
-      t38.SetOptionBoolean("T38FaxTranscodingJBIG", t38_options->T38FaxTranscodingJBIG);\r
-      t38.SetOptionValue("T38FaxRateManagement", t38_options->T38FaxRateManagement);\r
-      t38.SetOptionInteger("T38Version", t38_options->T38FaxMaxBuffer);\r
-      t38.SetOptionInteger("T38Version", t38_options->T38FaxMaxDatagram);\r
-      t38.SetOptionValue("T38FaxUdpEC", t38_options->T38FaxUdpEC);\r
-    }\r
-\r
-    m_switchMediaFormats += t38;\r
-#endif // HAVE_T38\r
-}\r
-\r
-\r
-OpalMediaStream *FSConnection::CreateMediaStream(const OpalMediaFormat & mediaFormat, unsigned sessionID, PBoolean isSource)\r
-{\r
-    return new FSMediaStream(*this, mediaFormat, sessionID, isSource);\r
-}\r
-\r
-\r
-void FSConnection::OnPatchMediaStream(PBoolean isSource, OpalMediaPatch & patch)\r
-{\r
-    OpalConnection::OnPatchMediaStream(isSource, patch);\r
-\r
-    if (PAssertNULL(m_fsChannel) == NULL)\r
-        return;\r
-\r
-    if (patch.GetSource().GetMediaFormat().GetMediaType() != OpalMediaType::Audio())\r
-        return;\r
-\r
-    if (switch_channel_direction(m_fsChannel) == SWITCH_CALL_DIRECTION_INBOUND) {\r
-        PTRACE(4, "mod_opal\tOnPatchMediaStream for inbound call, flagging media opened");\r
-        if (isSource)\r
-            m_rxAudioOpened.Signal();\r
-        else\r
-            m_txAudioOpened.Signal();\r
-    }\r
-    else {\r
-      PTRACE(4, "mod_opal\tOnPatchMediaStream for outbound call, checking media");\r
-      if (GetMediaStream(OpalMediaType::Audio(), !isSource) != NULL) {\r
-          // Have open media in both directions.\r
-          if (IsEstablished()) {\r
-              PTRACE(3, "mod_opal\tOnPatchMediaStream for outbound call, making call answered");\r
-              switch_channel_mark_answered(m_fsChannel);\r
-          }\r
-          else if (!IsReleased()) {\r
-              PTRACE(3, "mod_opal\tOnPatchMediaStream for outbound call, making call pre-answered");\r
-              switch_channel_mark_pre_answered(m_fsChannel);\r
-          }\r
-      }\r
-    }\r
-}\r
-\r
-\r
-switch_status_t FSConnection::on_init()\r
-{\r
-    if (PAssertNULL(m_fsChannel) == NULL)\r
-        return SWITCH_STATUS_FALSE;\r
-\r
-    PTRACE(4, "mod_opal\tStarted routing for connection " << *this);\r
-\r
-    return SWITCH_STATUS_SUCCESS;\r
-}\r
-\r
-\r
-switch_status_t FSConnection::on_routing()\r
-{\r
-    if (PAssertNULL(m_fsChannel) == NULL)\r
-        return SWITCH_STATUS_FALSE;\r
-\r
-    PTRACE(4, "mod_opal\tRouting connection " << *this);\r
-    return SWITCH_STATUS_SUCCESS;\r
-}\r
-\r
-\r
-switch_status_t FSConnection::on_execute()\r
-{\r
-    if (PAssertNULL(m_fsChannel) == NULL)\r
-        return SWITCH_STATUS_FALSE;\r
-\r
-    PTRACE(4, "mod_opal\tExecuting connection " << *this);\r
-    return SWITCH_STATUS_SUCCESS;\r
-}\r
-\r
-\r
-switch_status_t FSConnection::on_destroy()\r
-{\r
-    PTRACE(3, "mod_opal\tFS on_destroy for connection " << *this);\r
-\r
-    m_fsChannel = NULL; // Will be destroyed by FS, so don't use it any more.\r
-\r
-    switch_core_codec_destroy(&m_read_codec);\r
-    switch_core_codec_destroy(&m_write_codec);\r
-    switch_core_codec_destroy(&m_vid_read_codec);\r
-    switch_core_codec_destroy(&m_vid_write_codec);\r
-    switch_core_timer_destroy(&m_read_timer);\r
-    switch_core_timer_destroy(&m_vid_read_timer);\r
-\r
-    switch_core_session_set_private(m_fsSession, NULL);\r
-    SafeDereference();\r
-\r
-    return SWITCH_STATUS_SUCCESS;\r
-}\r
-\r
-\r
-switch_status_t FSConnection::on_hangup()\r
-{\r
-    if (PAssertNULL(m_fsChannel) == NULL)\r
-        return SWITCH_STATUS_FALSE;\r
-\r
-    /* if this is still here it was our idea to hangup not opal's */\r
-    ClearCallSynchronous(NULL, H323TranslateToCallEndReason(\r
-              (Q931::CauseValues)switch_channel_get_cause_q850(m_fsChannel), UINT_MAX));\r
-\r
-    return SWITCH_STATUS_SUCCESS;\r
-}\r
-\r
-\r
-switch_status_t FSConnection::on_exchange_media()\r
-{\r
-    PTRACE(4, "mod_opal\tExchanging media on connection " << *this);\r
-    return SWITCH_STATUS_SUCCESS;\r
-}\r
-\r
-\r
-switch_status_t FSConnection::on_soft_execute()\r
-{\r
-    PTRACE(4, "mod_opal\tSoft execute on connection " << *this);\r
-    return SWITCH_STATUS_SUCCESS;\r
-}\r
-\r
-\r
-switch_status_t FSConnection::kill_channel(int sig)\r
-{\r
-    switch (sig) {\r
-    case SWITCH_SIG_KILL:\r
-        PTRACE(4, "mod_opal\tSignal KILL received on connection " << *this);\r
-        m_rxAudioOpened.Signal();\r
-        m_txAudioOpened.Signal();\r
-        CloseMediaStreams();\r
-        break;\r
-\r
-    case SWITCH_SIG_BREAK:\r
-        PTRACE(4, "mod_opal\tSignal BREAK received on connection " << *this);\r
-        break;\r
-\r
-    default:\r
-        PTRACE(4, "mod_opal\tSignal " << sig << " received on connection " << *this);\r
-        break;\r
-    }\r
-\r
-    return SWITCH_STATUS_SUCCESS;\r
-}\r
-\r
-\r
-switch_status_t FSConnection::send_dtmf(const switch_dtmf_t *dtmf)\r
-{\r
-    PTRACE(4, "mod_opal\tReceived DTMF from FS: tone=" << dtmf->digit << ", duration=" << dtmf->duration);\r
-    OnUserInputTone(dtmf->digit, dtmf->duration);\r
-    return SWITCH_STATUS_SUCCESS;\r
-}\r
-\r
-\r
-switch_status_t FSConnection::receive_message(switch_core_session_message_t *msg)\r
-{\r
-    if (PAssertNULL(m_fsChannel) == NULL)\r
-        return SWITCH_STATUS_FALSE;\r
-\r
-    switch (msg->message_id) {\r
-    case SWITCH_MESSAGE_INDICATE_RINGING:\r
-    case SWITCH_MESSAGE_INDICATE_PROGRESS:\r
-    case SWITCH_MESSAGE_INDICATE_ANSWER:\r
-    case SWITCH_MESSAGE_INDICATE_DEFLECT:\r
-        if (switch_channel_direction(m_fsChannel) == SWITCH_CALL_DIRECTION_INBOUND) {\r
-            switch_caller_profile_t * profile = switch_channel_get_caller_profile(m_fsChannel);\r
-            if (profile != NULL && profile->caller_extension != NULL)\r
-            {\r
-                PSafePtr<OpalConnection> other = GetOtherPartyConnection();\r
-                if (other != NULL) {\r
-                    other->SetLocalPartyName(profile->caller_extension->extension_number);\r
-                    other->SetDisplayName(profile->caller_extension->extension_name);\r
-                }\r
-                SetLocalPartyName(profile->caller_extension->extension_number);\r
-                SetDisplayName(profile->caller_extension->extension_name);\r
-            }\r
-        }\r
-        else {\r
-            return SWITCH_STATUS_FALSE;\r
-        }\r
-        break;\r
-\r
-    default:\r
-        break;\r
-    }\r
-\r
-    switch (msg->message_id) {\r
-    case SWITCH_MESSAGE_INDICATE_BRIDGE:\r
-    case SWITCH_MESSAGE_INDICATE_UNBRIDGE:\r
-    case SWITCH_MESSAGE_INDICATE_AUDIO_SYNC:\r
-        m_flushAudio = true;\r
-        break;\r
-\r
-    case SWITCH_MESSAGE_INDICATE_RINGING:\r
-        AlertingIncoming();\r
-        break;\r
-\r
-    case SWITCH_MESSAGE_INDICATE_PROGRESS:\r
-        AutoStartMediaStreams();\r
-        AlertingIncoming();\r
-\r
-        if (!WaitForMedia())\r
-            return SWITCH_STATUS_FALSE;\r
-\r
-        if (!switch_channel_test_flag(m_fsChannel, CF_EARLY_MEDIA)) {\r
-            switch_channel_mark_pre_answered(m_fsChannel);\r
-        }\r
-        break;\r
-\r
-    case SWITCH_MESSAGE_INDICATE_ANSWER:\r
-        AcceptIncoming();\r
-\r
-        if (!WaitForMedia())\r
-            return SWITCH_STATUS_FALSE;\r
-\r
-        if (!switch_channel_test_flag(m_fsChannel, CF_ANSWERED)) {\r
-            switch_channel_mark_answered(m_fsChannel);\r
-        }\r
-        break;\r
-\r
-    case SWITCH_MESSAGE_INDICATE_DEFLECT:\r
-        ownerCall.Transfer(msg->string_arg, GetOtherPartyConnection());\r
-        break;\r
-\r
-#if HAVE_T38\r
-    case SWITCH_MESSAGE_INDICATE_REQUEST_IMAGE_MEDIA:\r
-      {\r
-        PTRACE(2, "mod_opal\tRequesting switch to T.38");\r
-        PSafePtr<OpalConnection> other = GetOtherPartyConnection();\r
-        if (other != NULL && other->SwitchFaxMediaStreams(true))\r
-            switch_channel_set_flag(m_fsChannel, CF_REQ_MEDIA);\r
-        else {\r
-            PTRACE(1, "mod_opal\tMode change request to T.38 failed");\r
-        }\r
-        break;\r
-      }\r
-\r
-    case SWITCH_MESSAGE_INDICATE_T38_DESCRIPTION:\r
-        PTRACE(2, "mod_opal\tSWITCH_MESSAGE_INDICATE_T38_DESCRIPTION");\r
-        break;\r
-\r
-    case SWITCH_MESSAGE_INDICATE_UDPTL_MODE:\r
-        PTRACE(2, "mod_opal\tSWITCH_MESSAGE_INDICATE_UDPTL_MODE");\r
-        m_udptl = true;\r
-        break;\r
-#endif // HAVE_T38\r
-\r
-    default:\r
-        PTRACE(3, "mod_opal\tReceived unhandled message " << msg->message_id << " on connection " << *this);\r
-    }\r
-\r
-    return SWITCH_STATUS_SUCCESS;\r
-}\r
-\r
-\r
-bool FSConnection::WaitForMedia()\r
-{\r
-    PTRACE(4, "mod_opal\tAwaiting media start on connection " << *this);\r
-    m_rxAudioOpened.Wait();\r
-    m_txAudioOpened.Wait();\r
-\r
-    if (IsReleased()) {\r
-        // Call got aborted\r
-        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(m_fsSession), SWITCH_LOG_ERROR, "Call abandoned!\n");\r
-        return false;\r
-    }\r
-\r
-    PTRACE(3, "mod_opal\tMedia started on connection " << *this);\r
-    return true;\r
-}\r
-\r
-\r
-#if HAVE_T38\r
-void FSConnection::SetT38OptionsFromMediaFormat(const OpalMediaFormat & mediaFormat, const char * varname)\r
-{\r
-    switch_t38_options_t *t38_options = (switch_t38_options_t *)switch_channel_get_private(m_fsChannel, varname);\r
-    if (t38_options == NULL)\r
-      t38_options = (switch_t38_options_t *)switch_core_session_alloc(m_fsSession, sizeof(switch_t38_options_t));\r
-\r
-    PString value;\r
-    mediaFormat.GetOptionValue("T38FaxRateManagement", value);\r
-    t38_options->T38FaxRateManagement = switch_core_session_strdup(m_fsSession, value);\r
-\r
-    mediaFormat.GetOptionValue("T38FaxUdpEC", value);\r
-    t38_options->T38FaxUdpEC = switch_core_session_strdup(m_fsSession, value);\r
-\r
-    t38_options->T38MaxBitRate = mediaFormat.GetOptionInteger("T38MaxBitRate", 9600);\r
-    t38_options->T38FaxMaxBuffer = mediaFormat.GetOptionInteger("T38FaxMaxBuffer", 2000);\r
-    t38_options->T38FaxMaxDatagram = mediaFormat.GetOptionInteger("T38FaxMaxDatagram", 528);\r
-\r
-    t38_options->T38FaxFillBitRemoval = mediaFormat.GetOptionBoolean("T38FaxFillBitRemoval") ? SWITCH_TRUE : SWITCH_FALSE;\r
-    t38_options->T38FaxTranscodingMMR = mediaFormat.GetOptionBoolean("T38FaxTranscodingMMR") ? SWITCH_TRUE : SWITCH_FALSE;\r
-    t38_options->T38FaxTranscodingJBIG = mediaFormat.GetOptionBoolean("T38FaxTranscodingJBIG") ? SWITCH_TRUE : SWITCH_FALSE;\r
-\r
-    t38_options->T38VendorInfo = switch_core_session_strdup(m_fsSession, mediaFormat.GetOptionString("T38VendorInfo"));\r
-\r
-    //t38_options->remote_ip = switch_core_session_strdup(session, mediaFormat.something);\r
-    //t38_options->remote_port = mediaFormat.something;\r
-\r
-    switch_channel_set_private(m_fsChannel, varname, t38_options);\r
-    PTRACE(3, "mod_opal\tSet " << varname);\r
-}\r
-\r
-\r
-void FSConnection::OnSwitchedT38(bool toT38, bool success)\r
-{\r
-    if (toT38 && success && IndicateSwitchedT38()) {\r
-        PTRACE(3, "mod_opal\tMode change request to T.38 succeeded");\r
-    }\r
-    else {\r
-        AbortT38();\r
-    }\r
-}\r
-\r
-\r
-void FSConnection::OnSwitchingT38(bool toT38)\r
-{\r
-    if (toT38 && IndicateSwitchedT38()) {\r
-        PTRACE(3, "mod_opal\tMode change request to T.38 started");\r
-    }\r
-    else {\r
-      AbortT38();\r
-    }\r
-}\r
-\r
-\r
-void FSConnection::AbortT38()\r
-{\r
-    PTRACE(3, "mod_opal\tMode change request to T.38 failed");\r
-    switch_channel_set_private(m_fsChannel, "t38_options", NULL);\r
-    switch_channel_clear_app_flag_key("T38", m_fsChannel, CF_APP_T38);\r
-    switch_channel_clear_app_flag_key("T38", m_fsChannel, CF_APP_T38_REQ);\r
-    switch_channel_set_app_flag_key("T38", m_fsChannel, CF_APP_T38_FAIL);\r
-}\r
-\r
-\r
-bool FSConnection::IndicateSwitchedT38()\r
-{\r
-    PSafePtr<OpalConnection> other = GetOtherPartyConnection();\r
-    if (other == NULL) {\r
-        PTRACE(3, "mod_opal\tCan't change to T.38, no other connection");\r
-        return false;\r
-    }\r
-\r
-    OpalMediaFormatList otherFormats = other->GetMediaFormats();\r
-    OpalMediaFormatList::const_iterator t38 = otherFormats.FindFormat(OpalT38);\r
-    if (t38 == otherFormats.end()) {\r
-        PTRACE(3, "mod_opal\tCan't change to T.38, no remote capability");\r
-        return false;\r
-    }\r
-\r
-    SetT38OptionsFromMediaFormat(*t38, "t38_options");\r
-\r
-    switch_channel_set_variable(m_fsChannel, "has_t38", "true");\r
-    switch_channel_set_app_flag_key("T38", m_fsChannel, CF_APP_T38);\r
-\r
-    switch_channel_execute_on(m_fsChannel, "opal_execute_on_t38");\r
-    switch_channel_api_on(m_fsChannel, "opal_api_on_t38");\r
-    return true;\r
-}\r
-#endif // HAVE_T38\r
-\r
-\r
-switch_status_t FSConnection::receive_event(switch_event_t *event)\r
-{\r
-    PTRACE(4, "mod_opal\tReceived event " << event->event_id << " on connection " << *this);\r
-    return SWITCH_STATUS_SUCCESS;\r
-}\r
-\r
-\r
-switch_status_t FSConnection::state_change()\r
-{\r
-    PTRACE(4, "mod_opal\tState changed on connection " << *this);\r
-    return SWITCH_STATUS_SUCCESS;\r
-}\r
-\r
-\r
-switch_status_t FSConnection::read_audio_frame(switch_frame_t **frame, switch_io_flag_t flags, int stream_id)\r
-{\r
-    return read_frame(m_udptl ? OpalMediaType::Fax() : OpalMediaType::Audio(), frame, flags);\r
-}\r
-\r
-\r
-switch_status_t FSConnection::write_audio_frame(switch_frame_t *frame, switch_io_flag_t flags, int stream_id)\r
-{\r
-    return write_frame(m_udptl ? OpalMediaType::Fax() : OpalMediaType::Audio(), frame, flags);\r
-}\r
-\r
-\r
-switch_status_t FSConnection::read_video_frame(switch_frame_t **frame, switch_io_flag_t flag, int stream_id)\r
-{\r
-    return read_frame(OpalMediaType::Video(), frame, flag);\r
-}\r
-\r
-\r
-switch_status_t FSConnection::write_video_frame(switch_frame_t *frame, switch_io_flag_t flag, int stream_id)\r
-{\r
-    return write_frame(OpalMediaType::Video(), frame, flag);\r
-}\r
-\r
-\r
-switch_status_t FSConnection::read_frame(const OpalMediaType & mediaType, switch_frame_t **frame, switch_io_flag_t flags)\r
-{\r
-    if (!ownerCall.IsSwitchingT38()) {\r
-        PSafePtr <FSMediaStream> stream = PSafePtrCast <OpalMediaStream, FSMediaStream>(GetMediaStream(mediaType, false));\r
-        if (stream != NULL)\r
-            return stream->read_frame(frame, flags);\r
-\r
-        PTRACE(2, "mod_opal\tNo stream for read of " << mediaType);\r
-    }\r
-\r
-    // Avoid all the channel closing and re-opening, especially with faxa switching, upsetting FS\r
-    *frame = &m_dummy_frame;\r
-    return SWITCH_STATUS_SUCCESS;\r
-}\r
-\r
-\r
-switch_status_t FSConnection::write_frame(const OpalMediaType & mediaType, const switch_frame_t *frame, switch_io_flag_t flags)\r
-{\r
-    // Avoid all the channel closing and re-opening, especially with faxa switching, upsetting FS\r
-    if (ownerCall.IsSwitchingT38())\r
-      return SWITCH_STATUS_SUCCESS;\r
-\r
-    PSafePtr <FSMediaStream> stream = PSafePtrCast<OpalMediaStream, FSMediaStream>(GetMediaStream(mediaType, true));\r
-    if (stream != NULL)\r
-      return stream->write_frame(frame, flags);\r
-\r
-    PTRACE(2, "mod_opal\tNo stream for write of " << mediaType);\r
-    return SWITCH_STATUS_SUCCESS;\r
-}\r
-\r
-\r
-///////////////////////////////////////////////////////////////////////\r
-\r
-FSMediaStream::FSMediaStream(FSConnection & conn, const OpalMediaFormat & mediaFormat, unsigned sessionID, bool isSource)\r
-    : OpalMediaStream(conn, mediaFormat, sessionID, isSource)\r
-    , m_connection(conn)\r
-    , m_switchTimer(NULL)\r
-    , m_switchCodec(NULL)\r
-    , m_readRTP(0, SWITCH_RECOMMENDED_BUFFER_SIZE)\r
-{\r
-    memset(&m_readFrame, 0, sizeof(m_readFrame));\r
-}\r
-\r
-\r
-PBoolean FSMediaStream::Open()\r
-{\r
-    if (IsOpen()) {\r
-        return true;\r
-    }\r
-\r
-    switch_core_session_t *fsSession = m_connection.GetSession();\r
-    switch_channel_t *fsChannel = m_connection.GetChannel();\r
-    if (PAssertNULL(fsSession) == NULL || PAssertNULL(fsChannel) == NULL)\r
-        return false;\r
-\r
-    bool isAudio;\r
-    OpalMediaType mediaType = mediaFormat.GetMediaType();\r
-    if (mediaType == OpalMediaType::Audio())\r
-        isAudio = true;\r
-    else if (mediaType == OpalMediaType::Video())\r
-        isAudio = false;\r
-#if HAVE_T38\r
-    else if (mediaType == OpalMediaType::Fax()) {\r
-        m_readFrame.flags = SFF_UDPTL_PACKET|SFF_PROXY_PACKET;\r
-        return OpalMediaStream::Open();\r
-    }\r
-#endif\r
-    else {\r
-        PTRACE(1, "mod_opal\tUnsupported media type: " << mediaType);\r
-        return false;\r
-    }\r
-\r
-    int ptime = mediaFormat.GetOptionInteger(OpalAudioFormat::TxFramesPerPacketOption()) * mediaFormat.GetFrameTime() / mediaFormat.GetTimeUnits();\r
-\r
-    if (IsSink()) {\r
-        m_switchCodec = isAudio ? &m_connection.m_read_codec : &m_connection.m_vid_read_codec;\r
-        m_switchTimer = isAudio ? &m_connection.m_read_timer : &m_connection.m_vid_read_timer;\r
-        m_readFrame.codec = m_switchCodec;\r
-        m_readFrame.rate = mediaFormat.GetClockRate();\r
-    } else {\r
-        m_switchCodec = isAudio ? &m_connection.m_write_codec : &m_connection.m_vid_write_codec;\r
-    }\r
-\r
-    // The following is performed on two different instances of this object.\r
-    if (switch_core_codec_init(m_switchCodec, mediaFormat.GetEncodingName(), NULL, // FMTP\r
-                               mediaFormat.GetClockRate(), ptime, 1,  // Channels\r
-                               SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL,   // Settings\r
-                               switch_core_session_get_pool(fsSession)) != SWITCH_STATUS_SUCCESS) {\r
-        // Could not select a codecs using negotiated frames/packet, so try using default.\r
-        if (switch_core_codec_init(m_switchCodec, mediaFormat.GetEncodingName(), NULL, // FMTP\r
-                                   mediaFormat.GetClockRate(), 0, 1,  // Channels\r
-                                   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL,   // Settings\r
-                                   switch_core_session_get_pool(fsSession)) != SWITCH_STATUS_SUCCESS) {\r
-            PTRACE(1, "mod_opal\t" << switch_channel_get_name(fsChannel)\r
-                   << " cannot initialise " << (IsSink()? "read" : "write") << ' '\r
-                   << mediaType << " codec " << mediaFormat << " for connection " << *this);\r
-            switch_channel_hangup(fsChannel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);\r
-            return false;\r
-        }\r
-        PTRACE(2, "mod_opal\t" << switch_channel_get_name(fsChannel)\r
-               << " unsupported ptime of " << ptime << " on " << (IsSink()? "read" : "write") << ' '\r
-               << mediaType << " codec " << mediaFormat << " for connection " << *this);\r
-    }\r
-\r
-    if (IsSink()) {\r
-        if (isAudio) {\r
-            switch_core_session_set_read_codec(fsSession, m_switchCodec);\r
-            if (switch_core_timer_init(m_switchTimer,\r
-                                       "soft",\r
-                                       m_switchCodec->implementation->microseconds_per_packet / 1000,\r
-                                       m_switchCodec->implementation->samples_per_packet,\r
-                                       switch_core_session_get_pool(fsSession)) != SWITCH_STATUS_SUCCESS) {\r
-                PTRACE(1, "mod_opal\t" << switch_channel_get_name(fsChannel)\r
-                       << " timer init failed on " << (IsSink()? "read" : "write") << ' '\r
-                       << mediaType << " codec " << mediaFormat << " for connection " << *this);\r
-                switch_core_codec_destroy(m_switchCodec);\r
-                m_switchCodec = NULL;\r
-                return false;\r
-            }\r
-        } else {\r
-            switch_core_session_set_video_read_codec(fsSession, m_switchCodec);\r
-            switch_channel_set_flag(fsChannel, CF_VIDEO);\r
-        }\r
-    } else {\r
-        if (isAudio) {\r
-            switch_core_session_set_write_codec(fsSession, m_switchCodec);\r
-        } else {\r
-            switch_core_session_set_video_write_codec(fsSession, m_switchCodec);\r
-            switch_channel_set_flag(fsChannel, CF_VIDEO);\r
-        }\r
-    }\r
-\r
-    PTRACE(3, "mod_opal\t" << switch_channel_get_name(fsChannel)\r
-           << " initialised " << (IsSink()? "read" : "write") << ' '\r
-           << mediaType << " codec " << mediaFormat << " for connection " << *this);\r
-\r
-    return OpalMediaStream::Open();\r
-}\r
-\r
-\r
-void FSMediaStream::InternalClose()\r
-{\r
-}\r
-\r
-\r
-PBoolean FSMediaStream::IsSynchronous() const\r
-{\r
-    return true;\r
-}\r
-\r
-\r
-PBoolean FSMediaStream::RequiresPatchThread(OpalMediaStream *) const\r
-{\r
-    return false;\r
-}\r
-\r
-\r
-int FSMediaStream::StartReadWrite(PatchPtr & mediaPatch) const\r
-{\r
-    if (!IsOpen()) {\r
-        PTRACE(1, "mod_opal\tNot open!");\r
-        return -1;\r
-    }\r
-\r
-    if (!m_connection.IsChannelReady()) {\r
-        PTRACE(1, "mod_opal\tChannel not ready!");\r
-        return -1;\r
-    }\r
-\r
-    // We make referenced copy of pointer so can't be deleted out from under us\r
-    mediaPatch = m_mediaPatch;\r
-    if (mediaPatch == NULL) {\r
-        /*There is a race here... sometimes we make it here and m_mediaPatch is NULL\r
-          if we wait it shows up in 1ms, maybe there is a better way to wait. */\r
-        PTRACE(2, "mod_opal\tPatch not ready!");\r
-        return 1;\r
-    }\r
-\r
-    return 0;\r
-}\r
-\r
-\r
-switch_status_t FSMediaStream::read_frame(switch_frame_t **frame, switch_io_flag_t flags)\r
-{\r
-    *frame = &m_readFrame;\r
-    m_readFrame.flags |= SFF_CNG;\r
-\r
-    PatchPtr mediaPatch;\r
-    switch (StartReadWrite(mediaPatch)) {\r
-      case -1 :\r
-        return SWITCH_STATUS_FALSE;\r
-      case 1 :\r
-        return SWITCH_STATUS_SUCCESS;\r
-    }\r
-\r
-    if (m_connection.NeedFlushAudio()) {\r
-        mediaPatch->GetSource().EnableJitterBuffer(); // This flushes data and resets jitter buffer\r
-        m_readRTP.SetPayloadSize(0);\r
-    } else {\r
-        if (m_switchCodec != NULL) {\r
-            m_readRTP.SetTimestamp(m_readFrame.timestamp + m_switchCodec->implementation->samples_per_packet);\r
-        }\r
-\r
-        if (!mediaPatch->GetSource().ReadPacket(m_readRTP)) {\r
-            PTRACE(1, "mod_opal\tread_frame: no source data!");\r
-            return SWITCH_STATUS_FALSE;\r
-        }\r
-    }\r
-\r
-    if (m_switchTimer != NULL) {\r
-        switch_core_timer_next(m_switchTimer);\r
-    }\r
-\r
-    if (m_switchCodec != NULL) {\r
-        if (!switch_core_codec_ready(m_switchCodec)) {\r
-            PTRACE(1, "mod_opal\tread_frame: codec not ready!");\r
-            return SWITCH_STATUS_FALSE;\r
-        }\r
-    }\r
-\r
-    if (switch_test_flag(&m_readFrame, SFF_UDPTL_PACKET)) {\r
-        m_readFrame.flags    &= ~SFF_CNG;\r
-        m_readFrame.packet    = m_readRTP.GetPayloadPtr();\r
-        m_readFrame.packetlen = m_readRTP.GetPayloadSize();\r
-        return SWITCH_STATUS_SUCCESS;\r
-    }\r
-\r
-    if (switch_test_flag(&m_readFrame, SFF_RAW_RTP)) {\r
-        m_readFrame.flags    &= ~SFF_CNG;\r
-        m_readFrame.packet    = m_readRTP.GetPointer();\r
-        m_readFrame.packetlen = m_readRTP.GetHeaderSize() + m_readRTP.GetPayloadSize();\r
-        return SWITCH_STATUS_SUCCESS;\r
-    }\r
-\r
-#if IMPLEMENT_MULTI_FAME_AUDIO\r
-    // Repackage frames in incoming packet to agree with what FS expects.\r
-    // Not implmented yet!!!!!!!!!\r
-    // Cheating and only supporting one frame per packet\r
-#endif\r
-\r
-    m_readFrame.buflen    = m_readRTP.GetSize();\r
-    m_readFrame.data      = m_readRTP.GetPayloadPtr();\r
-    m_readFrame.datalen   = m_readRTP.GetPayloadSize();\r
-    m_readFrame.timestamp = m_readRTP.GetTimestamp();\r
-    m_readFrame.seq       = m_readRTP.GetSequenceNumber();\r
-    m_readFrame.ssrc      = m_readRTP.GetSyncSource();\r
-    m_readFrame.m         = m_readRTP.GetMarker() ? SWITCH_TRUE : SWITCH_FALSE;\r
-    m_readFrame.payload   = (switch_payload_t)m_readRTP.GetPayloadType();\r
-\r
-    if (m_readFrame.datalen > 0 &&\r
-        m_readFrame.payload != RTP_DataFrame::CN &&\r
-        m_readFrame.payload != RTP_DataFrame::Cisco_CN) {\r
-        m_readFrame.flags &= ~SFF_CNG;\r
-    }\r
-\r
-    return SWITCH_STATUS_SUCCESS;\r
-}\r
-\r
-\r
-switch_status_t FSMediaStream::write_frame(const switch_frame_t *frame, switch_io_flag_t flags)\r
-{\r
-    PatchPtr mediaPatch;\r
-    switch (StartReadWrite(mediaPatch)) {\r
-      case -1 :\r
-        return SWITCH_STATUS_FALSE;\r
-      case 1 :\r
-        return SWITCH_STATUS_SUCCESS;\r
-    }\r
-\r
-    RTP_DataFrame rtp;\r
-    if (switch_test_flag(frame, SFF_RAW_RTP)) {\r
-        rtp = RTP_DataFrame((const BYTE *)frame->packet, frame->packetlen, false);\r
-    }\r
-    else if (switch_test_flag(frame, SFF_UDPTL_PACKET)) {\r
-        rtp.SetPayloadSize(frame->packetlen);\r
-        memcpy(rtp.GetPayloadPtr(), frame->packet, frame->packetlen);\r
-    }\r
-    else {\r
-        rtp.SetPayloadSize(frame->datalen);\r
-        memcpy(rtp.GetPayloadPtr(), frame->data, frame->datalen);\r
-\r
-        rtp.SetPayloadType(mediaFormat.GetPayloadType());\r
-\r
-        /* Not sure what FS is going to give us!\r
-           Suspect it depends on the mod on the other side sending it. */\r
-        if (frame->timestamp != 0)\r
-            timestamp = frame->timestamp;\r
-        else if (frame->samples != 0)\r
-            timestamp += frame->samples;\r
-        else if (m_switchCodec != NULL)\r
-            timestamp += m_switchCodec->implementation->samples_per_packet;\r
-        rtp.SetTimestamp(timestamp);\r
-    }\r
-\r
-    if (mediaPatch->PushFrame(rtp))\r
-      return SWITCH_STATUS_SUCCESS;\r
-\r
-    PTRACE(1, "mod_opal\tread_frame: push failed!");\r
-    return SWITCH_STATUS_FALSE;\r
-}\r
-\r
-\r
-/* For Emacs:\r
- * Local Variables:\r
- * mode:c\r
- * indent-tabs-mode:nil\r
- * tab-width:4\r
- * c-basic-offset:4\r
- * End:\r
- * For VIM:\r
- * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:s:\r
- */\r
+/* Opal endpoint interface for Freeswitch Modular Media Switching Software Library /
+ * Soft-Switch Application
+ *
+ * Version: MPL 1.1
+ *
+ * Copyright (c) 2007 Tuyan Ozipek (tuyanozipek@gmail.com)
+ * Copyright (c) 2008-2012 Vox Lucida Pty. Ltd. (robertj@voxlucida.com.au)
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Contributor(s):
+ * Tuyan Ozipek   (tuyanozipek@gmail.com)
+ * Lukasz Zwierko (lzwierko@gmail.com)
+ * Robert Jongbloed (robertj@voxlucida.com.au)
+ *
+ */
+
+#include "mod_opal.h"
+#include <opal/patch.h>
+#include <rtp/rtp.h>
+#if PTLIB_CHECK_VERSION(2,11,1)
+#include <rtp/rtp_session.h>
+#endif
+#include <h323/h323pdu.h>
+#include <h323/gkclient.h>
+
+
+/* FreeSWITCH does not correctly handle an H.323 subtely, that is that a
+   MAXIMUM audio frames per packet is negotiated, and there is no
+   requirement for the remote to actually send that many. So, in say GSM, we
+   negotiate up to 3 frames or 60ms of data and the remote actually sends one
+   (20ms) frame per packet. Perfectly legal but blows up the media handling
+   in FS.
+
+   Eventually we will get around to bundling the packets, but not yet. This
+   compile flag will just force one frame/packet for all audio codecs.
+ */
+#define IMPLEMENT_MULTI_FAME_AUDIO 0
+
+
+static switch_call_cause_t create_outgoing_channel(switch_core_session_t   *session,
+                                                   switch_event_t          *var_event,
+                                                   switch_caller_profile_t *outbound_profile,
+                                                   switch_core_session_t  **new_session,
+                                                   switch_memory_pool_t   **pool,
+                                                   switch_originate_flag_t  flags,
+                                                   switch_call_cause_t     *cancel_cause);
+
+
+static FSProcess *opal_process = NULL;
+
+
+static PConstString const ModuleName("opal");
+static char const ConfigFile[] = "opal.conf";
+#define FS_PREFIX "fs"
+
+
+static switch_io_routines_t opalfs_io_routines = {
+    /*.outgoing_channel */ create_outgoing_channel,
+    /*.read_frame */ FSConnection::read_audio_frame,
+    /*.write_frame */ FSConnection::write_audio_frame,
+    /*.kill_channel */ FSConnection::kill_channel,
+    /*.send_dtmf */ FSConnection::send_dtmf,
+    /*.receive_message */ FSConnection::receive_message,
+    /*.receive_event */ FSConnection::receive_event,
+    /*.state_change */ FSConnection::state_change,
+    /*.read_video_frame */ FSConnection::read_video_frame,
+    /*.write_video_frame */ FSConnection::write_video_frame
+};
+
+static switch_state_handler_table_t opalfs_event_handlers = {
+    /*.on_init */ FSConnection::on_init,
+    /*.on_routing */ FSConnection::on_routing,
+    /*.on_execute */ FSConnection::on_execute,
+    /*.on_hangup */ FSConnection::on_hangup,
+    /*.on_exchange_media */ FSConnection::on_exchange_media,
+    /*.on_soft_execute */ FSConnection::on_soft_execute,
+    /*.on_consume_media*/ NULL,
+    /*.on_hibernate*/ NULL,
+    /*.on_reset*/ NULL,
+    /*.on_park*/ NULL,
+    /*.on_reporting*/ NULL,
+    /*.on_destroy*/ FSConnection::on_destroy
+};
+
+
+SWITCH_BEGIN_EXTERN_C
+/*******************************************************************************/
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_opal_load);
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_opal_shutdown);
+SWITCH_MODULE_DEFINITION(mod_opal, mod_opal_load, mod_opal_shutdown, NULL);
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_opal_load)
+{
+    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Starting loading mod_opal\n");
+
+    /* Prevent the loading of OPAL codecs via "plug ins", this is a directory
+       full of DLLs that will be loaded automatically. */
+    (void)putenv((char *)"PTLIBPLUGINDIR=/no/thanks");
+
+
+    *module_interface = switch_loadable_module_create_module_interface(pool, modname);
+    if (!*module_interface) {
+        return SWITCH_STATUS_MEMERR;
+    }
+
+    opal_process = new FSProcess();
+    if (opal_process == NULL) {
+        return SWITCH_STATUS_MEMERR;
+    }
+
+    if (opal_process->Initialise(*module_interface)) {
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Opal manager initialized and running\n");
+        //unloading causes a seg in linux
+        //return SWITCH_STATUS_UNLOAD;
+        return SWITCH_STATUS_SUCCESS;
+    }
+
+    delete opal_process;
+    opal_process = NULL;
+    return SWITCH_STATUS_FALSE;
+}
+
+
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_opal_shutdown)
+{
+    delete opal_process;
+    opal_process = NULL;
+    return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_END_EXTERN_C
+/*******************************************************************************/
+
+///////////////////////////////////////////////////////////////////////
+
+#if PTRACING
+
+class FSTrace : public std::ostream
+{
+private:
+  class Buffer : public std::stringbuf
+  {
+    virtual int sync()
+    {
+      std::string s = str();
+      if (s.empty())
+        return 0;
+
+      //Due to explicit setting of flags we know exactly what we are getting
+  #define THREAD_ID_INDEX 2
+  #define FILE_NAME_INDEX 3
+  #define FILE_LINE_INDEX 4
+#if PTLIB_CHECK_VERSION(2,11,1)
+  #define CONTEXT_ID_REGEX "([0-9]+|- - - - - - -)\t"
+  #define LOG_PRINTF_FORMAT "{%s,%s} %s"
+  #define FULL_TEXT_INDEX 6
+#else
+  #define CONTEXT_ID_REGEX
+  #define LOG_PRINTF_FORMAT "{%s} %s"
+  #define FULL_TEXT_INDEX 5
+#endif
+      PStringArray fields(7);
+      static PRegularExpression logRE("^([0-9]+)\t *(.+)\t *([^(]+)\\(([0-9]+)\\)\t"CONTEXT_ID_REGEX"(.*)",
+                                      PRegularExpression::Extended);
+      if (!logRE.Execute(s.c_str(), fields)) {
+        fields[1] = "4";
+        fields[THREAD_ID_INDEX] = "unknown";
+        fields[FILE_NAME_INDEX] = __FILE__;
+        fields[FILE_LINE_INDEX] = __LINE__;
+        fields[FULL_TEXT_INDEX] = s;
+      }
+
+      switch_log_level_t level;
+      switch (fields[1].AsUnsigned()) {
+        case 0 :
+          level = SWITCH_LOG_ALERT;
+          break;
+        case 1 :
+          level = SWITCH_LOG_ERROR;
+          break;
+        case 2 :
+          level = SWITCH_LOG_WARNING;
+          break;
+        case 3 :
+          level = SWITCH_LOG_INFO;
+          break;
+        default :
+          level = SWITCH_LOG_DEBUG;
+          break;
+      }
+
+      fields[4].Replace("\t", " ", true);
+#if PTLIB_CHECK_VERSION(2,11,1)
+      fields[5].Replace("- - - - - - -", "-"),
+#endif
+      switch_log_printf(SWITCH_CHANNEL_ID_LOG,
+                        fields[FILE_NAME_INDEX],
+                        "PTLib-OPAL",
+                        fields[FILE_LINE_INDEX].AsUnsigned(),
+                        NULL,
+                        level,
+                        LOG_PRINTF_FORMAT,
+                        fields[THREAD_ID_INDEX].GetPointer(),
+#if PTLIB_CHECK_VERSION(2,11,1)
+                        fields[5].GetPointer(),
+#endif
+                        fields[FULL_TEXT_INDEX].GetPointer());
+
+      // Reset string
+      str(std::string());
+      return 0;
+    }
+  } buffer;
+
+public:
+  FSTrace()
+    : ostream(&buffer)
+  {
+  }
+};
+
+#endif // PTRACING
+
+
+///////////////////////////////////////////////////////////////////////
+
+FSProcess::FSProcess()
+  : PLibraryProcess("Vox Lucida Pty. Ltd.", MODNAME, 1, 1, BetaCode, 1)
+  , m_manager(NULL)
+{
+}
+
+
+FSProcess::~FSProcess()
+{
+  delete m_manager;
+#if PTRACING
+    PTrace::SetStream(NULL); // This will delete the FSTrace object
+#endif
+}
+
+
+bool FSProcess::Initialise(switch_loadable_module_interface_t *iface)
+{
+    m_manager = new FSManager();
+    return m_manager != NULL && m_manager->Initialise(iface);
+}
+
+
+///////////////////////////////////////////////////////////////////////
+
+FSManager::FSManager()
+  : m_context("default")
+  , m_dialplan("XML")
+{
+    // These are deleted by the OpalManager class, no need to have destructor
+    m_h323ep = new H323EndPoint(*this);
+    m_iaxep = new IAX2EndPoint(*this);
+    m_fsep = new FSEndPoint(*this);
+}
+
+
+bool FSManager::Initialise(switch_loadable_module_interface_t *iface)
+{
+    ReadConfig(false);
+
+    m_FreeSwitch = (switch_endpoint_interface_t *) switch_loadable_module_create_interface(iface, SWITCH_ENDPOINT_INTERFACE);
+    m_FreeSwitch->interface_name = ModuleName;
+    m_FreeSwitch->io_routines = &opalfs_io_routines;
+    m_FreeSwitch->state_handler = &opalfs_event_handlers;
+
+    silenceDetectParams.m_mode = OpalSilenceDetector::NoSilenceDetection;
+
+    if (m_listeners.empty()) {
+        m_h323ep->StartListener("");
+    } else {
+        for (std::list < FSListener >::iterator it = m_listeners.begin(); it != m_listeners.end(); ++it) {
+            if (!m_h323ep->StartListener(OpalTransportAddress(it->m_address, it->m_port))) {
+                PTRACE(2, "mod_opal\tCannot start listener for " << it->m_name);
+            }
+        }
+    }
+
+    AddRouteEntry("h323:.* = "FS_PREFIX":<da>");  // config option for direct routing
+    AddRouteEntry("iax2:.* = "FS_PREFIX":<da>");  // config option for direct routing
+    AddRouteEntry(FS_PREFIX":.* = h323:<da>");  // config option for direct routing
+
+    // Make sure all known codecs are instantiated,
+    // these are ones we know how to translate into H.323 capabilities
+    GetOpalG728();
+    GetOpalG729();
+    GetOpalG729A();
+    GetOpalG729B();
+    GetOpalG729AB();
+    GetOpalG7231_6k3();
+    GetOpalG7231_5k3();
+    GetOpalG7231A_6k3();
+    GetOpalG7231A_5k3();
+    GetOpalGSM0610();
+    GetOpalGSMAMR();
+    GetOpaliLBC();
+
+#if !IMPLEMENT_MULTI_FAME_AUDIO
+    OpalMediaFormatList allCodecs = OpalMediaFormat::GetAllRegisteredMediaFormats();
+    for (OpalMediaFormatList::iterator it = allCodecs.begin(); it != allCodecs.end(); ++it) {
+      if (it->GetMediaType() == OpalMediaType::Audio()) {
+        int ms_per_frame = it->GetFrameTime()/it->GetTimeUnits();
+        int frames_in_20_ms = (ms_per_frame+19)/ms_per_frame;
+        it->SetOptionInteger(OpalAudioFormat::RxFramesPerPacketOption(), frames_in_20_ms);
+        it->SetOptionInteger(OpalAudioFormat::TxFramesPerPacketOption(), frames_in_20_ms);
+        OpalMediaFormat::SetRegisteredMediaFormat(*it);
+        PTRACE(4, "mod_opal\tSet " << *it << " to " << frames_in_20_ms << "frames/packet");
+      }
+    }
+#endif // IMPLEMENT_MULTI_FAME_AUDIO
+
+    OpalMediaFormat t38 = OpalT38;
+    t38.SetOptionBoolean("UDPTL-Raw-Mode", true);
+    OpalMediaFormat::SetRegisteredMediaFormat(t38);
+
+    if (!m_gkAddress.IsEmpty()) {
+      if (m_h323ep->UseGatekeeper(m_gkAddress, m_gkIdentifer, m_gkInterface))
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Started gatekeeper: %s\n",
+                          (const char *)m_h323ep->GetGatekeeper()->GetName());
+      else
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
+                          "Could not start gatekeeper: addr=\"%s\", id=\"%s\", if=\"%s\"\n",
+                          (const char *)m_gkAddress,
+                          (const char *)m_gkIdentifer,
+                          (const char *)m_gkInterface);
+    }
+
+    return TRUE;
+}
+
+
+switch_status_t FSManager::ReadConfig(int reload)
+{
+    switch_event_t *request_params = NULL;
+    switch_event_create(&request_params, SWITCH_EVENT_REQUEST_PARAMS);
+    switch_assert(request_params);
+    switch_event_add_header_string(request_params, SWITCH_STACK_BOTTOM, "profile", switch_str_nil(""));
+
+    switch_xml_t cfg;
+    switch_xml_t xml = switch_xml_open_cfg(ConfigFile, &cfg, request_params);
+    if (xml == NULL) {
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", ConfigFile);
+        return SWITCH_STATUS_FALSE;
+    }
+
+    switch_xml_t xmlSettings = switch_xml_child(cfg, "settings");
+    if (xmlSettings) {
+        for (switch_xml_t xmlParam = switch_xml_child(xmlSettings, "param"); xmlParam != NULL; xmlParam = xmlParam->next) {
+            PConstCaselessString const var(switch_xml_attr_soft(xmlParam, "name"));
+            PConstString const val(switch_xml_attr_soft(xmlParam, "value"));
+
+            if (var == "context") {
+                m_context = val;
+            } else if (var == "dialplan") {
+                m_dialplan = val;
+            } else if (var == "codec-prefs") {
+                m_codecPrefs = val;
+            } else if (var == "disable-transcoding") {
+                m_disableTranscoding = switch_true(val);
+            } else if (var == "dtmf-type") {
+                if (val == "string")
+                  m_h323ep->SetSendUserInputMode(OpalConnection::SendUserInputAsString);
+                else if (val == "signal")
+                  m_h323ep->SetSendUserInputMode(OpalConnection::SendUserInputAsTone);
+                else if (val == "rfc2833")
+                  m_h323ep->SetSendUserInputMode(OpalConnection::SendUserInputAsRFC2833);
+                else if (val == "in-band")
+                  m_h323ep->SetSendUserInputMode(OpalConnection::SendUserInputInBand);
+            } else if (var == "jitter-size") {
+                SetAudioJitterDelay(val.AsUnsigned(), val.Mid(val.Find(',')+1).AsUnsigned()); // In milliseconds
+            } else if (var == "gk-address") {
+                m_gkAddress = val;
+            } else if (var == "gk-identifer") {
+                m_gkIdentifer = val;
+            } else if (var == "gk-interface") {
+                m_gkInterface = val;
+#if PTRACING
+            } else if (var == "trace-level") {
+                unsigned level = val.AsUnsigned();
+                if (level > 0) {
+                    PTrace::SetLevel(level);
+                    PTrace::ClearOptions(0xffffffff); // Everything off
+                    PTrace::SetOptions(               // Except these
+                      PTrace::TraceLevel|PTrace::FileAndLine|PTrace::Thread
+#if PTLIB_CHECK_VERSION(2,11,1)
+                      |PTrace::ContextIdentifier
+#endif
+                    );
+                    PTrace::SetStream(new FSTrace);
+                }
+#endif
+            }
+        }
+    }
+
+    switch_xml_t xmlListeners = switch_xml_child(cfg, "listeners");
+    if (xmlListeners != NULL) {
+        for (switch_xml_t xmlListener = switch_xml_child(xmlListeners, "listener"); xmlListener != NULL; xmlListener = xmlListener->next) {
+
+            m_listeners.push_back(FSListener());
+            FSListener & listener = m_listeners.back();
+
+            listener.m_name = switch_xml_attr_soft(xmlListener, "name");
+            if (listener.m_name.IsEmpty())
+                listener.m_name = "unnamed";
+
+            for (switch_xml_t xmlParam = switch_xml_child(xmlListener, "param"); xmlParam != NULL; xmlParam = xmlParam->next) {
+                PConstCaselessString const var(switch_xml_attr_soft(xmlParam, "name"));
+                PConstString const val(switch_xml_attr_soft(xmlParam, "value"));
+                if (var == "h323-ip")
+                    listener.m_address = val;
+                else if (var == "h323-port")
+                    listener.m_port = (uint16_t)val.AsUnsigned();
+            }
+
+            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Created Listener '%s'\n", (const char *) listener.m_name);
+        }
+    }
+
+    switch_event_destroy(&request_params);
+
+    if (xml)
+        switch_xml_free(xml);
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_call_cause_t create_outgoing_channel(switch_core_session_t   *session,
+                                                   switch_event_t          *var_event,
+                                                   switch_caller_profile_t *outbound_profile,
+                                                   switch_core_session_t  **new_session,
+                                                   switch_memory_pool_t   **pool,
+                                                   switch_originate_flag_t  flags,
+                                                   switch_call_cause_t     *cancel_cause)
+{
+    if (opal_process == NULL)
+      return SWITCH_CAUSE_CRASH;
+
+    FSConnection::outgoing_params params;
+    params.var_event        = var_event;
+    params.outbound_profile = outbound_profile;
+    params.new_session      = new_session;
+    params.pool             = pool;
+    params.flags            = flags;
+    params.cancel_cause     = cancel_cause;
+    params.fail_cause       = SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
+
+    if (opal_process->GetManager().SetUpCall(FS_PREFIX":", outbound_profile->destination_number, &params) != NULL)
+        return SWITCH_CAUSE_SUCCESS;
+
+    if (*new_session != NULL)
+        switch_core_session_destroy(new_session);
+    return params.fail_cause;
+}
+
+
+///////////////////////////////////////////////////////////////////////
+
+FSEndPoint::FSEndPoint(FSManager & manager)
+  : OpalLocalEndPoint(manager, FS_PREFIX)
+  , m_manager(manager)
+{
+    PTRACE(4, "mod_opal\tFSEndPoint created.");
+}
+
+
+OpalLocalConnection *FSEndPoint::CreateConnection(OpalCall & call, void *userData, unsigned options, OpalConnection::StringOptions* stringOptions)
+{
+    return new FSConnection(call, *this, options, stringOptions, (FSConnection::outgoing_params *)userData);
+}
+
+
+///////////////////////////////////////////////////////////////////////
+
+FSConnection::FSConnection(OpalCall & call,
+                           FSEndPoint & endpoint,
+                           unsigned options,
+                           OpalConnection::StringOptions* stringOptions,
+                           outgoing_params * params)
+  : OpalLocalConnection(call, endpoint, NULL, options, stringOptions)
+  , m_endpoint(endpoint)
+  , m_fsSession(NULL)
+  , m_fsChannel(NULL)
+  , m_flushAudio(false)
+  , m_udptl(false)
+{
+    memset(&m_read_timer, 0, sizeof(m_read_timer));
+    memset(&m_read_codec, 0, sizeof(m_read_codec));
+    memset(&m_write_codec, 0, sizeof(m_write_codec));
+    memset(&m_vid_read_timer, 0, sizeof(m_vid_read_timer));
+    memset(&m_vid_read_codec, 0, sizeof(m_vid_read_codec));
+    memset(&m_vid_write_codec, 0, sizeof(m_vid_write_codec));
+    memset(&m_dummy_frame, 0, sizeof(m_dummy_frame));
+    m_dummy_frame.flags = SFF_CNG;
+
+    if (params != NULL) {
+        // If we fail, this is the cause
+        params->fail_cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+
+        if ((m_fsSession = switch_core_session_request(endpoint.GetManager().GetSwitchInterface(),
+                                      SWITCH_CALL_DIRECTION_OUTBOUND, params->flags, params->pool)) == NULL) {
+            PTRACE(1, "mod_opal\tCannot create session for outgoing call.");
+            return;
+        }
+    }
+    else {
+      if ((m_fsSession = switch_core_session_request(endpoint.GetManager().GetSwitchInterface(),
+                                                     SWITCH_CALL_DIRECTION_INBOUND, SOF_NONE, NULL)) == NULL) {
+            PTRACE(1, "mod_opal\tCannot create session for incoming call.");
+            return;
+      }
+    }
+
+    if ((m_fsChannel = switch_core_session_get_channel(m_fsSession)) == NULL) {
+        switch_core_session_destroy(&m_fsSession);
+        return;
+    }
+
+    switch_core_session_set_private(m_fsSession, this);
+    SafeReference(); // Make sure cannot be deleted until on_destroy()
+
+    if (params != NULL) {
+        switch_caller_profile_t *caller_profile = switch_caller_profile_clone(m_fsSession, params->outbound_profile);
+        switch_channel_set_caller_profile(m_fsChannel, caller_profile);
+        SetLocalPartyName(caller_profile->caller_id_number);
+        SetDisplayName(caller_profile->caller_id_name);
+
+        *params->new_session = m_fsSession;
+    }
+
+    switch_channel_set_state(m_fsChannel, CS_INIT);
+}
+
+
+bool FSConnection::OnOutgoingSetUp()
+{
+    if (m_fsSession == NULL || m_fsChannel == NULL) {
+        PTRACE(1, "mod_opal\tSession request failed.");
+        return false;
+    }
+
+    // Transfer FS caller_id_number & caller_id_name from the FSConnection
+    // to the protocol connection (e.g. H.323) so gets sent correctly
+    // in outgoing packets
+    PSafePtr<OpalConnection> proto = GetOtherPartyConnection();
+    if (proto == NULL) {
+        PTRACE(1, "mod_opal\tNo protocol connection in call.");
+        return false;
+    }
+
+    proto->SetLocalPartyName(GetLocalPartyName());
+    proto->SetDisplayName(GetDisplayName());
+
+    switch_channel_set_name(m_fsChannel, ModuleName + '/' + GetRemotePartyURL());
+    return true;
+}
+
+
+bool FSConnection::OnIncoming()
+{
+    if (m_fsSession == NULL || m_fsChannel == NULL) {
+        PTRACE(1, "mod_opal\tSession request failed.");
+        return false;
+    }
+
+    switch_core_session_add_stream(m_fsSession, NULL);
+
+    PURL url = GetRemotePartyURL();
+    switch_caller_profile_t *caller_profile = switch_caller_profile_new(
+          switch_core_session_get_pool(m_fsSession),
+          url.GetUserName(),      /** username */
+          m_endpoint.GetManager().GetDialPlan(), /** dial plan */
+          GetRemotePartyName(),   /** caller_id_name */
+          GetRemotePartyNumber(), /** caller_id_number */
+          url.GetHostName(),      /** network addr */
+          NULL,                   /** ANI */
+          NULL,                   /** ANI II */
+          NULL,                   /** RDNIS */
+          ModuleName,             /** source */
+          m_endpoint.GetManager().GetContext(), /** set context  */
+          GetCalledPartyNumber()  /** destination_number */
+    );
+    if (caller_profile == NULL) {
+        PTRACE(1, "mod_opal\tCould not create caller profile");
+        return false;
+    }
+
+    PTRACE(4, "mod_opal\tCreated switch caller profile:\n"
+              "  username          = " << caller_profile->username << "\n"
+              "  dialplan          = " << caller_profile->dialplan << "\n"
+              "  caller_id_name    = " << caller_profile->caller_id_name << "\n"
+              "  caller_id_number  = " << caller_profile->caller_id_number << "\n"
+              "  network_addr      = " << caller_profile->network_addr << "\n"
+              "  source            = " << caller_profile->source << "\n"
+              "  context           = " << caller_profile->context << "\n"
+              "  destination_number= " << caller_profile->destination_number);
+    switch_channel_set_caller_profile(m_fsChannel, caller_profile);
+
+    switch_channel_set_name(m_fsChannel, ModuleName + '/' + url.GetScheme() + ':' + caller_profile->destination_number);
+
+    if (switch_core_session_thread_launch(m_fsSession) != SWITCH_STATUS_SUCCESS) {
+        PTRACE(1, "mod_opal\tCould not launch session thread");
+        switch_core_session_destroy(&m_fsSession);
+        m_fsChannel = NULL;
+        return false;
+    }
+
+    return true;
+}
+
+
+void FSConnection::OnEstablished()
+{
+  OpalLocalConnection::OnEstablished();
+
+  if (switch_channel_direction(m_fsChannel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
+    PTRACE(4, "mod_opal\tOnEstablished for outbound call, checking for media");
+    if (GetMediaStream(OpalMediaType::Audio(), true) != NULL && GetMediaStream(OpalMediaType::Audio(), false) != NULL) {
+      PTRACE(3, "mod_opal\tOnEstablished for outbound call, making call answered");
+      switch_channel_mark_answered(m_fsChannel);
+    }
+  }
+}
+
+
+void FSConnection::OnReleased()
+{
+    m_rxAudioOpened.Signal();   // Just in case
+    m_txAudioOpened.Signal();
+
+    if (m_fsChannel != NULL) {
+        PTRACE(3, "mod_opal\tHanging up FS side");
+        switch_channel_hangup(m_fsChannel, (switch_call_cause_t)callEndReason.q931);
+    }
+
+    OpalLocalConnection::OnReleased();
+}
+
+
+PBoolean FSConnection::SetAlerting(const PString & calleeName, PBoolean withMedia)
+{
+    if (PAssertNULL(m_fsChannel) == NULL)
+        return false;
+
+    switch_channel_mark_ring_ready(m_fsChannel);
+    return OpalLocalConnection::SetAlerting(calleeName, withMedia);
+}
+
+
+PBoolean FSConnection::SendUserInputTone(char tone, unsigned duration)
+{
+    if (PAssertNULL(m_fsChannel) == NULL)
+        return false;
+
+    switch_dtmf_t dtmf = { tone, duration };
+    PTRACE(4, "mod_opal\tSending DTMF to FS: tone=" << tone << ", duration=" << duration);
+    return switch_channel_queue_dtmf(m_fsChannel, &dtmf) == SWITCH_STATUS_SUCCESS;
+}
+
+
+OpalMediaFormatList FSConnection::GetMediaFormats() const
+{
+    if (m_switchMediaFormats.IsEmpty()) {
+        const_cast<FSConnection *>(this)->SetCodecs();
+    }
+
+    return m_switchMediaFormats;
+}
+
+
+void FSConnection::SetCodecs()
+{
+    int numCodecs = 0;
+    const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS];
+
+    PString codec_string = switch_channel_get_variable(m_fsChannel, "absolute_codec_string");
+    if (codec_string.IsEmpty()) {
+        codec_string = switch_channel_get_variable(m_fsChannel, "codec_string");
+        if (codec_string.IsEmpty()) {
+            codec_string = m_endpoint.GetManager().GetCodecPrefs();
+            if (codec_string.IsEmpty()) {
+                numCodecs = switch_loadable_module_get_codecs(codecs, sizeof(codecs) / sizeof(codecs[0]));
+                for (int i = 0; i < numCodecs; i++) {
+                  if (i > 0)
+                    codec_string += ',';
+                  codec_string += codecs[i]->iananame;
+                }
+                PTRACE(4, "mod_opal\tDefault to all loaded codecs=" << codec_string);
+            }
+            else {
+                PTRACE(4, "mod_opal\tSettings codec-prefs=" << codec_string);
+            }
+        }
+        else {
+            PTRACE(4, "mod_opal\tChannel codec_string=" << codec_string);
+        }
+
+        PString orig_codec = switch_channel_get_variable(m_fsChannel, SWITCH_ORIGINATOR_CODEC_VARIABLE);
+        if (!orig_codec.IsEmpty()) {
+          if (m_endpoint.GetManager().GetDisableTranscoding()) {
+              codec_string = orig_codec;
+              PTRACE(4, "mod_opal\tNo transcoding, forced to originator codec=" << orig_codec);
+          }
+          else {
+              codec_string.Splice(orig_codec+',', 0);
+              PTRACE(4, "mod_opal\tSetting preference to originator codec=" << orig_codec);
+          }
+        }
+    }
+    else {
+        PTRACE(4, "mod_opal\tChannel absolute_codec_string=" << codec_string);
+    }
+
+    {
+        char *codec_order[SWITCH_MAX_CODECS];
+        int codec_order_last = switch_separate_string((char *)codec_string.GetPointer(), ',', codec_order, SWITCH_MAX_CODECS);
+        numCodecs = switch_loadable_module_get_codecs_sorted(codecs, SWITCH_MAX_CODECS, codec_order, codec_order_last);
+    }
+
+    for (int i = 0; i < numCodecs; i++) {
+        const switch_codec_implementation_t *codec = codecs[i];
+
+        // See if we have a match by PayloadType/rate/name
+        OpalMediaFormat switchFormat((RTP_DataFrame::PayloadTypes)codec->ianacode,
+                                     codec->samples_per_second,
+                                     codec->iananame);
+        if (!switchFormat.IsValid()) {
+            // See if we have a match by name alone
+            switchFormat = codec->iananame;
+            if (!switchFormat.IsValid()) {
+              PTRACE(2, "mod_opal\tCould not match FS codec "
+                     << codec->iananame << '@' << codec->samples_per_second
+                     << " (pt=" << (unsigned)codec->ianacode << ")"
+                        " to an OPAL media format.");
+              continue;
+            }
+        }
+
+        PTRACE(4, "mod_opal\tMatched FS codec " << codec->iananame << " to OPAL media format " << switchFormat);
+
+#if IMPLEMENT_MULTI_FAME_AUDIO
+        // Did we match or create a new media format?
+        if (switchFormat.IsValid() && codec->codec_type == SWITCH_CODEC_TYPE_AUDIO) {
+            // Calculate frames per packet, do not use codec->codec_frames_per_packet as that field
+            // has slightly different semantics when used in streamed codecs such as G.711
+            int fpp = codec->samples_per_packet/switchFormat.GetFrameTime();
+
+            /* Set the frames/packet to maximum of what is in the FS table. The OPAL negotiations will
+               drop the value from there. This might fail if there are "holes" in the FS table, e.g.
+               if for some reason G.723.1 has 30ms and 90ms but not 60ms, then the OPAL negotiations
+               could end up with 60ms and the codec cannot be created. The "holes" are unlikely in
+               all but streamed codecs such as G.711, where it is theoretically possible for OPAL to
+               come up with 32ms and there is only 30ms and 40ms in the FS table. We deem these
+               scenarios sufficiently rare that we can safely ignore them ... for now. */
+
+            if (fpp > switchFormat.GetOptionInteger(OpalAudioFormat::RxFramesPerPacketOption())) {
+                switchFormat.SetOptionInteger(OpalAudioFormat::RxFramesPerPacketOption(), fpp);
+            }
+
+            if (fpp > switchFormat.GetOptionInteger(OpalAudioFormat::TxFramesPerPacketOption())) {
+                switchFormat.SetOptionInteger(OpalAudioFormat::TxFramesPerPacketOption(), fpp);
+            }
+        }
+#endif // IMPLEMENT_MULTI_FAME_AUDIO
+
+        m_switchMediaFormats += switchFormat;
+    }
+
+#if HAVE_T38
+    OpalMediaFormat t38 = OpalT38;
+
+    /* We need to have a T.38 options for TCS, but may be before the
+       spandsp_mod has set it us. So, if not, we actually give to spandsp_mod. */
+    switch_t38_options_t *t38_options = (switch_t38_options_t *)switch_channel_get_private(m_fsChannel, "t38_options");
+    if (t38_options == NULL)
+      SetT38OptionsFromMediaFormat(t38, "_preconfigured_t38_options");
+    else {
+      t38.SetOptionInteger("T38FaxVersion", t38_options->T38FaxVersion);
+      t38.SetOptionInteger("T38MaxBitRate", t38_options->T38MaxBitRate);
+      t38.SetOptionBoolean("T38FaxFillBitRemoval", t38_options->T38FaxFillBitRemoval);
+      t38.SetOptionBoolean("T38FaxTranscodingMMR", t38_options->T38FaxTranscodingMMR);
+      t38.SetOptionBoolean("T38FaxTranscodingJBIG", t38_options->T38FaxTranscodingJBIG);
+      t38.SetOptionValue("T38FaxRateManagement", t38_options->T38FaxRateManagement);
+      t38.SetOptionInteger("T38Version", t38_options->T38FaxMaxBuffer);
+      t38.SetOptionInteger("T38Version", t38_options->T38FaxMaxDatagram);
+      t38.SetOptionValue("T38FaxUdpEC", t38_options->T38FaxUdpEC);
+    }
+
+    m_switchMediaFormats += t38;
+#endif // HAVE_T38
+}
+
+
+OpalMediaStream *FSConnection::CreateMediaStream(const OpalMediaFormat & mediaFormat, unsigned sessionID, PBoolean isSource)
+{
+    return new FSMediaStream(*this, mediaFormat, sessionID, isSource);
+}
+
+
+void FSConnection::OnPatchMediaStream(PBoolean isSource, OpalMediaPatch & patch)
+{
+    OpalConnection::OnPatchMediaStream(isSource, patch);
+
+    if (PAssertNULL(m_fsChannel) == NULL)
+        return;
+
+    if (patch.GetSource().GetMediaFormat().GetMediaType() != OpalMediaType::Audio())
+        return;
+
+    if (switch_channel_direction(m_fsChannel) == SWITCH_CALL_DIRECTION_INBOUND) {
+        PTRACE(4, "mod_opal\tOnPatchMediaStream for inbound call, flagging media opened");
+        if (isSource)
+            m_rxAudioOpened.Signal();
+        else
+            m_txAudioOpened.Signal();
+    }
+    else {
+      PTRACE(4, "mod_opal\tOnPatchMediaStream for outbound call, checking media");
+      if (GetMediaStream(OpalMediaType::Audio(), !isSource) != NULL) {
+          // Have open media in both directions.
+          if (IsEstablished()) {
+              PTRACE(3, "mod_opal\tOnPatchMediaStream for outbound call, making call answered");
+              switch_channel_mark_answered(m_fsChannel);
+          }
+          else if (!IsReleased()) {
+              PTRACE(3, "mod_opal\tOnPatchMediaStream for outbound call, making call pre-answered");
+              switch_channel_mark_pre_answered(m_fsChannel);
+          }
+      }
+    }
+}
+
+
+switch_status_t FSConnection::on_init()
+{
+    if (PAssertNULL(m_fsChannel) == NULL)
+        return SWITCH_STATUS_FALSE;
+
+    PTRACE(4, "mod_opal\tStarted routing for connection " << *this);
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+
+switch_status_t FSConnection::on_routing()
+{
+    if (PAssertNULL(m_fsChannel) == NULL)
+        return SWITCH_STATUS_FALSE;
+
+    PTRACE(4, "mod_opal\tRouting connection " << *this);
+    return SWITCH_STATUS_SUCCESS;
+}
+
+
+switch_status_t FSConnection::on_execute()
+{
+    if (PAssertNULL(m_fsChannel) == NULL)
+        return SWITCH_STATUS_FALSE;
+
+    PTRACE(4, "mod_opal\tExecuting connection " << *this);
+    return SWITCH_STATUS_SUCCESS;
+}
+
+
+switch_status_t FSConnection::on_destroy()
+{
+    PTRACE(3, "mod_opal\tFS on_destroy for connection " << *this);
+
+    m_fsChannel = NULL; // Will be destroyed by FS, so don't use it any more.
+
+    switch_core_codec_destroy(&m_read_codec);
+    switch_core_codec_destroy(&m_write_codec);
+    switch_core_codec_destroy(&m_vid_read_codec);
+    switch_core_codec_destroy(&m_vid_write_codec);
+    switch_core_timer_destroy(&m_read_timer);
+    switch_core_timer_destroy(&m_vid_read_timer);
+
+    switch_core_session_set_private(m_fsSession, NULL);
+    SafeDereference();
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+
+switch_status_t FSConnection::on_hangup()
+{
+    if (PAssertNULL(m_fsChannel) == NULL)
+        return SWITCH_STATUS_FALSE;
+
+    /* if this is still here it was our idea to hangup not opal's */
+    ClearCallSynchronous(NULL, H323TranslateToCallEndReason(
+              (Q931::CauseValues)switch_channel_get_cause_q850(m_fsChannel), UINT_MAX));
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+
+switch_status_t FSConnection::on_exchange_media()
+{
+    PTRACE(4, "mod_opal\tExchanging media on connection " << *this);
+    return SWITCH_STATUS_SUCCESS;
+}
+
+
+switch_status_t FSConnection::on_soft_execute()
+{
+    PTRACE(4, "mod_opal\tSoft execute on connection " << *this);
+    return SWITCH_STATUS_SUCCESS;
+}
+
+
+switch_status_t FSConnection::kill_channel(int sig)
+{
+    switch (sig) {
+    case SWITCH_SIG_KILL:
+        PTRACE(4, "mod_opal\tSignal KILL received on connection " << *this);
+        m_rxAudioOpened.Signal();
+        m_txAudioOpened.Signal();
+        CloseMediaStreams();
+        break;
+
+    case SWITCH_SIG_BREAK:
+        PTRACE(4, "mod_opal\tSignal BREAK received on connection " << *this);
+        break;
+
+    default:
+        PTRACE(4, "mod_opal\tSignal " << sig << " received on connection " << *this);
+        break;
+    }
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+
+switch_status_t FSConnection::send_dtmf(const switch_dtmf_t *dtmf)
+{
+    PTRACE(4, "mod_opal\tReceived DTMF from FS: tone=" << dtmf->digit << ", duration=" << dtmf->duration);
+    OnUserInputTone(dtmf->digit, dtmf->duration);
+    return SWITCH_STATUS_SUCCESS;
+}
+
+
+switch_status_t FSConnection::receive_message(switch_core_session_message_t *msg)
+{
+    if (PAssertNULL(m_fsChannel) == NULL)
+        return SWITCH_STATUS_FALSE;
+
+    switch (msg->message_id) {
+    case SWITCH_MESSAGE_INDICATE_RINGING:
+    case SWITCH_MESSAGE_INDICATE_PROGRESS:
+    case SWITCH_MESSAGE_INDICATE_ANSWER:
+    case SWITCH_MESSAGE_INDICATE_DEFLECT:
+        if (switch_channel_direction(m_fsChannel) == SWITCH_CALL_DIRECTION_INBOUND) {
+            switch_caller_profile_t * profile = switch_channel_get_caller_profile(m_fsChannel);
+            if (profile != NULL && profile->caller_extension != NULL)
+            {
+                PSafePtr<OpalConnection> other = GetOtherPartyConnection();
+                if (other != NULL) {
+                    other->SetLocalPartyName(profile->caller_extension->extension_number);
+                    other->SetDisplayName(profile->caller_extension->extension_name);
+                }
+                SetLocalPartyName(profile->caller_extension->extension_number);
+                SetDisplayName(profile->caller_extension->extension_name);
+            }
+        }
+        else {
+            return SWITCH_STATUS_FALSE;
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    switch (msg->message_id) {
+    case SWITCH_MESSAGE_INDICATE_BRIDGE:
+    case SWITCH_MESSAGE_INDICATE_UNBRIDGE:
+    case SWITCH_MESSAGE_INDICATE_AUDIO_SYNC:
+        m_flushAudio = true;
+        break;
+
+    case SWITCH_MESSAGE_INDICATE_RINGING:
+        AlertingIncoming();
+        break;
+
+    case SWITCH_MESSAGE_INDICATE_PROGRESS:
+        AutoStartMediaStreams();
+        AlertingIncoming();
+
+        if (!WaitForMedia())
+            return SWITCH_STATUS_FALSE;
+
+        if (!switch_channel_test_flag(m_fsChannel, CF_EARLY_MEDIA)) {
+            switch_channel_mark_pre_answered(m_fsChannel);
+        }
+        break;
+
+    case SWITCH_MESSAGE_INDICATE_ANSWER:
+        AcceptIncoming();
+
+        if (!WaitForMedia())
+            return SWITCH_STATUS_FALSE;
+
+        if (!switch_channel_test_flag(m_fsChannel, CF_ANSWERED)) {
+            switch_channel_mark_answered(m_fsChannel);
+        }
+        break;
+
+    case SWITCH_MESSAGE_INDICATE_DEFLECT:
+        ownerCall.Transfer(msg->string_arg, GetOtherPartyConnection());
+        break;
+
+#if HAVE_T38
+    case SWITCH_MESSAGE_INDICATE_REQUEST_IMAGE_MEDIA:
+      {
+        PTRACE(2, "mod_opal\tRequesting switch to T.38");
+        PSafePtr<OpalConnection> other = GetOtherPartyConnection();
+        if (other != NULL && other->SwitchFaxMediaStreams(true))
+            switch_channel_set_flag(m_fsChannel, CF_REQ_MEDIA);
+        else {
+            PTRACE(1, "mod_opal\tMode change request to T.38 failed");
+        }
+        break;
+      }
+
+    case SWITCH_MESSAGE_INDICATE_T38_DESCRIPTION:
+        PTRACE(2, "mod_opal\tSWITCH_MESSAGE_INDICATE_T38_DESCRIPTION");
+        break;
+
+    case SWITCH_MESSAGE_INDICATE_UDPTL_MODE:
+        PTRACE(2, "mod_opal\tSWITCH_MESSAGE_INDICATE_UDPTL_MODE");
+        m_udptl = true;
+        break;
+#endif // HAVE_T38
+
+    default:
+        PTRACE(3, "mod_opal\tReceived unhandled message " << msg->message_id << " on connection " << *this);
+    }
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+
+bool FSConnection::WaitForMedia()
+{
+    PTRACE(4, "mod_opal\tAwaiting media start on connection " << *this);
+    m_rxAudioOpened.Wait();
+    m_txAudioOpened.Wait();
+
+    if (IsReleased()) {
+        // Call got aborted
+        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(m_fsSession), SWITCH_LOG_ERROR, "Call abandoned!\n");
+        return false;
+    }
+
+    PTRACE(3, "mod_opal\tMedia started on connection " << *this);
+    return true;
+}
+
+
+#if HAVE_T38
+void FSConnection::SetT38OptionsFromMediaFormat(const OpalMediaFormat & mediaFormat, const char * varname)
+{
+    switch_t38_options_t *t38_options = (switch_t38_options_t *)switch_channel_get_private(m_fsChannel, varname);
+    if (t38_options == NULL)
+      t38_options = (switch_t38_options_t *)switch_core_session_alloc(m_fsSession, sizeof(switch_t38_options_t));
+
+    PString value;
+    mediaFormat.GetOptionValue("T38FaxRateManagement", value);
+    t38_options->T38FaxRateManagement = switch_core_session_strdup(m_fsSession, value);
+
+    mediaFormat.GetOptionValue("T38FaxUdpEC", value);
+    t38_options->T38FaxUdpEC = switch_core_session_strdup(m_fsSession, value);
+
+    t38_options->T38MaxBitRate = mediaFormat.GetOptionInteger("T38MaxBitRate", 9600);
+    t38_options->T38FaxMaxBuffer = mediaFormat.GetOptionInteger("T38FaxMaxBuffer", 2000);
+    t38_options->T38FaxMaxDatagram = mediaFormat.GetOptionInteger("T38FaxMaxDatagram", 528);
+
+    t38_options->T38FaxFillBitRemoval = mediaFormat.GetOptionBoolean("T38FaxFillBitRemoval") ? SWITCH_TRUE : SWITCH_FALSE;
+    t38_options->T38FaxTranscodingMMR = mediaFormat.GetOptionBoolean("T38FaxTranscodingMMR") ? SWITCH_TRUE : SWITCH_FALSE;
+    t38_options->T38FaxTranscodingJBIG = mediaFormat.GetOptionBoolean("T38FaxTranscodingJBIG") ? SWITCH_TRUE : SWITCH_FALSE;
+
+    t38_options->T38VendorInfo = switch_core_session_strdup(m_fsSession, mediaFormat.GetOptionString("T38VendorInfo"));
+
+    //t38_options->remote_ip = switch_core_session_strdup(session, mediaFormat.something);
+    //t38_options->remote_port = mediaFormat.something;
+
+    switch_channel_set_private(m_fsChannel, varname, t38_options);
+    PTRACE(3, "mod_opal\tSet " << varname);
+}
+
+
+void FSConnection::OnSwitchedT38(bool toT38, bool success)
+{
+    if (toT38 && success && IndicateSwitchedT38()) {
+        PTRACE(3, "mod_opal\tMode change request to T.38 succeeded");
+    }
+    else {
+        AbortT38();
+    }
+}
+
+
+void FSConnection::OnSwitchingT38(bool toT38)
+{
+    if (toT38 && IndicateSwitchedT38()) {
+        PTRACE(3, "mod_opal\tMode change request to T.38 started");
+    }
+    else {
+      AbortT38();
+    }
+}
+
+
+void FSConnection::AbortT38()
+{
+    PTRACE(3, "mod_opal\tMode change request to T.38 failed");
+    switch_channel_set_private(m_fsChannel, "t38_options", NULL);
+    switch_channel_clear_app_flag_key("T38", m_fsChannel, CF_APP_T38);
+    switch_channel_clear_app_flag_key("T38", m_fsChannel, CF_APP_T38_REQ);
+    switch_channel_set_app_flag_key("T38", m_fsChannel, CF_APP_T38_FAIL);
+}
+
+
+bool FSConnection::IndicateSwitchedT38()
+{
+    PSafePtr<OpalConnection> other = GetOtherPartyConnection();
+    if (other == NULL) {
+        PTRACE(3, "mod_opal\tCan't change to T.38, no other connection");
+        return false;
+    }
+
+    OpalMediaFormatList otherFormats = other->GetMediaFormats();
+    OpalMediaFormatList::const_iterator t38 = otherFormats.FindFormat(OpalT38);
+    if (t38 == otherFormats.end()) {
+        PTRACE(3, "mod_opal\tCan't change to T.38, no remote capability");
+        return false;
+    }
+
+    SetT38OptionsFromMediaFormat(*t38, "t38_options");
+
+    switch_channel_set_variable(m_fsChannel, "has_t38", "true");
+    switch_channel_set_app_flag_key("T38", m_fsChannel, CF_APP_T38);
+
+    switch_channel_execute_on(m_fsChannel, "opal_execute_on_t38");
+    switch_channel_api_on(m_fsChannel, "opal_api_on_t38");
+    return true;
+}
+#endif // HAVE_T38
+
+
+switch_status_t FSConnection::receive_event(switch_event_t *event)
+{
+    PTRACE(4, "mod_opal\tReceived event " << event->event_id << " on connection " << *this);
+    return SWITCH_STATUS_SUCCESS;
+}
+
+
+switch_status_t FSConnection::state_change()
+{
+    PTRACE(4, "mod_opal\tState changed on connection " << *this);
+    return SWITCH_STATUS_SUCCESS;
+}
+
+
+switch_status_t FSConnection::read_audio_frame(switch_frame_t **frame, switch_io_flag_t flags, int stream_id)
+{
+    return read_frame(m_udptl ? OpalMediaType::Fax() : OpalMediaType::Audio(), frame, flags);
+}
+
+
+switch_status_t FSConnection::write_audio_frame(switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
+{
+    return write_frame(m_udptl ? OpalMediaType::Fax() : OpalMediaType::Audio(), frame, flags);
+}
+
+
+switch_status_t FSConnection::read_video_frame(switch_frame_t **frame, switch_io_flag_t flag, int stream_id)
+{
+    return read_frame(OpalMediaType::Video(), frame, flag);
+}
+
+
+switch_status_t FSConnection::write_video_frame(switch_frame_t *frame, switch_io_flag_t flag, int stream_id)
+{
+    return write_frame(OpalMediaType::Video(), frame, flag);
+}
+
+
+switch_status_t FSConnection::read_frame(const OpalMediaType & mediaType, switch_frame_t **frame, switch_io_flag_t flags)
+{
+    if (!ownerCall.IsSwitchingT38()) {
+        PSafePtr <FSMediaStream> stream = PSafePtrCast <OpalMediaStream, FSMediaStream>(GetMediaStream(mediaType, false));
+        if (stream != NULL)
+            return stream->read_frame(frame, flags);
+
+        PTRACE(2, "mod_opal\tNo stream for read of " << mediaType);
+    }
+
+    // Avoid all the channel closing and re-opening, especially with faxa switching, upsetting FS
+    *frame = &m_dummy_frame;
+    return SWITCH_STATUS_SUCCESS;
+}
+
+
+switch_status_t FSConnection::write_frame(const OpalMediaType & mediaType, const switch_frame_t *frame, switch_io_flag_t flags)
+{
+    // Avoid all the channel closing and re-opening, especially with faxa switching, upsetting FS
+    if (ownerCall.IsSwitchingT38())
+      return SWITCH_STATUS_SUCCESS;
+
+    PSafePtr <FSMediaStream> stream = PSafePtrCast<OpalMediaStream, FSMediaStream>(GetMediaStream(mediaType, true));
+    if (stream != NULL)
+      return stream->write_frame(frame, flags);
+
+    PTRACE(2, "mod_opal\tNo stream for write of " << mediaType);
+    return SWITCH_STATUS_SUCCESS;
+}
+
+
+///////////////////////////////////////////////////////////////////////
+
+FSMediaStream::FSMediaStream(FSConnection & conn, const OpalMediaFormat & mediaFormat, unsigned sessionID, bool isSource)
+    : OpalMediaStream(conn, mediaFormat, sessionID, isSource)
+    , m_connection(conn)
+    , m_switchTimer(NULL)
+    , m_switchCodec(NULL)
+    , m_readRTP(0, SWITCH_RECOMMENDED_BUFFER_SIZE)
+{
+    memset(&m_readFrame, 0, sizeof(m_readFrame));
+}
+
+
+PBoolean FSMediaStream::Open()
+{
+    if (IsOpen()) {
+        return true;
+    }
+
+    switch_core_session_t *fsSession = m_connection.GetSession();
+    switch_channel_t *fsChannel = m_connection.GetChannel();
+    if (PAssertNULL(fsSession) == NULL || PAssertNULL(fsChannel) == NULL)
+        return false;
+
+    bool isAudio;
+    OpalMediaType mediaType = mediaFormat.GetMediaType();
+    if (mediaType == OpalMediaType::Audio())
+        isAudio = true;
+    else if (mediaType == OpalMediaType::Video())
+        isAudio = false;
+#if HAVE_T38
+    else if (mediaType == OpalMediaType::Fax()) {
+        m_readFrame.flags = SFF_UDPTL_PACKET|SFF_PROXY_PACKET;
+        return OpalMediaStream::Open();
+    }
+#endif
+    else {
+        PTRACE(1, "mod_opal\tUnsupported media type: " << mediaType);
+        return false;
+    }
+
+    int ptime = mediaFormat.GetOptionInteger(OpalAudioFormat::TxFramesPerPacketOption()) * mediaFormat.GetFrameTime() / mediaFormat.GetTimeUnits();
+
+    if (IsSink()) {
+        m_switchCodec = isAudio ? &m_connection.m_read_codec : &m_connection.m_vid_read_codec;
+        m_switchTimer = isAudio ? &m_connection.m_read_timer : &m_connection.m_vid_read_timer;
+        m_readFrame.codec = m_switchCodec;
+        m_readFrame.rate = mediaFormat.GetClockRate();
+    } else {
+        m_switchCodec = isAudio ? &m_connection.m_write_codec : &m_connection.m_vid_write_codec;
+    }
+
+    // The following is performed on two different instances of this object.
+    if (switch_core_codec_init(m_switchCodec, mediaFormat.GetEncodingName(), NULL, // FMTP
+                               mediaFormat.GetClockRate(), ptime, 1,  // Channels
+                               SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL,   // Settings
+                               switch_core_session_get_pool(fsSession)) != SWITCH_STATUS_SUCCESS) {
+        // Could not select a codecs using negotiated frames/packet, so try using default.
+        if (switch_core_codec_init(m_switchCodec, mediaFormat.GetEncodingName(), NULL, // FMTP
+                                   mediaFormat.GetClockRate(), 0, 1,  // Channels
+                                   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL,   // Settings
+                                   switch_core_session_get_pool(fsSession)) != SWITCH_STATUS_SUCCESS) {
+            PTRACE(1, "mod_opal\t" << switch_channel_get_name(fsChannel)
+                   << " cannot initialise " << (IsSink()? "read" : "write") << ' '
+                   << mediaType << " codec " << mediaFormat << " for connection " << *this);
+            switch_channel_hangup(fsChannel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
+            return false;
+        }
+        PTRACE(2, "mod_opal\t" << switch_channel_get_name(fsChannel)
+               << " unsupported ptime of " << ptime << " on " << (IsSink()? "read" : "write") << ' '
+               << mediaType << " codec " << mediaFormat << " for connection " << *this);
+    }
+
+    if (IsSink()) {
+        if (isAudio) {
+            switch_core_session_set_read_codec(fsSession, m_switchCodec);
+            if (switch_core_timer_init(m_switchTimer,
+                                       "soft",
+                                       m_switchCodec->implementation->microseconds_per_packet / 1000,
+                                       m_switchCodec->implementation->samples_per_packet,
+                                       switch_core_session_get_pool(fsSession)) != SWITCH_STATUS_SUCCESS) {
+                PTRACE(1, "mod_opal\t" << switch_channel_get_name(fsChannel)
+                       << " timer init failed on " << (IsSink()? "read" : "write") << ' '
+                       << mediaType << " codec " << mediaFormat << " for connection " << *this);
+                switch_core_codec_destroy(m_switchCodec);
+                m_switchCodec = NULL;
+                return false;
+            }
+        } else {
+            switch_core_session_set_video_read_codec(fsSession, m_switchCodec);
+            switch_channel_set_flag(fsChannel, CF_VIDEO);
+        }
+    } else {
+        if (isAudio) {
+            switch_core_session_set_write_codec(fsSession, m_switchCodec);
+        } else {
+            switch_core_session_set_video_write_codec(fsSession, m_switchCodec);
+            switch_channel_set_flag(fsChannel, CF_VIDEO);
+        }
+    }
+
+    PTRACE(3, "mod_opal\t" << switch_channel_get_name(fsChannel)
+           << " initialised " << (IsSink()? "read" : "write") << ' '
+           << mediaType << " codec " << mediaFormat << " for connection " << *this);
+
+    return OpalMediaStream::Open();
+}
+
+
+void FSMediaStream::InternalClose()
+{
+}
+
+
+PBoolean FSMediaStream::IsSynchronous() const
+{
+    return true;
+}
+
+
+PBoolean FSMediaStream::RequiresPatchThread(OpalMediaStream *) const
+{
+    return false;
+}
+
+
+int FSMediaStream::StartReadWrite(PatchPtr & mediaPatch) const
+{
+    if (!IsOpen()) {
+        PTRACE(1, "mod_opal\tNot open!");
+        return -1;
+    }
+
+    if (!m_connection.IsChannelReady()) {
+        PTRACE(1, "mod_opal\tChannel not ready!");
+        return -1;
+    }
+
+    // We make referenced copy of pointer so can't be deleted out from under us
+    mediaPatch = m_mediaPatch;
+    if (mediaPatch == NULL) {
+        /*There is a race here... sometimes we make it here and m_mediaPatch is NULL
+          if we wait it shows up in 1ms, maybe there is a better way to wait. */
+        PTRACE(2, "mod_opal\tPatch not ready!");
+        return 1;
+    }
+
+    return 0;
+}
+
+
+switch_status_t FSMediaStream::read_frame(switch_frame_t **frame, switch_io_flag_t flags)
+{
+    *frame = &m_readFrame;
+    m_readFrame.flags |= SFF_CNG;
+
+    PatchPtr mediaPatch;
+    switch (StartReadWrite(mediaPatch)) {
+      case -1 :
+        return SWITCH_STATUS_FALSE;
+      case 1 :
+        return SWITCH_STATUS_SUCCESS;
+    }
+
+    if (m_connection.NeedFlushAudio()) {
+        mediaPatch->GetSource().EnableJitterBuffer(); // This flushes data and resets jitter buffer
+        m_readRTP.SetPayloadSize(0);
+    } else {
+        if (m_switchCodec != NULL) {
+            m_readRTP.SetTimestamp(m_readFrame.timestamp + m_switchCodec->implementation->samples_per_packet);
+        }
+
+        if (!mediaPatch->GetSource().ReadPacket(m_readRTP)) {
+            PTRACE(1, "mod_opal\tread_frame: no source data!");
+            return SWITCH_STATUS_FALSE;
+        }
+    }
+
+    if (m_switchTimer != NULL) {
+        switch_core_timer_next(m_switchTimer);
+    }
+
+    if (m_switchCodec != NULL) {
+        if (!switch_core_codec_ready(m_switchCodec)) {
+            PTRACE(1, "mod_opal\tread_frame: codec not ready!");
+            return SWITCH_STATUS_FALSE;
+        }
+    }
+
+    if (switch_test_flag(&m_readFrame, SFF_UDPTL_PACKET)) {
+        m_readFrame.flags    &= ~SFF_CNG;
+        m_readFrame.packet    = m_readRTP.GetPayloadPtr();
+        m_readFrame.packetlen = m_readRTP.GetPayloadSize();
+        return SWITCH_STATUS_SUCCESS;
+    }
+
+    if (switch_test_flag(&m_readFrame, SFF_RAW_RTP)) {
+        m_readFrame.flags    &= ~SFF_CNG;
+        m_readFrame.packet    = m_readRTP.GetPointer();
+        m_readFrame.packetlen = m_readRTP.GetHeaderSize() + m_readRTP.GetPayloadSize();
+        return SWITCH_STATUS_SUCCESS;
+    }
+
+#if IMPLEMENT_MULTI_FAME_AUDIO
+    // Repackage frames in incoming packet to agree with what FS expects.
+    // Not implmented yet!!!!!!!!!
+    // Cheating and only supporting one frame per packet
+#endif
+
+    m_readFrame.buflen    = m_readRTP.GetSize();
+    m_readFrame.data      = m_readRTP.GetPayloadPtr();
+    m_readFrame.datalen   = m_readRTP.GetPayloadSize();
+    m_readFrame.timestamp = m_readRTP.GetTimestamp();
+    m_readFrame.seq       = m_readRTP.GetSequenceNumber();
+    m_readFrame.ssrc      = m_readRTP.GetSyncSource();
+    m_readFrame.m         = m_readRTP.GetMarker() ? SWITCH_TRUE : SWITCH_FALSE;
+    m_readFrame.payload   = (switch_payload_t)m_readRTP.GetPayloadType();
+
+    if (m_readFrame.datalen > 0 &&
+        m_readFrame.payload != RTP_DataFrame::CN &&
+        m_readFrame.payload != RTP_DataFrame::Cisco_CN) {
+        m_readFrame.flags &= ~SFF_CNG;
+    }
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+
+switch_status_t FSMediaStream::write_frame(const switch_frame_t *frame, switch_io_flag_t flags)
+{
+    PatchPtr mediaPatch;
+    switch (StartReadWrite(mediaPatch)) {
+      case -1 :
+        return SWITCH_STATUS_FALSE;
+      case 1 :
+        return SWITCH_STATUS_SUCCESS;
+    }
+
+    RTP_DataFrame rtp;
+    if (switch_test_flag(frame, SFF_RAW_RTP)) {
+        rtp = RTP_DataFrame((const BYTE *)frame->packet, frame->packetlen, false);
+    }
+    else if (switch_test_flag(frame, SFF_UDPTL_PACKET)) {
+        rtp.SetPayloadSize(frame->packetlen);
+        memcpy(rtp.GetPayloadPtr(), frame->packet, frame->packetlen);
+    }
+    else {
+        rtp.SetPayloadSize(frame->datalen);
+        memcpy(rtp.GetPayloadPtr(), frame->data, frame->datalen);
+
+        rtp.SetPayloadType(mediaFormat.GetPayloadType());
+
+        /* Not sure what FS is going to give us!
+           Suspect it depends on the mod on the other side sending it. */
+        if (frame->timestamp != 0)
+            timestamp = frame->timestamp;
+        else if (frame->samples != 0)
+            timestamp += frame->samples;
+        else if (m_switchCodec != NULL)
+            timestamp += m_switchCodec->implementation->samples_per_packet;
+        rtp.SetTimestamp(timestamp);
+    }
+
+    if (mediaPatch->PushFrame(rtp))
+      return SWITCH_STATUS_SUCCESS;
+
+    PTRACE(1, "mod_opal\tread_frame: push failed!");
+    return SWITCH_STATUS_FALSE;
+}
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:nil
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:s:
+ */
index 4b0cd62a0208ef8983f1c30fce08ed369aff0707..4ee10910ee4e724c6c39be633e286d5f076b27fa 100644 (file)
-/* Opal endpoint interface for Freeswitch Modular Media Switching Software Library /\r
- * Soft-Switch Application\r
- *\r
- * Version: MPL 1.1\r
- *\r
- * Copyright (c) 2007 Tuyan Ozipek (tuyanozipek@gmail.com)\r
- * Copyright (c) 2008-2012 Vox Lucida Pty. Ltd. (robertj@voxlucida.com.au)\r
- *\r
- * The contents of this file are subject to the Mozilla Public License Version\r
- * 1.1 (the "License"); you may not use this file except in compliance with\r
- * the License. You may obtain a copy of the License at\r
- * http://www.mozilla.org/MPL/\r
- *\r
- * Software distributed under the License is distributed on an "AS IS" basis,\r
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\r
- * for the specific language governing rights and limitations under the\r
- * License.\r
- *\r
- * Contributor(s):\r
- * Tuyan Ozipek   (tuyanozipek@gmail.com)\r
- * Lukasz Zwierko (lzwierko@gmail.com)\r
- * Robert Jongbloed (robertj@voxlucida.com.au)\r
- *\r
- */\r
-\r
-\r
-#ifndef __FREESWITCH_MOD_OPAL__\r
-#define __FREESWITCH_MOD_OPAL__\r
-\r
-#if defined(__GNUC__) && defined(HAVE_VISIBILITY)\r
-#pragma GCC visibility push(default)\r
-#endif\r
-\r
-#include <ptlib.h>\r
-#include <opal/manager.h>\r
-\r
-#ifndef OPAL_CHECK_VERSION\r
-  #define OPAL_CHECK_VERSION(a,b,c) 0\r
-#endif\r
-\r
-#if !OPAL_CHECK_VERSION(3,12,8)\r
-  #error OPAL is too old to use, must be >= 2.12.8\r
-#endif\r
-\r
-#include <ep/localep.h>\r
-#include <h323/h323ep.h>\r
-#include <iax2/iax2ep.h>\r
-\r
-#if defined(__GNUC__) && defined(HAVE_VISIBILITY)\r
-#pragma GCC visibility pop\r
-#endif\r
-\r
-#undef strcasecmp\r
-#undef strncasecmp\r
-\r
-#include <switch.h>\r
-\r
-#define MODNAME "mod_opal"\r
-\r
-#define HAVE_T38 OPAL_T38_CAPABILITY\r
-\r
-\r
-\r
-class FSEndPoint;\r
-class FSManager;\r
-\r
-\r
-class FSProcess : public PLibraryProcess\r
-{\r
-    PCLASSINFO(FSProcess, PLibraryProcess);\r
-  public:\r
-    FSProcess();\r
-    ~FSProcess();\r
-\r
-    bool Initialise(switch_loadable_module_interface_t *iface);\r
-\r
-    FSManager & GetManager() const\r
-    {\r
-        return *m_manager;\r
-    }\r
-\r
-  protected:\r
-    FSManager * m_manager;\r
-};\r
-\r
-\r
-struct FSListener\r
-{\r
-    FSListener() : m_port(H323EndPoint::DefaultTcpSignalPort) { }\r
-\r
-    PString            m_name;\r
-    PIPSocket::Address m_address;\r
-    uint16_t           m_port;\r
-};\r
-\r
-\r
-class FSManager : public OpalManager\r
-{\r
-    PCLASSINFO(FSManager, OpalManager);\r
-\r
-  public:\r
-    FSManager();\r
-\r
-    bool Initialise(switch_loadable_module_interface_t *iface);\r
-\r
-    switch_status_t ReadConfig(int reload);\r
-\r
-    switch_endpoint_interface_t *GetSwitchInterface() const { return m_FreeSwitch; }\r
-    const PString & GetContext() const { return m_context; }\r
-    const PString & GetDialPlan() const { return m_dialplan; }\r
-    const PString & GetCodecPrefs() const { return m_codecPrefs; }\r
-    bool GetDisableTranscoding() const { return m_disableTranscoding; }\r
-\r
-  private:\r
-    switch_endpoint_interface_t *m_FreeSwitch;\r
-\r
-    H323EndPoint *m_h323ep;\r
-    IAX2EndPoint *m_iaxep;\r
-    FSEndPoint   *m_fsep;\r
-\r
-    PString m_context;\r
-    PString m_dialplan;\r
-    PString m_codecPrefs;\r
-    bool    m_disableTranscoding;\r
-    PString m_gkAddress;\r
-    PString m_gkIdentifer;\r
-    PString m_gkInterface;\r
-\r
-    list <FSListener> m_listeners;\r
-};\r
-\r
-\r
-class FSEndPoint : public OpalLocalEndPoint\r
-{\r
-    PCLASSINFO(FSEndPoint, OpalLocalEndPoint);\r
-  public:\r
-    FSEndPoint(FSManager & manager);\r
-\r
-    virtual OpalLocalConnection *CreateConnection(OpalCall & call, void *userData, unsigned options, OpalConnection::StringOptions * stringOptions);\r
-\r
-    FSManager & GetManager() const { return m_manager; }\r
-\r
-  protected:\r
-    FSManager & m_manager;\r
-};\r
-\r
-\r
-class FSConnection;\r
-\r
-\r
-class FSMediaStream : public OpalMediaStream\r
-{\r
-    PCLASSINFO(FSMediaStream, OpalMediaStream);\r
-  public:\r
-    FSMediaStream(\r
-      FSConnection & conn,\r
-      const OpalMediaFormat & mediaFormat,    ///<  Media format for stream\r
-      unsigned sessionID,    ///<  Session number for stream\r
-      bool isSource    ///<  Is a source stream\r
-    );\r
-\r
-    virtual PBoolean Open();\r
-    virtual PBoolean IsSynchronous() const;\r
-    virtual PBoolean RequiresPatchThread(OpalMediaStream *) const;\r
-\r
-    switch_status_t read_frame(switch_frame_t **frame, switch_io_flag_t flags);\r
-    switch_status_t write_frame(const switch_frame_t *frame, switch_io_flag_t flags);\r
-\r
-  protected:\r
-    virtual void InternalClose();\r
-    int StartReadWrite(PatchPtr & mediaPatch) const;\r
-\r
-  private:\r
-    bool CheckPatchAndLock();\r
-\r
-    FSConnection          &m_connection;\r
-    switch_timer_t        *m_switchTimer;\r
-    switch_codec_t        *m_switchCodec;\r
-    switch_frame_t         m_readFrame;\r
-    RTP_DataFrame          m_readRTP;\r
-};\r
-\r
-\r
-#define DECLARE_CALLBACK0(name)                           \\r
-    static switch_status_t name(switch_core_session_t *session) {       \\r
-        FSConnection *tech_pvt = (FSConnection *) switch_core_session_get_private(session); \\r
-        return tech_pvt != NULL ? tech_pvt->name() : SWITCH_STATUS_FALSE; } \\r
-    switch_status_t name()\r
-\r
-#define DECLARE_CALLBACK1(name, type1, name1)                           \\r
-    static switch_status_t name(switch_core_session_t *session, type1 name1) { \\r
-        FSConnection *tech_pvt = (FSConnection *) switch_core_session_get_private(session); \\r
-        return tech_pvt != NULL ? tech_pvt->name(name1) : SWITCH_STATUS_FALSE; } \\r
-    switch_status_t name(type1 name1)\r
-\r
-#define DECLARE_CALLBACK3(name, type1, name1, type2, name2, type3, name3) \\r
-    static switch_status_t name(switch_core_session_t *session, type1 name1, type2 name2, type3 name3) { \\r
-        FSConnection *tech_pvt = (FSConnection *) switch_core_session_get_private(session); \\r
-        return tech_pvt != NULL ? tech_pvt->name(name1, name2, name3) : SWITCH_STATUS_FALSE; } \\r
-    switch_status_t name(type1 name1, type2 name2, type3 name3)\r
-\r
-\r
-\r
-\r
-class FSConnection : public OpalLocalConnection\r
-{\r
-    PCLASSINFO(FSConnection, OpalLocalConnection)\r
-\r
-  public:\r
-    struct outgoing_params {\r
-      switch_event_t          *var_event;\r
-      switch_caller_profile_t *outbound_profile;\r
-      switch_core_session_t  **new_session;\r
-      switch_memory_pool_t   **pool;\r
-      switch_originate_flag_t  flags;\r
-      switch_call_cause_t     *cancel_cause;\r
-      switch_call_cause_t      fail_cause;\r
-    };\r
-\r
-    FSConnection(OpalCall & call,\r
-                 FSEndPoint & endpoint,\r
-                 unsigned options,\r
-                 OpalConnection::StringOptions * stringOptions,\r
-                 outgoing_params * params);\r
-\r
-    virtual bool OnOutgoingSetUp();\r
-    virtual bool OnIncoming();\r
-    virtual void OnEstablished();\r
-    virtual void OnReleased();\r
-    virtual PBoolean SetAlerting(const PString & calleeName, PBoolean withMedia);\r
-    virtual OpalMediaStream *CreateMediaStream(const OpalMediaFormat &, unsigned, PBoolean);\r
-    virtual void OnPatchMediaStream(PBoolean isSource, OpalMediaPatch & patch);\r
-    virtual OpalMediaFormatList GetMediaFormats() const;\r
-    virtual PBoolean SendUserInputTone(char tone, unsigned duration);\r
-#if HAVE_T38\r
-    virtual void OnSwitchedT38(bool toT38, bool success);\r
-    virtual void OnSwitchingT38(bool toT38);\r
-#endif\r
-\r
-    DECLARE_CALLBACK0(on_init);\r
-    DECLARE_CALLBACK0(on_destroy);\r
-    DECLARE_CALLBACK0(on_routing);\r
-    DECLARE_CALLBACK0(on_execute);\r
-    DECLARE_CALLBACK0(on_hangup);\r
-\r
-    DECLARE_CALLBACK0(on_exchange_media);\r
-    DECLARE_CALLBACK0(on_soft_execute);\r
-\r
-    DECLARE_CALLBACK1(kill_channel, int, sig);\r
-    DECLARE_CALLBACK1(send_dtmf, const switch_dtmf_t *, dtmf);\r
-    DECLARE_CALLBACK1(receive_message, switch_core_session_message_t *, msg);\r
-    DECLARE_CALLBACK1(receive_event, switch_event_t *, event);\r
-    DECLARE_CALLBACK0(state_change);\r
-    DECLARE_CALLBACK3(read_audio_frame, switch_frame_t **, frame, switch_io_flag_t, flags, int, stream_id);\r
-    DECLARE_CALLBACK3(write_audio_frame, switch_frame_t *, frame, switch_io_flag_t, flags, int, stream_id);\r
-    DECLARE_CALLBACK3(read_video_frame, switch_frame_t **, frame, switch_io_flag_t, flag, int, stream_id);\r
-    DECLARE_CALLBACK3(write_video_frame, switch_frame_t *, frame, switch_io_flag_t, flag, int, stream_id);\r
-\r
-    __inline switch_core_session_t *GetSession() const\r
-    {\r
-        return m_fsSession;\r
-    }\r
-\r
-    __inline switch_channel_t *GetChannel() const\r
-    {\r
-        return m_fsChannel;\r
-    }\r
-\r
-    bool IsChannelReady() const\r
-    {\r
-        return m_fsChannel != NULL && switch_channel_ready(m_fsChannel);\r
-    }\r
-\r
-    bool NeedFlushAudio()\r
-    {\r
-        if (!m_flushAudio)\r
-          return false;\r
-        m_flushAudio = false;\r
-        return true;\r
-    }\r
-\r
-  protected:\r
-    void SetCodecs();\r
-    bool WaitForMedia();\r
-#if HAVE_T38\r
-    void SetT38OptionsFromMediaFormat(const OpalMediaFormat & mediaFormat, const char * varname);\r
-    bool IndicateSwitchedT38();\r
-    void AbortT38();\r
-#endif\r
-\r
-    switch_status_t read_frame(const OpalMediaType & mediaType, switch_frame_t **frame, switch_io_flag_t flags);\r
-    switch_status_t write_frame(const OpalMediaType & mediaType, const switch_frame_t *frame, switch_io_flag_t flags);\r
-\r
-  private:\r
-    FSEndPoint            &m_endpoint;\r
-    switch_core_session_t *m_fsSession;\r
-    switch_channel_t      *m_fsChannel;\r
-    PSyncPoint             m_rxAudioOpened;\r
-    PSyncPoint             m_txAudioOpened;\r
-    OpalMediaFormatList    m_switchMediaFormats;\r
-\r
-    // If FS ever supports more than one audio and one video, this needs to change\r
-    switch_timer_t m_read_timer;\r
-    switch_codec_t m_read_codec;\r
-    switch_codec_t m_write_codec;\r
-\r
-    switch_timer_t m_vid_read_timer;\r
-    switch_codec_t m_vid_read_codec;\r
-    switch_codec_t m_vid_write_codec;\r
-\r
-    switch_frame_t m_dummy_frame;\r
-\r
-    bool m_flushAudio;\r
-    bool m_udptl;\r
-\r
-    friend PBoolean FSMediaStream::Open();\r
-};\r
-\r
-\r
-#endif /* __FREESWITCH_MOD_OPAL__ */\r
-\r
-/* For Emacs:\r
- * Local Variables:\r
- * mode:c\r
- * indent-tabs-mode:nil\r
- * tab-width:4\r
- * c-basic-offset:4\r
- * End:\r
- * For VIM:\r
- * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:s:\r
- */\r
+/* Opal endpoint interface for Freeswitch Modular Media Switching Software Library /
+ * Soft-Switch Application
+ *
+ * Version: MPL 1.1
+ *
+ * Copyright (c) 2007 Tuyan Ozipek (tuyanozipek@gmail.com)
+ * Copyright (c) 2008-2012 Vox Lucida Pty. Ltd. (robertj@voxlucida.com.au)
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Contributor(s):
+ * Tuyan Ozipek   (tuyanozipek@gmail.com)
+ * Lukasz Zwierko (lzwierko@gmail.com)
+ * Robert Jongbloed (robertj@voxlucida.com.au)
+ *
+ */
+
+
+#ifndef __FREESWITCH_MOD_OPAL__
+#define __FREESWITCH_MOD_OPAL__
+
+#if defined(__GNUC__) && defined(HAVE_VISIBILITY)
+#pragma GCC visibility push(default)
+#endif
+
+#include <ptlib.h>
+#include <opal/manager.h>
+
+#ifndef OPAL_CHECK_VERSION
+  #define OPAL_CHECK_VERSION(a,b,c) 0
+#endif
+
+#if !OPAL_CHECK_VERSION(3,12,8)
+  #error OPAL is too old to use, must be >= 2.12.8
+#endif
+
+#include <ep/localep.h>
+#include <h323/h323ep.h>
+#include <iax2/iax2ep.h>
+
+#if defined(__GNUC__) && defined(HAVE_VISIBILITY)
+#pragma GCC visibility pop
+#endif
+
+#undef strcasecmp
+#undef strncasecmp
+
+#include <switch.h>
+
+#define MODNAME "mod_opal"
+
+#define HAVE_T38 OPAL_T38_CAPABILITY
+
+
+
+class FSEndPoint;
+class FSManager;
+
+
+class FSProcess : public PLibraryProcess
+{
+    PCLASSINFO(FSProcess, PLibraryProcess);
+  public:
+    FSProcess();
+    ~FSProcess();
+
+    bool Initialise(switch_loadable_module_interface_t *iface);
+
+    FSManager & GetManager() const
+    {
+        return *m_manager;
+    }
+
+  protected:
+    FSManager * m_manager;
+};
+
+
+struct FSListener
+{
+    FSListener() : m_port(H323EndPoint::DefaultTcpSignalPort) { }
+
+    PString            m_name;
+    PIPSocket::Address m_address;
+    uint16_t           m_port;
+};
+
+
+class FSManager : public OpalManager
+{
+    PCLASSINFO(FSManager, OpalManager);
+
+  public:
+    FSManager();
+
+    bool Initialise(switch_loadable_module_interface_t *iface);
+
+    switch_status_t ReadConfig(int reload);
+
+    switch_endpoint_interface_t *GetSwitchInterface() const { return m_FreeSwitch; }
+    const PString & GetContext() const { return m_context; }
+    const PString & GetDialPlan() const { return m_dialplan; }
+    const PString & GetCodecPrefs() const { return m_codecPrefs; }
+    bool GetDisableTranscoding() const { return m_disableTranscoding; }
+
+  private:
+    switch_endpoint_interface_t *m_FreeSwitch;
+
+    H323EndPoint *m_h323ep;
+    IAX2EndPoint *m_iaxep;
+    FSEndPoint   *m_fsep;
+
+    PString m_context;
+    PString m_dialplan;
+    PString m_codecPrefs;
+    bool    m_disableTranscoding;
+    PString m_gkAddress;
+    PString m_gkIdentifer;
+    PString m_gkInterface;
+
+    list <FSListener> m_listeners;
+};
+
+
+class FSEndPoint : public OpalLocalEndPoint
+{
+    PCLASSINFO(FSEndPoint, OpalLocalEndPoint);
+  public:
+    FSEndPoint(FSManager & manager);
+
+    virtual OpalLocalConnection *CreateConnection(OpalCall & call, void *userData, unsigned options, OpalConnection::StringOptions * stringOptions);
+
+    FSManager & GetManager() const { return m_manager; }
+
+  protected:
+    FSManager & m_manager;
+};
+
+
+class FSConnection;
+
+
+class FSMediaStream : public OpalMediaStream
+{
+    PCLASSINFO(FSMediaStream, OpalMediaStream);
+  public:
+    FSMediaStream(
+      FSConnection & conn,
+      const OpalMediaFormat & mediaFormat,    ///<  Media format for stream
+      unsigned sessionID,    ///<  Session number for stream
+      bool isSource    ///<  Is a source stream
+    );
+
+    virtual PBoolean Open();
+    virtual PBoolean IsSynchronous() const;
+    virtual PBoolean RequiresPatchThread(OpalMediaStream *) const;
+
+    switch_status_t read_frame(switch_frame_t **frame, switch_io_flag_t flags);
+    switch_status_t write_frame(const switch_frame_t *frame, switch_io_flag_t flags);
+
+  protected:
+    virtual void InternalClose();
+    int StartReadWrite(PatchPtr & mediaPatch) const;
+
+  private:
+    bool CheckPatchAndLock();
+
+    FSConnection          &m_connection;
+    switch_timer_t        *m_switchTimer;
+    switch_codec_t        *m_switchCodec;
+    switch_frame_t         m_readFrame;
+    RTP_DataFrame          m_readRTP;
+};
+
+
+#define DECLARE_CALLBACK0(name)                           \
+    static switch_status_t name(switch_core_session_t *session) {       \
+        FSConnection *tech_pvt = (FSConnection *) switch_core_session_get_private(session); \
+        return tech_pvt != NULL ? tech_pvt->name() : SWITCH_STATUS_FALSE; } \
+    switch_status_t name()
+
+#define DECLARE_CALLBACK1(name, type1, name1)                           \
+    static switch_status_t name(switch_core_session_t *session, type1 name1) { \
+        FSConnection *tech_pvt = (FSConnection *) switch_core_session_get_private(session); \
+        return tech_pvt != NULL ? tech_pvt->name(name1) : SWITCH_STATUS_FALSE; } \
+    switch_status_t name(type1 name1)
+
+#define DECLARE_CALLBACK3(name, type1, name1, type2, name2, type3, name3) \
+    static switch_status_t name(switch_core_session_t *session, type1 name1, type2 name2, type3 name3) { \
+        FSConnection *tech_pvt = (FSConnection *) switch_core_session_get_private(session); \
+        return tech_pvt != NULL ? tech_pvt->name(name1, name2, name3) : SWITCH_STATUS_FALSE; } \
+    switch_status_t name(type1 name1, type2 name2, type3 name3)
+
+
+
+
+class FSConnection : public OpalLocalConnection
+{
+    PCLASSINFO(FSConnection, OpalLocalConnection)
+
+  public:
+    struct outgoing_params {
+      switch_event_t          *var_event;
+      switch_caller_profile_t *outbound_profile;
+      switch_core_session_t  **new_session;
+      switch_memory_pool_t   **pool;
+      switch_originate_flag_t  flags;
+      switch_call_cause_t     *cancel_cause;
+      switch_call_cause_t      fail_cause;
+    };
+
+    FSConnection(OpalCall & call,
+                 FSEndPoint & endpoint,
+                 unsigned options,
+                 OpalConnection::StringOptions * stringOptions,
+                 outgoing_params * params);
+
+    virtual bool OnOutgoingSetUp();
+    virtual bool OnIncoming();
+    virtual void OnEstablished();
+    virtual void OnReleased();
+    virtual PBoolean SetAlerting(const PString & calleeName, PBoolean withMedia);
+    virtual OpalMediaStream *CreateMediaStream(const OpalMediaFormat &, unsigned, PBoolean);
+    virtual void OnPatchMediaStream(PBoolean isSource, OpalMediaPatch & patch);
+    virtual OpalMediaFormatList GetMediaFormats() const;
+    virtual PBoolean SendUserInputTone(char tone, unsigned duration);
+#if HAVE_T38
+    virtual void OnSwitchedT38(bool toT38, bool success);
+    virtual void OnSwitchingT38(bool toT38);
+#endif
+
+    DECLARE_CALLBACK0(on_init);
+    DECLARE_CALLBACK0(on_destroy);
+    DECLARE_CALLBACK0(on_routing);
+    DECLARE_CALLBACK0(on_execute);
+    DECLARE_CALLBACK0(on_hangup);
+
+    DECLARE_CALLBACK0(on_exchange_media);
+    DECLARE_CALLBACK0(on_soft_execute);
+
+    DECLARE_CALLBACK1(kill_channel, int, sig);
+    DECLARE_CALLBACK1(send_dtmf, const switch_dtmf_t *, dtmf);
+    DECLARE_CALLBACK1(receive_message, switch_core_session_message_t *, msg);
+    DECLARE_CALLBACK1(receive_event, switch_event_t *, event);
+    DECLARE_CALLBACK0(state_change);
+    DECLARE_CALLBACK3(read_audio_frame, switch_frame_t **, frame, switch_io_flag_t, flags, int, stream_id);
+    DECLARE_CALLBACK3(write_audio_frame, switch_frame_t *, frame, switch_io_flag_t, flags, int, stream_id);
+    DECLARE_CALLBACK3(read_video_frame, switch_frame_t **, frame, switch_io_flag_t, flag, int, stream_id);
+    DECLARE_CALLBACK3(write_video_frame, switch_frame_t *, frame, switch_io_flag_t, flag, int, stream_id);
+
+    __inline switch_core_session_t *GetSession() const
+    {
+        return m_fsSession;
+    }
+
+    __inline switch_channel_t *GetChannel() const
+    {
+        return m_fsChannel;
+    }
+
+    bool IsChannelReady() const
+    {
+        return m_fsChannel != NULL && switch_channel_ready(m_fsChannel);
+    }
+
+    bool NeedFlushAudio()
+    {
+        if (!m_flushAudio)
+          return false;
+        m_flushAudio = false;
+        return true;
+    }
+
+  protected:
+    void SetCodecs();
+    bool WaitForMedia();
+#if HAVE_T38
+    void SetT38OptionsFromMediaFormat(const OpalMediaFormat & mediaFormat, const char * varname);
+    bool IndicateSwitchedT38();
+    void AbortT38();
+#endif
+
+    switch_status_t read_frame(const OpalMediaType & mediaType, switch_frame_t **frame, switch_io_flag_t flags);
+    switch_status_t write_frame(const OpalMediaType & mediaType, const switch_frame_t *frame, switch_io_flag_t flags);
+
+  private:
+    FSEndPoint            &m_endpoint;
+    switch_core_session_t *m_fsSession;
+    switch_channel_t      *m_fsChannel;
+    PSyncPoint             m_rxAudioOpened;
+    PSyncPoint             m_txAudioOpened;
+    OpalMediaFormatList    m_switchMediaFormats;
+
+    // If FS ever supports more than one audio and one video, this needs to change
+    switch_timer_t m_read_timer;
+    switch_codec_t m_read_codec;
+    switch_codec_t m_write_codec;
+
+    switch_timer_t m_vid_read_timer;
+    switch_codec_t m_vid_read_codec;
+    switch_codec_t m_vid_write_codec;
+
+    switch_frame_t m_dummy_frame;
+
+    bool m_flushAudio;
+    bool m_udptl;
+
+    friend PBoolean FSMediaStream::Open();
+};
+
+
+#endif /* __FREESWITCH_MOD_OPAL__ */
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:nil
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:s:
+ */
index 40ee41139a55fd63c620471d995920b106e14ade..327c5f6b6e184fa90367cd651625936668cc4edc 100644 (file)
    such a type exists and the standard includes do not define it. */
 #cmakedefine uint8_t unsigned char
 
-#ifdef HAVE_INTTYPES_H\r
-#include <inttypes.h>\r
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
 #endif
 
 #include <stdlib.h>
 
 /* AMF number */
-typedef\r
-#if SIZEOF_FLOAT == 8\r
-float\r
-#elif SIZEOF_DOUBLE == 8\r
-double\r
-#elif SIZEOF_LONG_DOUBLE == 8\r
-long double\r
-#else\r
-uint64_t\r
-#endif\r
+typedef
+#if SIZEOF_FLOAT == 8
+float
+#elif SIZEOF_DOUBLE == 8
+double
+#elif SIZEOF_LONG_DOUBLE == 8
+long double
+#else
+uint64_t
+#endif
 number64_t;
 
 /* custom read/write function type */
-typedef size_t (*read_proc_t)(void * out_buffer, size_t size, void * user_data);\r
+typedef size_t (*read_proc_t)(void * out_buffer, size_t size, void * user_data);
 typedef size_t (*write_proc_t)(const void * in_buffer, size_t size, void * user_data);
 
 #endif /* __AMF_H__ */
index 6aa25587d30e770f6c37812bf096b735ac7b0d2a..1575944b4b7f829efab4862aa33872c3f0cf731f 100644 (file)
@@ -1 +1 @@
-#define PERL_LIB "@PERL_LIB@"\r
+#define PERL_LIB "@PERL_LIB@"
index e665e9e16e734a21582b84dc1bcabd01eb9fd130..24716fd2e6812eec9cb622f44bf52a389991c7a3 100644 (file)
@@ -49,9 +49,9 @@
 #include <math.h>
 #include <ctype.h>
 
-void gregorian_to_jalali(/* output */ int *j_y, int *j_m, int *j_d,\r
+void gregorian_to_jalali(/* output */ int *j_y, int *j_m, int *j_d,
                          /*  input */ int  g_y, int  g_m, int  g_d);
-void jalali_to_gregorian(/* output */ int *g_y, int *g_m, int *g_d,\r
+void jalali_to_gregorian(/* output */ int *g_y, int *g_m, int *g_d,
                          /*  input */ int  j_y, int  j_m, int  j_d);
 
 SWITCH_MODULE_LOAD_FUNCTION(mod_say_fa_load);
@@ -575,108 +575,108 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_say_fa_load)
 int g_days_in_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
 int j_days_in_month[12] = {31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29};
 
-void gregorian_to_jalali(int *j_y, int *j_m, int *j_d,\r
-                                                int  g_y, int  g_m, int  g_d)\r
-{\r
-   int gy, gm, gd;\r
-   int jy, jm, jd;\r
-   long g_day_no, j_day_no;\r
-   int j_np;\r
\r
-   int i;\r
-\r
-   gy = g_y-1600;\r
-   gm = g_m-1;\r
-   gd = g_d-1;\r
\r
-   g_day_no = 365*gy+(gy+3)/4-(gy+99)/100+(gy+399)/400;\r
-   for (i=0;i<gm;++i)\r
-      g_day_no += g_days_in_month[i];\r
-   if (gm>1 && ((gy%4==0 && gy%100!=0) || (gy%400==0)))\r
-      /* leap and after Feb */\r
-      ++g_day_no;\r
-   g_day_no += gd;\r
\r
-   j_day_no = g_day_no-79;\r
\r
-   j_np = j_day_no / 12053;\r
-   j_day_no %= 12053;\r
\r
-   jy = 979+33*j_np+4*(j_day_no/1461);\r
-   j_day_no %= 1461;\r
\r
-   if (j_day_no >= 366) {\r
-      jy += (j_day_no-1)/365;\r
-      j_day_no = (j_day_no-1)%365;\r
-   }\r
\r
-   for (i = 0; i < 11 && j_day_no >= j_days_in_month[i]; ++i) {\r
-      j_day_no -= j_days_in_month[i];\r
-   }\r
-   jm = i+1;\r
-   jd = j_day_no+1;\r
-   *j_y = jy;\r
-   *j_m = jm;\r
-   *j_d = jd;\r
+void gregorian_to_jalali(int *j_y, int *j_m, int *j_d,
+                                                int  g_y, int  g_m, int  g_d)
+{
+   int gy, gm, gd;
+   int jy, jm, jd;
+   long g_day_no, j_day_no;
+   int j_np;
+   int i;
+
+   gy = g_y-1600;
+   gm = g_m-1;
+   gd = g_d-1;
+   g_day_no = 365*gy+(gy+3)/4-(gy+99)/100+(gy+399)/400;
+   for (i=0;i<gm;++i)
+      g_day_no += g_days_in_month[i];
+   if (gm>1 && ((gy%4==0 && gy%100!=0) || (gy%400==0)))
+      /* leap and after Feb */
+      ++g_day_no;
+   g_day_no += gd;
+   j_day_no = g_day_no-79;
+   j_np = j_day_no / 12053;
+   j_day_no %= 12053;
+   jy = 979+33*j_np+4*(j_day_no/1461);
+   j_day_no %= 1461;
+   if (j_day_no >= 366) {
+      jy += (j_day_no-1)/365;
+      j_day_no = (j_day_no-1)%365;
+   }
+   for (i = 0; i < 11 && j_day_no >= j_days_in_month[i]; ++i) {
+      j_day_no -= j_days_in_month[i];
+   }
+   jm = i+1;
+   jd = j_day_no+1;
+   *j_y = jy;
+   *j_m = jm;
+   *j_d = jd;
 }
 
-void jalali_to_gregorian(int *g_y, int *g_m, int *g_d,\r
-                                                int  j_y, int  j_m, int  j_d)\r
-{\r
-   int gy, gm, gd;\r
-   int jy, jm, jd;\r
-   long g_day_no, j_day_no;\r
-   int leap;\r
-\r
-   int i;\r
-\r
-   jy = j_y-979;\r
-   jm = j_m-1;\r
-   jd = j_d-1;\r
-\r
-   j_day_no = 365*jy + (jy/33)*8 + (jy%33+3)/4;\r
-   for (i=0; i < jm; ++i)\r
-      j_day_no += j_days_in_month[i];\r
-\r
-   j_day_no += jd;\r
-\r
-   g_day_no = j_day_no+79;\r
-\r
-   gy = 1600 + 400*(g_day_no/146097); /* 146097 = 365*400 + 400/4 - 400/100 + 400/400 */\r
-   g_day_no = g_day_no % 146097;\r
-\r
-   leap = 1;\r
-   if (g_day_no >= 36525) /* 36525 = 365*100 + 100/4 */\r
-   {\r
-      g_day_no--;\r
-      gy += 100*(g_day_no/36524); /* 36524 = 365*100 + 100/4 - 100/100 */\r
-      g_day_no = g_day_no % 36524;\r
-      \r
-      if (g_day_no >= 365)\r
-         g_day_no++;\r
-      else\r
-         leap = 0;\r
-   }\r
-\r
-   gy += 4*(g_day_no/1461); /* 1461 = 365*4 + 4/4 */\r
-   g_day_no %= 1461;\r
-\r
-   if (g_day_no >= 366) {\r
-      leap = 0;\r
-\r
-      g_day_no--;\r
-      gy += g_day_no/365;\r
-      g_day_no = g_day_no % 365;\r
-   }\r
-\r
-   for (i = 0; g_day_no >= g_days_in_month[i] + (i == 1 && leap); i++)\r
-      g_day_no -= g_days_in_month[i] + (i == 1 && leap);\r
-   gm = i+1;\r
-   gd = g_day_no+1;\r
-\r
-   *g_y = gy;\r
-   *g_m = gm;\r
-   *g_d = gd;\r
+void jalali_to_gregorian(int *g_y, int *g_m, int *g_d,
+                                                int  j_y, int  j_m, int  j_d)
+{
+   int gy, gm, gd;
+   int jy, jm, jd;
+   long g_day_no, j_day_no;
+   int leap;
+
+   int i;
+
+   jy = j_y-979;
+   jm = j_m-1;
+   jd = j_d-1;
+
+   j_day_no = 365*jy + (jy/33)*8 + (jy%33+3)/4;
+   for (i=0; i < jm; ++i)
+      j_day_no += j_days_in_month[i];
+
+   j_day_no += jd;
+
+   g_day_no = j_day_no+79;
+
+   gy = 1600 + 400*(g_day_no/146097); /* 146097 = 365*400 + 400/4 - 400/100 + 400/400 */
+   g_day_no = g_day_no % 146097;
+
+   leap = 1;
+   if (g_day_no >= 36525) /* 36525 = 365*100 + 100/4 */
+   {
+      g_day_no--;
+      gy += 100*(g_day_no/36524); /* 36524 = 365*100 + 100/4 - 100/100 */
+      g_day_no = g_day_no % 36524;
+      
+      if (g_day_no >= 365)
+         g_day_no++;
+      else
+         leap = 0;
+   }
+
+   gy += 4*(g_day_no/1461); /* 1461 = 365*4 + 4/4 */
+   g_day_no %= 1461;
+
+   if (g_day_no >= 366) {
+      leap = 0;
+
+      g_day_no--;
+      gy += g_day_no/365;
+      g_day_no = g_day_no % 365;
+   }
+
+   for (i = 0; g_day_no >= g_days_in_month[i] + (i == 1 && leap); i++)
+      g_day_no -= g_days_in_month[i] + (i == 1 && leap);
+   gm = i+1;
+   gd = g_day_no+1;
+
+   *g_y = gy;
+   *g_m = gm;
+   *g_d = gd;
 }
 
 /* For Emacs:
index b1e0db9b52bcc5737507655c625654b119094631..a0b9d5b8634f6c1fa99d0b4d1458481191e64d32 100644 (file)
-/*\r
- * Copyright (c) 2007-2014, Anthony Minessale II\r
- * All rights reserved.\r
- * \r
- * Redistribution and use in source and binary forms, with or without\r
- * modification, are permitted provided that the following conditions\r
- * are met:\r
- * \r
- * * Redistributions of source code must retain the above copyright\r
- * notice, this list of conditions and the following disclaimer.\r
- * \r
- * * Redistributions in binary form must reproduce the above copyright\r
- * notice, this list of conditions and the following disclaimer in the\r
- * documentation and/or other materials provided with the distribution.\r
- * \r
- * * Neither the name of the original author; nor the names of any contributors\r
- * may be used to endorse or promote products derived from this software\r
- * without specific prior written permission.\r
- * \r
- * \r
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
- * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER\r
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\r
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\r
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
- *\r
- * The Initial Developer of the Original Code is\r
- * Anthony Minessale II <anthm@freeswitch.org>\r
- * Portions created by the Initial Developer are Copyright (C)\r
- * the Initial Developer. All Rights Reserved.\r
- *\r
- * Contributor(s):\r
- * \r
- * Anthony Minessale II <anthm@freeswitch.org>\r
- * Michael B. Murdock <mike@mmurdock.org>\r
- * António Silva <asilva@wirelessmundi.com>\r
- *\r
- * mod_say_pt.c -- Say for Portuguese\r
- *\r
- */\r
-\r
-#include <switch.h>\r
-#include <math.h>\r
-#include <ctype.h>\r
-\r
-SWITCH_MODULE_LOAD_FUNCTION(mod_say_pt_load);\r
-SWITCH_MODULE_DEFINITION(mod_say_pt, mod_say_pt_load, NULL, NULL);\r
-\r
-#define say_num(num, meth) {                                                                                   \\r
-               char tmp[80];                                                                                                   \\r
-               switch_status_t tstatus;                                                                                \\r
-               switch_say_method_t smeth = say_args->method;                                   \\r
-               switch_say_type_t stype = say_args->type;                                               \\r
-               say_args->type = SST_ITEMS; say_args->method = meth;                    \\r
-               switch_snprintf(tmp, sizeof(tmp), "%u", (unsigned)num);                 \\r
-               if ((tstatus =                                                                                                  \\r
-                        pt_say_general_count(session, tmp, say_args, args))            \\r
-                       != SWITCH_STATUS_SUCCESS) {                                                                     \\r
-                       return tstatus;                                                                                         \\r
-               }                                                                                                                               \\r
-               say_args->method = smeth; say_args->type = stype;                               \\r
-       }                                                                                                                                       \\r
-\r
-\r
-#define say_file(...) {                                                                                                        \\r
-               char tmp[80];                                                                                                   \\r
-               switch_status_t tstatus;                                                                                \\r
-               switch_snprintf(tmp, sizeof(tmp), __VA_ARGS__);                                 \\r
-               if ((tstatus =                                                                                                  \\r
-                        switch_ivr_play_file(session, NULL, tmp, args))                        \\r
-                       != SWITCH_STATUS_SUCCESS){                                                                      \\r
-                       return tstatus;                                                                                         \\r
-               }                                                                                                                               \\r
-               if (!switch_channel_ready(switch_core_session_get_channel(session))) { \\r
-                       return SWITCH_STATUS_FALSE;                                                                     \\r
-               }}                                                                                                                              \\r
-\r
-\r
-static switch_status_t play_group(switch_say_method_t method, int a, int b, int c, char *what, switch_core_session_t *session, switch_input_args_t *args)\r
-{\r
-\r
-       /*a => 1xx-9xx*/\r
-       if (a) {\r
-               switch (a) {\r
-               case 1:\r
-                       if (b || c) {\r
-                               say_file("digits/hundred.wav");\r
-                       } else {\r
-                               say_file("digits/100.wav");\r
-                       }\r
-                       break;\r
-               case 2:\r
-                       say_file("digits/200.wav");\r
-                       break;\r
-               case 3:\r
-                       say_file("digits/300.wav");\r
-                       break;\r
-               case 5:\r
-                       say_file("digits/500.wav");\r
-                       break;\r
-               default:\r
-                       say_file("digits/%d.wav", a);\r
-                       say_file("digits/hundreds.wav");\r
-                       break;\r
-               }\r
-               if (b || c) {\r
-                       say_file("currency/and.wav");\r
-               }\r
-       }\r
-       /* b => 1x - 9x */\r
-       if (b) {\r
-               if (b > 1) {\r
-                       if (method == SSM_COUNTED) {\r
-                               say_file("digits/h-%d0.wav", b);\r
-                       } else {\r
-                               say_file("digits/%d0.wav", b);\r
-                               if (c > 0) {\r
-                                       say_file("currency/and.wav");\r
-                               }\r
-                       }\r
-               } else {\r
-                       say_file("digits/%d%d.wav", b, c);\r
-                       c = 0;\r
-               }\r
-       }\r
-       /* c => 0 - 9*/\r
-       if (c) {\r
-               if (method == SSM_COUNTED) {\r
-                       say_file("digits/h-%d.wav", c);\r
-               } else {\r
-                       say_file("digits/%d.wav", c);\r
-               }\r
-       }\r
-\r
-       if (what && (a || b || c)) {\r
-               say_file(what);\r
-       }\r
-\r
-       return SWITCH_STATUS_SUCCESS;\r
-}\r
-\r
-static switch_status_t pt_say_general_count(switch_core_session_t *session,    char *tosay, switch_say_args_t *say_args, switch_input_args_t *args)\r
-{\r
-       int in;\r
-       int x = 0;\r
-       int places[9] = { 0 };\r
-       char sbuf[128] = "";\r
-       switch_status_t status;\r
-\r
-       if (say_args->method == SSM_ITERATED) {\r
-               if ((tosay = switch_strip_commas(tosay, sbuf, sizeof(sbuf)-1))) {\r
-                       char *p;\r
-                       for (p = tosay; p && *p; p++) {\r
-                               say_file("digits/%c.wav", *p);\r
-                       }\r
-               } else {\r
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n");\r
-                       return SWITCH_STATUS_GENERR;\r
-               }\r
-               return SWITCH_STATUS_SUCCESS;\r
-       }\r
-\r
-       if (!(tosay = switch_strip_commas(tosay, sbuf, sizeof(sbuf)-1)) || strlen(tosay) > 9) {\r
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n");\r
-               return SWITCH_STATUS_GENERR;\r
-       }\r
-\r
-       in = atoi(tosay);\r
-\r
-       if (in != 0) {\r
-               for (x = 8; x >= 0; x--) {\r
-                       int num = (int) pow(10, x);\r
-                       if ((places[(uint32_t) x] = in / num)) {\r
-                               in -= places[(uint32_t) x] * num;\r
-                       }\r
-               }\r
-\r
-               switch (say_args->method) {\r
-               case SSM_COUNTED:\r
-               case SSM_PRONOUNCED:\r
+/*
+ * Copyright (c) 2007-2014, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * 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.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER
+ * 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.
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Michael B. Murdock <mike@mmurdock.org>
+ * António Silva <asilva@wirelessmundi.com>
+ *
+ * mod_say_pt.c -- Say for Portuguese
+ *
+ */
+
+#include <switch.h>
+#include <math.h>
+#include <ctype.h>
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_say_pt_load);
+SWITCH_MODULE_DEFINITION(mod_say_pt, mod_say_pt_load, NULL, NULL);
+
+#define say_num(num, meth) {                                                                                   \
+               char tmp[80];                                                                                                   \
+               switch_status_t tstatus;                                                                                \
+               switch_say_method_t smeth = say_args->method;                                   \
+               switch_say_type_t stype = say_args->type;                                               \
+               say_args->type = SST_ITEMS; say_args->method = meth;                    \
+               switch_snprintf(tmp, sizeof(tmp), "%u", (unsigned)num);                 \
+               if ((tstatus =                                                                                                  \
+                        pt_say_general_count(session, tmp, say_args, args))            \
+                       != SWITCH_STATUS_SUCCESS) {                                                                     \
+                       return tstatus;                                                                                         \
+               }                                                                                                                               \
+               say_args->method = smeth; say_args->type = stype;                               \
+       }                                                                                                                                       \
+
+
+#define say_file(...) {                                                                                                        \
+               char tmp[80];                                                                                                   \
+               switch_status_t tstatus;                                                                                \
+               switch_snprintf(tmp, sizeof(tmp), __VA_ARGS__);                                 \
+               if ((tstatus =                                                                                                  \
+                        switch_ivr_play_file(session, NULL, tmp, args))                        \
+                       != SWITCH_STATUS_SUCCESS){                                                                      \
+                       return tstatus;                                                                                         \
+               }                                                                                                                               \
+               if (!switch_channel_ready(switch_core_session_get_channel(session))) { \
+                       return SWITCH_STATUS_FALSE;                                                                     \
+               }}                                                                                                                              \
+
+
+static switch_status_t play_group(switch_say_method_t method, int a, int b, int c, char *what, switch_core_session_t *session, switch_input_args_t *args)
+{
+
+       /*a => 1xx-9xx*/
+       if (a) {
+               switch (a) {
+               case 1:
+                       if (b || c) {
+                               say_file("digits/hundred.wav");
+                       } else {
+                               say_file("digits/100.wav");
+                       }
+                       break;
+               case 2:
+                       say_file("digits/200.wav");
+                       break;
+               case 3:
+                       say_file("digits/300.wav");
+                       break;
+               case 5:
+                       say_file("digits/500.wav");
+                       break;
+               default:
+                       say_file("digits/%d.wav", a);
+                       say_file("digits/hundreds.wav");
+                       break;
+               }
+               if (b || c) {
+                       say_file("currency/and.wav");
+               }
+       }
+       /* b => 1x - 9x */
+       if (b) {
+               if (b > 1) {
+                       if (method == SSM_COUNTED) {
+                               say_file("digits/h-%d0.wav", b);
+                       } else {
+                               say_file("digits/%d0.wav", b);
+                               if (c > 0) {
+                                       say_file("currency/and.wav");
+                               }
+                       }
+               } else {
+                       say_file("digits/%d%d.wav", b, c);
+                       c = 0;
+               }
+       }
+       /* c => 0 - 9*/
+       if (c) {
+               if (method == SSM_COUNTED) {
+                       say_file("digits/h-%d.wav", c);
+               } else {
+                       say_file("digits/%d.wav", c);
+               }
+       }
+
+       if (what && (a || b || c)) {
+               say_file(what);
+       }
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t pt_say_general_count(switch_core_session_t *session,    char *tosay, switch_say_args_t *say_args, switch_input_args_t *args)
+{
+       int in;
+       int x = 0;
+       int places[9] = { 0 };
+       char sbuf[128] = "";
+       switch_status_t status;
+
+       if (say_args->method == SSM_ITERATED) {
+               if ((tosay = switch_strip_commas(tosay, sbuf, sizeof(sbuf)-1))) {
+                       char *p;
+                       for (p = tosay; p && *p; p++) {
+                               say_file("digits/%c.wav", *p);
+                       }
+               } else {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n");
+                       return SWITCH_STATUS_GENERR;
+               }
+               return SWITCH_STATUS_SUCCESS;
+       }
+
+       if (!(tosay = switch_strip_commas(tosay, sbuf, sizeof(sbuf)-1)) || strlen(tosay) > 9) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n");
+               return SWITCH_STATUS_GENERR;
+       }
+
+       in = atoi(tosay);
+
+       if (in != 0) {
+               for (x = 8; x >= 0; x--) {
+                       int num = (int) pow(10, x);
+                       if ((places[(uint32_t) x] = in / num)) {
+                               in -= places[(uint32_t) x] * num;
+                       }
+               }
+
+               switch (say_args->method) {
+               case SSM_COUNTED:
+               case SSM_PRONOUNCED:
                        /* specific case, one million => um milhão */
                        if (!places[8] && !places[7] && (places[6] == 1)) {
                                say_file("digits/1.wav");
                                say_file("digits/million.wav");
-                       } else if ((status = play_group(SSM_PRONOUNCED, places[8], places[7], places[6], "digits/millions.wav", session, args)) != SWITCH_STATUS_SUCCESS) {\r
-                               return status;\r
-                       }\r
-                       if ((status = play_group(SSM_PRONOUNCED, places[5], places[4], places[3], "digits/thousand.wav", session, args)) != SWITCH_STATUS_SUCCESS) {\r
-                               return status;\r
-                       }\r
-                       if ((status = play_group(say_args->method, places[2], places[1], places[0], NULL, session, args)) != SWITCH_STATUS_SUCCESS) {\r
-                               return status;\r
-                       }\r
-                       break;\r
-               default:\r
-                       break;\r
-               }\r
-       } else {\r
-               say_file("digits/0.wav");\r
-       }\r
-\r
-       return SWITCH_STATUS_SUCCESS;\r
-}\r
-\r
-static switch_status_t pt_say_time(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, switch_input_args_t *args)\r
-{\r
-       int32_t t;\r
-       switch_time_t target = 0, target_now = 0;\r
-       switch_time_exp_t tm, tm_now;\r
-       uint8_t say_date = 0, say_time = 0, say_year = 0, say_month = 0, say_dow = 0, say_day = 0, say_yesterday = 0, say_today = 0;\r
-       switch_channel_t *channel = switch_core_session_get_channel(session);\r
-       const char *tz = switch_channel_get_variable(channel, "timezone");\r
-\r
-       if (say_args->type == SST_TIME_MEASUREMENT) {\r
-               int64_t hours = 0;\r
-               int64_t minutes = 0;\r
-               int64_t seconds = 0;\r
-               int64_t r = 0;\r
-\r
-               if (strchr(tosay, ':')) {\r
-                       char *tme = switch_core_session_strdup(session, tosay);\r
-                       char *p;\r
-\r
-                       if ((p = strrchr(tme, ':'))) {\r
-                               *p++ = '\0';\r
-                               seconds = atoi(p);\r
-                               if ((p = strchr(tme, ':'))) {\r
-                                       *p++ = '\0';\r
-                                       minutes = atoi(p);\r
-                                       hours = atoi(tme);\r
-                               } else {\r
-                                       minutes = atoi(tme);\r
-                               }\r
-                       }\r
-               } else {\r
-                       if ((seconds = atol(tosay)) <= 0) {\r
-                               seconds = (int64_t) switch_epoch_time_now(NULL);\r
-                       }\r
-\r
-                       if (seconds >= 60) {\r
-                               minutes = seconds / 60;\r
-                               r = seconds % 60;\r
-                               seconds = r;\r
-                       }\r
-\r
-                       if (minutes >= 60) {\r
-                               hours = minutes / 60;\r
-                               r = minutes % 60;\r
-                               minutes = r;\r
-                       }\r
-               }\r
-\r
-               if (hours) {\r
-                       say_num(hours, SSM_PRONOUNCED);\r
-                       if (hours == 1) {\r
-                               say_file("time/hour.wav");\r
-                       } else {\r
-                               say_file("time/hours.wav");\r
-                       }\r
-               } else {\r
-                       say_file("digits/0.wav");\r
-                       say_file("time/hours.wav");\r
-               }\r
-\r
-               if (minutes) {\r
-                       say_num(minutes, SSM_PRONOUNCED);\r
-                       if (minutes == 1) {\r
-                               say_file("time/minute.wav");\r
-                       } else {\r
-                               say_file("time/minutes.wav");\r
-                       }\r
-               } else {\r
-                       say_file("digits/0.wav");\r
-                       say_file("time/minutes.wav");\r
-               }\r
-\r
-               if (seconds) {\r
-                       say_num(seconds, SSM_PRONOUNCED);\r
-                       if (seconds == 1) {\r
-                               say_file("time/second.wav");\r
-                       } else {\r
-                               say_file("time/seconds.wav");\r
-                       }\r
-               } else {\r
-                       say_file("digits/0.wav");\r
-                       say_file("time/seconds.wav");\r
-               }\r
-\r
-               return SWITCH_STATUS_SUCCESS;\r
-       }\r
-\r
-       if ((t = atol(tosay)) > 0) {\r
-               target = switch_time_make(t, 0);\r
-               target_now = switch_micro_time_now();\r
-       } else {\r
-               target = switch_micro_time_now();\r
-               target_now = switch_micro_time_now();\r
-       }\r
-\r
-       if (tz) {\r
-               int check = atoi(tz);\r
-               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Timezone is [%s]\n", tz);\r
-               if (check) {\r
-                       switch_time_exp_tz(&tm, target, check);\r
-                       switch_time_exp_tz(&tm_now, target_now, check);\r
-               } else {\r
-                       switch_time_exp_tz_name(tz, &tm, target);\r
-                       switch_time_exp_tz_name(tz, &tm_now, target_now);\r
-               }\r
-       } else {\r
-               switch_time_exp_lt(&tm, target);\r
-               switch_time_exp_lt(&tm_now, target_now);\r
-       }\r
-\r
-       switch (say_args->type) {\r
-       case SST_CURRENT_DATE_TIME:\r
-               say_date = say_time = 1;\r
-               break;\r
-       case SST_CURRENT_DATE:\r
-               say_date = 1;\r
-               break;\r
-       case SST_CURRENT_TIME:\r
-               say_time = 1;\r
-               break;\r
-       case SST_SHORT_DATE_TIME:\r
-               say_time = 1;\r
-               if (tm.tm_year != tm_now.tm_year) {\r
-                       say_date = 1;\r
-                       break;\r
-               }\r
-               if (tm.tm_yday == tm_now.tm_yday) {\r
-                       say_today = 1;\r
-                       break;\r
-               }\r
-               if (tm.tm_yday == tm_now.tm_yday - 1) {\r
-                       say_yesterday = 1;\r
-                       break;\r
-               }\r
-               if (tm.tm_yday >= tm_now.tm_yday - 5) {\r
-                       say_dow = 1;\r
-                       break;\r
-               }\r
-               if (tm.tm_mon != tm_now.tm_mon) {\r
-                       say_month = say_day = say_dow = 1;\r
-                       break;\r
-               }\r
-\r
-               say_month = say_day = say_dow = 1;\r
-\r
-               break;\r
-       default:\r
-               break;\r
-       }\r
-\r
-       if (say_today) {\r
-               say_file("time/today.wav");\r
-       }\r
-       if (say_yesterday) {\r
-               say_file("time/yesterday.wav");\r
-       }\r
-       if (say_dow) {\r
-               say_file("time/day-%d.wav", tm.tm_wday);\r
-       }\r
-\r
-       if (say_date) {\r
-               say_year = say_month = say_day = say_dow = 1;\r
-               say_today = say_yesterday = 0;\r
-       }\r
-\r
-       if (say_month) {\r
-               say_file("time/mon-%d.wav", tm.tm_mon);\r
-       }\r
-       if (say_day) {\r
-               say_num(tm.tm_mday, SSM_COUNTED);\r
-       }\r
-       if (say_year) {\r
-               say_num(tm.tm_year + 1900, SSM_PRONOUNCED);\r
-       }\r
-\r
-       if (say_time) {\r
-               int32_t hour = tm.tm_hour, pm = 0;\r
-\r
-               if (say_date || say_today || say_yesterday || say_dow) {\r
-                       if (hour == 1) {\r
-                               say_file("time/at.wav");\r
-                       } else {\r
-                               say_file("time/ats.wav");\r
-                       }\r
-               }\r
-\r
-               if (hour > 12) {\r
-                       hour -= 12;\r
-                       pm = 1;\r
-               } else if (hour == 12) {\r
-                       pm = 1;\r
-               } else if (hour == 0) {\r
-                       hour = 12;\r
-                       pm = 0;\r
-               }\r
-\r
-               say_num(hour, SSM_PRONOUNCED);\r
-\r
-               if (tm.tm_min) {\r
-                       say_file("currency/and.wav");\r
-                       say_num(tm.tm_min, SSM_PRONOUNCED);\r
-               } else { \r
-                       say_file("time/oclock.wav");\r
-               }\r
-\r
-               say_file("time/%s.wav", pm ? "p-m" : "a-m");\r
-       }\r
-\r
-       return SWITCH_STATUS_SUCCESS;\r
-}\r
-\r
-\r
-static switch_status_t pt_say_money(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, switch_input_args_t *args)\r
-{\r
-       char sbuf[16] = "";                     /* enough for 999,999,999,999.99 (w/o the commas or leading $) */\r
-       char *dollars = NULL;\r
-       char *cents = NULL;\r
-\r
-       if (strlen(tosay) > 15 || !switch_strip_nonnumerics(tosay, sbuf, sizeof(sbuf)-1)) {\r
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n");\r
-               return SWITCH_STATUS_GENERR;\r
-       }\r
-\r
-       dollars = sbuf;\r
-\r
-       if ((cents = strchr(sbuf, '.'))) {\r
-               *cents++ = '\0';\r
-               if (strlen(cents) > 2) {\r
-                       cents[2] = '\0';\r
-               }\r
-       }\r
-\r
-       /* If positive sign - skip over" */\r
-       if (sbuf[0] == '+') {\r
-               dollars++;\r
-       }\r
-\r
-       /* If negative say "negative" */\r
-       if (sbuf[0] == '-') {\r
-               say_file("currency/negative.wav");\r
-               dollars++;\r
-       }\r
-\r
-       /* Say dollar amount */\r
-       pt_say_general_count(session, dollars, say_args, args);\r
-       if (atoi(dollars) == 1) {\r
-               say_file("currency/dollar.wav");\r
-       } else {\r
-               say_file("currency/dollars.wav");\r
-       }\r
-\r
-       /* Say "and" */\r
-       say_file("currency/and.wav");\r
-\r
-       /* Say cents */\r
-       if (cents) {\r
-               pt_say_general_count(session, cents, say_args, args);\r
-               if (atoi(cents) == 1) {\r
-                       say_file("currency/cent.wav");\r
-               } else {\r
-                       say_file("currency/cents.wav");\r
-               }\r
-       } else {\r
-               say_file("digits/0.wav");\r
-               say_file("currency/cents.wav");\r
-       }\r
-\r
-       return SWITCH_STATUS_SUCCESS;\r
-}\r
-\r
-\r
-\r
-static switch_status_t pt_say(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, switch_input_args_t *args)\r
-{\r
-\r
-       switch_say_callback_t say_cb = NULL;\r
-\r
-       switch (say_args->type) {\r
-       case SST_NUMBER:\r
-       case SST_ITEMS:\r
-       case SST_PERSONS:\r
-       case SST_MESSAGES:\r
-               say_cb = pt_say_general_count;\r
-               break;\r
-       case SST_TIME_MEASUREMENT:\r
-       case SST_CURRENT_DATE:\r
-       case SST_CURRENT_TIME:\r
-       case SST_CURRENT_DATE_TIME:\r
-       case SST_SHORT_DATE_TIME:\r
-               say_cb = pt_say_time;\r
-               break;\r
-       case SST_IP_ADDRESS:\r
-               return switch_ivr_say_ip(session, tosay, pt_say_general_count, say_args, args);\r
-               break;\r
-       case SST_NAME_SPELLED:\r
-       case SST_NAME_PHONETIC:\r
-               return switch_ivr_say_spell(session, tosay, say_args, args);\r
-               break;\r
-       case SST_CURRENCY:\r
-               say_cb = pt_say_money;\r
-               break;\r
-       default:\r
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown Say type=[%d]\n", say_args->type);\r
-               break;\r
-       }\r
-\r
-       if (say_cb) {\r
-               return say_cb(session, tosay, say_args, args);\r
-       }\r
-\r
-       return SWITCH_STATUS_FALSE;\r
-}\r
-\r
-SWITCH_MODULE_LOAD_FUNCTION(mod_say_pt_load)\r
-{\r
-       switch_say_interface_t *say_interface;\r
-       /* connect my internal structure to the blank pointer passed to me */\r
-       *module_interface = switch_loadable_module_create_module_interface(pool, modname);\r
-       say_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_SAY_INTERFACE);\r
-       say_interface->interface_name = "pt";\r
-       say_interface->say_function = pt_say;\r
-\r
-       /* indicate that the module should continue to be loaded */\r
-       return SWITCH_STATUS_SUCCESS;\r
-}\r
-\r
-/* For Emacs:\r
- * Local Variables:\r
- * mode:c\r
- * indent-tabs-mode:t\r
- * tab-width:4\r
- * c-basic-offset:4\r
- * End:\r
- * For VIM:\r
- * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:\r
+                       } else if ((status = play_group(SSM_PRONOUNCED, places[8], places[7], places[6], "digits/millions.wav", session, args)) != SWITCH_STATUS_SUCCESS) {
+                               return status;
+                       }
+                       if ((status = play_group(SSM_PRONOUNCED, places[5], places[4], places[3], "digits/thousand.wav", session, args)) != SWITCH_STATUS_SUCCESS) {
+                               return status;
+                       }
+                       if ((status = play_group(say_args->method, places[2], places[1], places[0], NULL, session, args)) != SWITCH_STATUS_SUCCESS) {
+                               return status;
+                       }
+                       break;
+               default:
+                       break;
+               }
+       } else {
+               say_file("digits/0.wav");
+       }
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t pt_say_time(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, switch_input_args_t *args)
+{
+       int32_t t;
+       switch_time_t target = 0, target_now = 0;
+       switch_time_exp_t tm, tm_now;
+       uint8_t say_date = 0, say_time = 0, say_year = 0, say_month = 0, say_dow = 0, say_day = 0, say_yesterday = 0, say_today = 0;
+       switch_channel_t *channel = switch_core_session_get_channel(session);
+       const char *tz = switch_channel_get_variable(channel, "timezone");
+
+       if (say_args->type == SST_TIME_MEASUREMENT) {
+               int64_t hours = 0;
+               int64_t minutes = 0;
+               int64_t seconds = 0;
+               int64_t r = 0;
+
+               if (strchr(tosay, ':')) {
+                       char *tme = switch_core_session_strdup(session, tosay);
+                       char *p;
+
+                       if ((p = strrchr(tme, ':'))) {
+                               *p++ = '\0';
+                               seconds = atoi(p);
+                               if ((p = strchr(tme, ':'))) {
+                                       *p++ = '\0';
+                                       minutes = atoi(p);
+                                       hours = atoi(tme);
+                               } else {
+                                       minutes = atoi(tme);
+                               }
+                       }
+               } else {
+                       if ((seconds = atol(tosay)) <= 0) {
+                               seconds = (int64_t) switch_epoch_time_now(NULL);
+                       }
+
+                       if (seconds >= 60) {
+                               minutes = seconds / 60;
+                               r = seconds % 60;
+                               seconds = r;
+                       }
+
+                       if (minutes >= 60) {
+                               hours = minutes / 60;
+                               r = minutes % 60;
+                               minutes = r;
+                       }
+               }
+
+               if (hours) {
+                       say_num(hours, SSM_PRONOUNCED);
+                       if (hours == 1) {
+                               say_file("time/hour.wav");
+                       } else {
+                               say_file("time/hours.wav");
+                       }
+               } else {
+                       say_file("digits/0.wav");
+                       say_file("time/hours.wav");
+               }
+
+               if (minutes) {
+                       say_num(minutes, SSM_PRONOUNCED);
+                       if (minutes == 1) {
+                               say_file("time/minute.wav");
+                       } else {
+                               say_file("time/minutes.wav");
+                       }
+               } else {
+                       say_file("digits/0.wav");
+                       say_file("time/minutes.wav");
+               }
+
+               if (seconds) {
+                       say_num(seconds, SSM_PRONOUNCED);
+                       if (seconds == 1) {
+                               say_file("time/second.wav");
+                       } else {
+                               say_file("time/seconds.wav");
+                       }
+               } else {
+                       say_file("digits/0.wav");
+                       say_file("time/seconds.wav");
+               }
+
+               return SWITCH_STATUS_SUCCESS;
+       }
+
+       if ((t = atol(tosay)) > 0) {
+               target = switch_time_make(t, 0);
+               target_now = switch_micro_time_now();
+       } else {
+               target = switch_micro_time_now();
+               target_now = switch_micro_time_now();
+       }
+
+       if (tz) {
+               int check = atoi(tz);
+               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Timezone is [%s]\n", tz);
+               if (check) {
+                       switch_time_exp_tz(&tm, target, check);
+                       switch_time_exp_tz(&tm_now, target_now, check);
+               } else {
+                       switch_time_exp_tz_name(tz, &tm, target);
+                       switch_time_exp_tz_name(tz, &tm_now, target_now);
+               }
+       } else {
+               switch_time_exp_lt(&tm, target);
+               switch_time_exp_lt(&tm_now, target_now);
+       }
+
+       switch (say_args->type) {
+       case SST_CURRENT_DATE_TIME:
+               say_date = say_time = 1;
+               break;
+       case SST_CURRENT_DATE:
+               say_date = 1;
+               break;
+       case SST_CURRENT_TIME:
+               say_time = 1;
+               break;
+       case SST_SHORT_DATE_TIME:
+               say_time = 1;
+               if (tm.tm_year != tm_now.tm_year) {
+                       say_date = 1;
+                       break;
+               }
+               if (tm.tm_yday == tm_now.tm_yday) {
+                       say_today = 1;
+                       break;
+               }
+               if (tm.tm_yday == tm_now.tm_yday - 1) {
+                       say_yesterday = 1;
+                       break;
+               }
+               if (tm.tm_yday >= tm_now.tm_yday - 5) {
+                       say_dow = 1;
+                       break;
+               }
+               if (tm.tm_mon != tm_now.tm_mon) {
+                       say_month = say_day = say_dow = 1;
+                       break;
+               }
+
+               say_month = say_day = say_dow = 1;
+
+               break;
+       default:
+               break;
+       }
+
+       if (say_today) {
+               say_file("time/today.wav");
+       }
+       if (say_yesterday) {
+               say_file("time/yesterday.wav");
+       }
+       if (say_dow) {
+               say_file("time/day-%d.wav", tm.tm_wday);
+       }
+
+       if (say_date) {
+               say_year = say_month = say_day = say_dow = 1;
+               say_today = say_yesterday = 0;
+       }
+
+       if (say_month) {
+               say_file("time/mon-%d.wav", tm.tm_mon);
+       }
+       if (say_day) {
+               say_num(tm.tm_mday, SSM_COUNTED);
+       }
+       if (say_year) {
+               say_num(tm.tm_year + 1900, SSM_PRONOUNCED);
+       }
+
+       if (say_time) {
+               int32_t hour = tm.tm_hour, pm = 0;
+
+               if (say_date || say_today || say_yesterday || say_dow) {
+                       if (hour == 1) {
+                               say_file("time/at.wav");
+                       } else {
+                               say_file("time/ats.wav");
+                       }
+               }
+
+               if (hour > 12) {
+                       hour -= 12;
+                       pm = 1;
+               } else if (hour == 12) {
+                       pm = 1;
+               } else if (hour == 0) {
+                       hour = 12;
+                       pm = 0;
+               }
+
+               say_num(hour, SSM_PRONOUNCED);
+
+               if (tm.tm_min) {
+                       say_file("currency/and.wav");
+                       say_num(tm.tm_min, SSM_PRONOUNCED);
+               } else { 
+                       say_file("time/oclock.wav");
+               }
+
+               say_file("time/%s.wav", pm ? "p-m" : "a-m");
+       }
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status_t pt_say_money(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, switch_input_args_t *args)
+{
+       char sbuf[16] = "";                     /* enough for 999,999,999,999.99 (w/o the commas or leading $) */
+       char *dollars = NULL;
+       char *cents = NULL;
+
+       if (strlen(tosay) > 15 || !switch_strip_nonnumerics(tosay, sbuf, sizeof(sbuf)-1)) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n");
+               return SWITCH_STATUS_GENERR;
+       }
+
+       dollars = sbuf;
+
+       if ((cents = strchr(sbuf, '.'))) {
+               *cents++ = '\0';
+               if (strlen(cents) > 2) {
+                       cents[2] = '\0';
+               }
+       }
+
+       /* If positive sign - skip over" */
+       if (sbuf[0] == '+') {
+               dollars++;
+       }
+
+       /* If negative say "negative" */
+       if (sbuf[0] == '-') {
+               say_file("currency/negative.wav");
+               dollars++;
+       }
+
+       /* Say dollar amount */
+       pt_say_general_count(session, dollars, say_args, args);
+       if (atoi(dollars) == 1) {
+               say_file("currency/dollar.wav");
+       } else {
+               say_file("currency/dollars.wav");
+       }
+
+       /* Say "and" */
+       say_file("currency/and.wav");
+
+       /* Say cents */
+       if (cents) {
+               pt_say_general_count(session, cents, say_args, args);
+               if (atoi(cents) == 1) {
+                       say_file("currency/cent.wav");
+               } else {
+                       say_file("currency/cents.wav");
+               }
+       } else {
+               say_file("digits/0.wav");
+               say_file("currency/cents.wav");
+       }
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+
+
+static switch_status_t pt_say(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, switch_input_args_t *args)
+{
+
+       switch_say_callback_t say_cb = NULL;
+
+       switch (say_args->type) {
+       case SST_NUMBER:
+       case SST_ITEMS:
+       case SST_PERSONS:
+       case SST_MESSAGES:
+               say_cb = pt_say_general_count;
+               break;
+       case SST_TIME_MEASUREMENT:
+       case SST_CURRENT_DATE:
+       case SST_CURRENT_TIME:
+       case SST_CURRENT_DATE_TIME:
+       case SST_SHORT_DATE_TIME:
+               say_cb = pt_say_time;
+               break;
+       case SST_IP_ADDRESS:
+               return switch_ivr_say_ip(session, tosay, pt_say_general_count, say_args, args);
+               break;
+       case SST_NAME_SPELLED:
+       case SST_NAME_PHONETIC:
+               return switch_ivr_say_spell(session, tosay, say_args, args);
+               break;
+       case SST_CURRENCY:
+               say_cb = pt_say_money;
+               break;
+       default:
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown Say type=[%d]\n", say_args->type);
+               break;
+       }
+
+       if (say_cb) {
+               return say_cb(session, tosay, say_args, args);
+       }
+
+       return SWITCH_STATUS_FALSE;
+}
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_say_pt_load)
+{
+       switch_say_interface_t *say_interface;
+       /* connect my internal structure to the blank pointer passed to me */
+       *module_interface = switch_loadable_module_create_module_interface(pool, modname);
+       say_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_SAY_INTERFACE);
+       say_interface->interface_name = "pt";
+       say_interface->say_function = pt_say;
+
+       /* indicate that the module should continue to be loaded */
+       return SWITCH_STATUS_SUCCESS;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
  */