summaryrefslogtreecommitdiffstats
path: root/private/crt32/convert/mbstowcs.c
blob: 739b91c5ef467af5030d356d040061e8a8655be6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/***
*mbstowcs.c - Convert multibyte char string to wide char string.
*
*       Copyright (c) 1990-1993, Microsoft Corporation.  All rights reserved.
*
*Purpose:
*       Convert a multibyte char string into the equivalent wide char string.
*
*Revision History:
*       08-24-90  KRS   Module created.
*       03-20-91  KRS   Ported from 16-bit tree.
*       10-16-91  ETC   Locale support under _INTL switch.
*       12-09-91  ETC   Updated nlsapi; added multithread.
*       08-20-92  KRS   Activated NLSAPI support.
*       08-31-92  SRW   Allow INTL definition to be conditional for building ntcrt.lib
*       09-02-92  SRW   Get _INTL definition via ..\crt32.def
*       02-09-93  CFW   Always stuff WC 0 at end of output string of room (non _INTL).
*       04-06-93  SKS   Replace _CRTAPI* with _cdecl
*       05-03-93  CFW   Return pointer == NULL, return size, plus massive cleanup.
*       06-02-93  SRW   ignore _INTL if _NTSUBSET_ defined.
*       09-27-93  CFW   Avoid cast bug.
*       10-26-93  CFW   Test for invalid MB chars using global preset flag.
*       01-14-94  SRW   if _NTSUBSET_ defined call Rtl functions
*       07-06-94  SRW   Call mblen instead of _mbstrlen for input to Rtl function
*       07-07-94  MMS/IJH  Undo previous change,  Call _mbstrlen
*
*******************************************************************************/

#ifdef _NTSUBSET_
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#endif
#include <cruntime.h>
#include <internal.h>
#include <stdlib.h>
#include <os2dll.h>
#include <locale.h>
#include <setlocal.h>
#include <errno.h>
#include <assert.h>

/***
*size_t mbstowcs() - Convert multibyte char string to wide char string.
*
*Purpose:
*       Convert a multi-byte char string into the equivalent wide char string,
*       according to the LC_CTYPE category of the current locale.
*       [ANSI].
*
*       NOTE:  Currently, the C libraries support the "C" locale only.
*              Non-C locale support now available under _INTL switch.
*Entry:
*       wchar_t *pwcs = pointer to destination wide character string buffer
*       const char *s = pointer to source multibyte character string
*       size_t      n = maximum number of wide characters to store
*
*Exit:
*       If s != NULL, returns:   number of words modified (<=n)
*                               (size_t)-1 (if invalid mbcs)
*
*Exceptions:
*       Returns (size_t)-1 if s is NULL or invalid mbcs character encountered
*
*******************************************************************************/

#ifdef MTHREAD
size_t _CRTAPI1 mbstowcs
        (
        wchar_t  *pwcs,
        const char *s,
        size_t n
        )
{
        size_t retval;

        _mlock (_LC_CTYPE_LOCK);
        retval = _mbstowcs_lk(pwcs, s, n);
        _munlock (_LC_CTYPE_LOCK);
        return retval;
}
#endif /* MTHREAD */

#ifdef MTHREAD
size_t _CRTAPI1 _mbstowcs_lk
#else
size_t _CRTAPI1 mbstowcs
#endif
        (
        wchar_t  *pwcs,
        const char *s,
        size_t n
        )
{
        int retval = 0;
        size_t count = 0;

        if (pwcs && n == 0)
                return (size_t) 0;

        assert(s != NULL);

        /* if destination string exists, fill it in */
        if (pwcs)
        {
#if defined(_INTL) && !defined(_NTSUBSET_)
                if (_lc_handle[LC_CTYPE] == _CLOCALEHANDLE &&
                _lc_codepage == _CLOCALECP)
                {
#endif /* _INTL */
#ifdef _NTSUBSET_
                        {
                        NTSTATUS Status;
                        int size;

                        size = _mbstrlen(s);
                        Status = RtlMultiByteToUnicodeN(pwcs, n * sizeof( *pwcs ), (PULONG)&size, s, size+1 );
                        if (!NT_SUCCESS(Status))
                        {
                                errno = EILSEQ;
                                size = -1;
                        } else {
                                size = size / sizeof( *pwcs );
                                if (pwcs[size-1] == L'\0') {
                                    size -= 1;
                                }
                        }

                        return size;
                        }
#else
                        /* C locale: easy and fast */
                        while (count < n)
                        {
                                *pwcs = (wchar_t) ((unsigned char)s[count]);
                                if (!s[count])
                                        return count;
                                count++;
                                pwcs++;
                        }
#endif
                        return count;
#if defined(_INTL) && !defined(_NTSUBSET_)
                } else {
                        /* Assume that usually the buffer is large enough */
                        if ((count=MultiByteToWideChar(_lc_codepage, MB_PRECOMPOSED|__invalid_mb_chars,
                        s, -1, pwcs, n)) != 0)
                                return count - 1;

                        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
                        {
                                errno = EILSEQ;
                                return (size_t)-1;
                        }

                        /* buffer not large enough, must do char by char */
                        while (count < n)
                        {
                                if ((retval = MultiByteToWideChar (_lc_codepage, MB_PRECOMPOSED,
                                s, MB_CUR_MAX, pwcs, 1)) == 0)
                                {
                                        errno = EILSEQ;
                                        return (size_t)-1;
                                }
                                if (!*s)
                                        return count;
                                if (isleadbyte((unsigned char)*s))
                                        s++;
                                s++;
                                count++;
                                pwcs++;
                        }
                        return count;
                }
#endif /* _INTL */
        }
        else { /* pwcs == NULL, get size only, s must be NUL-terminated */
#if defined(_INTL) && !defined(_NTSUBSET_)
                if (_lc_handle[LC_CTYPE] == _CLOCALEHANDLE &&
                _lc_codepage == _CLOCALECP)
#endif /* _INTL */
                        return strlen(s);

#if defined(_INTL) && !defined(_NTSUBSET_)
                else {
                        if ((count=MultiByteToWideChar(_lc_codepage, MB_PRECOMPOSED|__invalid_mb_chars,
                        s, -1, NULL, 0)) == 0)
                        {
                                        errno = EILSEQ;
                                        return (size_t)-1;
                        }

                        return count - 1;
                }
#endif /* _INTL */
        }
}