1 // xlocale internal header (from <locale>)
2 #pragma once
3 #ifndef _XLOCALE_
4 #define _XLOCALE_
5 #ifndef RC_INVOKED
6 #include <climits>
7 #include <cstring>
8 #include <stdexcept>
9 #include <typeinfo>
10 #include <xdebug>
11 #include <xlocinfo>
12
13 #ifdef _MSC_VER
14  #pragma pack(push,_CRT_PACKING)
15  #pragma warning(push,3)
16  #pragma warning(disable:4412)
17 #endif  /* _MSC_VER */
18
19 _STD_BEGIN
20
21         // TEMPLATE CLASS _Locbase
22 template<class _Dummy>
23     class _Locbase
24     {    // define templatized category constants, instantiate on demand
25 public:
26     _PGLOBAL static const int collate = _M_COLLATE;
27     _PGLOBAL static const int ctype = _M_CTYPE;
28     _PGLOBAL static const int monetary = _M_MONETARY;
29     _PGLOBAL static const int numeric = _M_NUMERIC;
30     _PGLOBAL static const int time = _M_TIME;
31     _PGLOBAL static const int messages = _M_MESSAGES;
32     _PGLOBAL static const int all = _M_ALL;
33     _PGLOBAL static const int none = 0;
34     };
35
36 template<class _Dummy>
37     const int _Locbase<_Dummy>::collate;
38 template<class _Dummy>
39     const int _Locbase<_Dummy>::ctype;
40 template<class _Dummy>
41     const int _Locbase<_Dummy>::monetary;
42 template<class _Dummy>
43     const int _Locbase<_Dummy>::numeric;
44 template<class _Dummy>
45     const int _Locbase<_Dummy>::time;
46 template<class _Dummy>
47     const int _Locbase<_Dummy>::messages;
48 template<class _Dummy>
49     const int _Locbase<_Dummy>::all;
50 template<class _Dummy>
51     const int _Locbase<_Dummy>::none;
52
53         // CLASS locale
54 class locale;
55 template<class _Facet>
56     const _Facet& __CRTDECL use_facet(const locale&);
57
58 // warning 4412 is benign here
59 #pragma warning(push)
60 #pragma warning(disable:4412)
61 class _CRTIMP2_PURE locale
62     : public _Locbase<int>
63     {    // nonmutable collection of facets that describe a locale
64 public:
65     typedef int category;
66
67             // CLASS id
68     class _CRTIMP2_PURE id
69         {    // identifier stamp, unique for each distinct kind of facet
70     public:
71         __CLR_OR_THIS_CALL id(size_t _Val = 0)
72             : _Id(_Val)
73             {    // construct with specified stamp value
74             }
75
76         __CLR_OR_THIS_CALL operator size_t()
77             {    // get stamp, with lazy allocation
78             if (_Id == 0)
79                 {    // still zero, allocate stamp
80                 _BEGIN_LOCK(_LOCK_LOCALE)
81                     if (_Id == 0)
82                         _Id = ++_Id_cnt;
83                 _END_LOCK()
84                 }
85             return (_Id);
86             }
87
88     private:
89         __CLR_OR_THIS_CALL id(const id&);    // not defined
90         id& __CLR_OR_THIS_CALL operator=(const id&);    // not defined
91
92         size_t _Id;    // the identifier stamp
93         static _MRTIMP2_NPURE int& __cdecl _Id_cnt_func();
94 #ifdef _M_CEE_PURE
95         static int& _Id_cnt;    // static source of unique stamps
96 #else
97         __PURE_APPDOMAIN_GLOBAL static int _Id_cnt;    // static source of unique stamps
98 #endif
99         };
100
101     class _Locimp;
102
103             // class facet
104     class facet
105         {    // base class for all locale facets, performs reference counting
106         friend class locale;
107         friend class _Locimp;
108
109     public:
110         _CRTIMP2_PURE static size_t __CLRCALL_OR_CDECL _Getcat(const facet ** = 0,
111             const locale * = 0)
112             {    // get category value, or -1 if no corresponding C category
113             return ((size_t)(-1));
114             }
115
116         _CRTIMP2_PURE void __CLR_OR_THIS_CALL _Incref()
117             {    // safely increment the reference count
118             _BEGIN_LOCK(_LOCK_LOCALE)
119                 if (_Refs < (size_t)(-1))
120                     ++_Refs;
121             _END_LOCK()
122             }
123
124         _CRTIMP2_PURE facet *__CLR_OR_THIS_CALL _Decref()
125             {    // safely decrement the reference count, return this when dead
126             _BEGIN_LOCK(_LOCK_LOCALE)
127                 if (0 < _Refs && _Refs < (size_t)(-1))
128                     --_Refs;
129                 return (_Refs == 0 ? this : 0);
130             _END_LOCK()
131             }
132
133         void __CLR_OR_THIS_CALL _Register()
134             {
135 #if defined(_M_CEE)
136             facet_Register_m(this);
137 #else
138             facet_Register(this);
139 #endif
140             }
141
142   #if defined(_DEBUG) && !defined(_M_X64)
143         _CRTIMP2_PURE void * __CLRCALL_OR_CDECL operator new(size_t _Size)
144             {    // replace operator new
145             return (operator new(_Size, std::_DebugHeapTag_func(),
146                 __FILE__, __LINE__));
147             }
148
149         _CRTIMP2_PURE void * __CLRCALL_OR_CDECL operator new(size_t _Size,
150             const std::_DebugHeapTag_t& _Tag, _In_opt_z_ char *_File, int _Line)
151             {    // replace debugging operator new
152             return (::operator new(_Size, _Tag, _File, _Line));
153             }
154
155         _CRTIMP2_PURE void __CLRCALL_OR_CDECL operator delete(void *_Ptr,
156             const std::_DebugHeapTag_t&, _In_opt_z_ char *, int)
157             {    // replace debugging operator delete
158             operator delete(_Ptr);
159             }
160
161         _CRTIMP2_PURE void __CLRCALL_OR_CDECL operator delete(void *_Ptr)
162             {    // replace operator delete
163             std::_DebugHeapDelete((facet*)_Ptr);
164             }
165  #endif /* defined(_DEBUG) */
166
167
168 //    _PROTECTED:
169         _CRTIMP2_PURE virtual __CLR_OR_THIS_CALL ~facet()
170             {    // destroy the object
171             }
172
173     protected:
174         _CRTIMP2_PURE explicit __CLR_OR_THIS_CALL facet(size_t _Initrefs = 0)
175             : _Refs(_Initrefs)
176             {    // construct with initial reference count
177             }
178
179     private:
180 #if defined(_M_CEE)
181         static void __CLRCALL_OR_CDECL facet_Register_m(facet *);    // queue up lazy facet for destruction
182 #else
183         static void __CLRCALL_OR_CDECL facet_Register(facet *);    // queue up lazy facet for destruction
184 #endif
185
186         __CLR_OR_THIS_CALL facet(const facet&);    // not defined
187         facet& __CLR_OR_THIS_CALL operator=(const facet&);    // not defined
188
189         size_t _Refs;    // the reference count
190         };
191
192 #pragma warning(push)
193 #pragma warning(disable:4275)
194             // CLASS _Locimp
195     class _CRTIMP2_PURE _Locimp
196         : public facet
197         {    // reference-counted actual implementation of a locale
198     _PROTECTED:
199         __CLR_OR_THIS_CALL ~_Locimp()
200             {
201             _Locimp_dtor(this);
202             }
203
204     private:
205         static _MRTIMP2_NPURE void __cdecl _Locimp_dtor(_Locimp *); // destoy the object
206         static void _Locimp_ctor(_Locimp *,const _Locimp&);    // copy a _Locimp
207         static _MRTIMP2_NPURE void __cdecl _Locimp_Addfac(_Locimp *,facet *, size_t);    // add a facet
208         friend class locale;
209
210         __CLR_OR_THIS_CALL _Locimp(bool _Transparent = false)
211             : locale::facet(1), _Facetvec(0), _Facetcount(0),
212                 _Catmask(none), _Xparent(_Transparent), _Name("*")
213             { }
214         
215         __CLR_OR_THIS_CALL _Locimp(const _Locimp& _Right)
216             : locale::facet(1), _Facetvec(0), _Facetcount(_Right._Facetcount),
217                 _Catmask(_Right._Catmask), _Xparent(_Right._Xparent), _Name(_Right._Name)
218             {
219             _Locimp_ctor(this, _Right);
220             }
221         
222         void __CLR_OR_THIS_CALL _Addfac(facet *_Pfacet, size_t _Id)
223             {
224             _Locimp_Addfac(this, _Pfacet, _Id);
225             }
226
227         static _Locimp * _Makeloc(const _Locinfo&,
228             category, _Locimp *, const locale *);    // make essential facets
229
230         static void _Makewloc(const _Locinfo&,
231             category, _Locimp *, const locale *);    // make wchar_t facets
232
233  #ifdef _NATIVE_WCHAR_T_DEFINED
234         static void _Makeushloc(const _Locinfo&,
235             category, _Locimp *, const locale *);    // make ushort facets
236  #endif /* _NATIVE_WCHAR_T_DEFINED */
237
238         static void _Makexloc(const _Locinfo&,
239             category, _Locimp *, const locale *);    // make remaining facets
240
241         facet **_Facetvec;    // pointer to vector of facets
242         size_t _Facetcount;    // size of vector of facets
243         category _Catmask;    // mask describing implemented categories
244         bool _Xparent;    // true if locale is transparent
245         _STRING_CRT _Name;    // locale name, or "*" if not known
246
247         static _MRTIMP2_NPURE _Locimp *& __cdecl _Clocptr_func();    // pointer to "C" locale object
248 #ifdef _M_CEE_PURE
249         static _Locimp *&_Clocptr;    // pointer to "C" locale object
250 #else
251         __PURE_APPDOMAIN_GLOBAL static _Locimp *_Clocptr;    // pointer to "C" locale object
252 #endif
253 private:
254         _Locimp& __CLR_OR_THIS_CALL operator=(const _Locimp&);    // not defined
255     
256         };
257 #pragma warning(pop)
258
259     _DEPRECATED locale& __CLR_OR_THIS_CALL _Addfac(facet *_Fac, size_t _Id,
260         size_t _Catmask)
261         {
262         if (1 < this->_Ptr->_Refs)
263             {    // shared, make private copy before altering
264             this->_Ptr->_Decref();
265             this->_Ptr = _NEW_CRT _Locimp(*this->_Ptr);
266             }
267         this->_Ptr->_Addfac(_Fac, _Id);
268
269         if (_Catmask != 0)
270             this->_Ptr->_Name = "*";
271         return (*this);
272         }
273
274
275     template<class _Elem,
276         class _Traits,
277         class _Alloc>
278         bool __CLR_OR_THIS_CALL operator()(const basic_string<_Elem, _Traits, _Alloc>& _Left,
279             const basic_string<_Elem, _Traits, _Alloc>& _Right) const
280         {    // compare _Left and _Right strings using collate facet in locale
281         const std::collate<_Elem>& _Coll_fac =
282             std::use_facet<std::collate<_Elem> >(*this);
283
284         return (_Coll_fac.compare(_Left.c_str(), _Left.c_str() + _Left.size(),
285             _Right.c_str(), _Right.c_str() + _Right.size()) < 0);
286         }
287
288     template<class _Facet>
289         locale __CLR_OR_THIS_CALL combine(const locale& _Loc) const
290         {    // combine two locales
291         _Facet *_Facptr;
292
293         _TRY_BEGIN
294             _Facptr = (_Facet *)&std::use_facet<_Facet>(_Loc);
295         _CATCH_ALL
296             _THROW(runtime_error, "locale::combine facet missing");
297         _CATCH_END
298
299         _Locimp *_Newimp = _NEW_CRT _Locimp(*_Ptr);
300         _Newimp->_Addfac(_Facptr, _Facet::id);
301         _Newimp->_Catmask = 0;
302         _Newimp->_Name = "*";
303         return (locale(_Newimp));
304         }
305
306     template<class _Facet>
307         __CLR_OR_THIS_CALL locale(const locale& _Loc, const _Facet *_Facptr)
308             : _Ptr(_NEW_CRT _Locimp(*_Loc._Ptr))
309         {    // construct from _Loc, replacing facet with *_Facptr
310         if (_Facptr != 0)
311             {    // replace facet
312             _Ptr->_Addfac((_Facet *)_Facptr, _Facet::id);
313             if (_Facet::_Getcat() != (size_t)(-1))
314                 {    // no C category
315                 _Ptr->_Catmask = 0;
316                 _Ptr->_Name = "*";
317                 }
318             }
319         }
320
321
322     __CLR_OR_THIS_CALL locale() _THROW0()
323         : _Ptr(_Init())
324         {    // construct from current locale
325         _Getgloballocale()->_Incref();
326         }
327
328     __CLR_OR_THIS_CALL locale(_Uninitialized)
329         {    // defer construction
330         }
331
332     __CLR_OR_THIS_CALL locale(const locale& _Right) _THROW0()
333         : _Ptr(_Right._Ptr)
334         {    // construct by copying
335         _Ptr->_Incref();
336         }
337
338     __CLR_OR_THIS_CALL locale(const locale& _Loc, const locale& _Other,
339         category _Cat)     // construct from locale and category in another locale
340         : _Ptr(_NEW_CRT _Locimp(*_Loc._Ptr))
341         {    // construct a locale by copying named facets
342         _TRY_BEGIN
343             _BEGIN_LOCINFO(_Lobj(_Loc._Ptr->_Catmask, _Loc._Ptr->_Name.c_str()))
344                 _Locimp::_Makeloc(_Lobj._Addcats(_Cat & _Other._Ptr->_Catmask,
345                     _Other._Ptr->_Name.c_str()), _Cat, _Ptr, &_Other);
346             _END_LOCINFO()
347         _CATCH_ALL
348             _DELETE_CRT(_Ptr->_Decref());
349             _RERAISE;
350         _CATCH_END
351         }
352
353     explicit __CLR_OR_THIS_CALL locale(const char *_Locname,
354         category _Cat = all)     // construct from named locale for category
355         : _Ptr(_NEW_CRT _Locimp)
356         {    // construct a locale with named facets
357         _TRY_BEGIN
358         _Init();
359         _BEGIN_LOCINFO(_Lobj(_Cat, _Locname))
360             if (_Lobj._Getname().compare("*") == 0)
361                 _THROW(runtime_error, "bad locale name");
362             _Locimp::_Makeloc(_Lobj, _Cat, _Ptr, 0);
363         _END_LOCINFO()
364         _CATCH_ALL
365         _DELETE_CRT(_Ptr->_Decref());
366         _RERAISE;
367         _CATCH_END
368         }
369
370     __CLR_OR_THIS_CALL locale(const locale& _Loc, const char * _Locname,
371         category _Cat)     // construct from locale and category in named locale
372         : _Ptr(_NEW_CRT _Locimp(*_Loc._Ptr))
373         {    // construct a locale by copying, replacing named facets
374         _TRY_BEGIN
375         _BEGIN_LOCINFO(_Lobj(_Loc._Ptr->_Catmask, _Loc._Ptr->_Name.c_str()))
376             bool _Hadname = _Lobj._Getname().compare("*") != 0;
377             _Lobj._Addcats(_Cat, _Locname);
378
379             if (_Hadname && _Lobj._Getname().compare("*") == 0)
380                 _THROW(runtime_error, "bad locale name");
381             _Locimp::_Makeloc(_Lobj, _Cat, _Ptr, 0);
382         _END_LOCINFO()
383         _CATCH_ALL
384         _DELETE_CRT(_Ptr->_Decref());
385         _RERAISE;
386         _CATCH_END
387         }
388
389     __CLR_OR_THIS_CALL ~locale() _THROW0()
390         {    // destroy the object
391         if (_Ptr != 0)
392             _DELETE_CRT(_Ptr->_Decref());
393         }
394
395     locale& __CLR_OR_THIS_CALL operator=(const locale& _Right) _THROW0()
396         {    // assign a locale
397         if (_Ptr != _Right._Ptr)
398             {    // different implementation, point at new one
399             _DELETE_CRT(_Ptr->_Decref());
400             _Ptr = _Right._Ptr;
401             _Ptr->_Incref();
402             }
403         return (*this);
404         }
405
406     string __CLR_OR_THIS_CALL name() const
407         {    // return locale name
408         return (_Ptr->_Name);
409         }
410
411     const facet *__CLR_OR_THIS_CALL _Getfacet(size_t _Id) const     // get facet by id
412         {    // look up a facet in locale object
413         const facet *_Facptr = _Id < _Ptr->_Facetcount
414             ? _Ptr->_Facetvec[_Id] : 0;    // null if id off end
415         if (_Facptr != 0 || !_Ptr->_Xparent)
416             return (_Facptr);    // found facet or not transparent, return pointer
417         else
418             {    // look in current locale
419             locale::_Locimp *_Ptr = _Getgloballocale();
420             return (_Id < _Ptr->_Facetcount
421                 ? _Ptr->_Facetvec[_Id]    // get from current locale
422                 : 0);    // no entry in current locale
423             }
424         }
425
426
427     bool __CLR_OR_THIS_CALL operator==(const locale& _Loc) const
428         {    // compare locales for equality
429         return (_Ptr == _Loc._Ptr
430             || name().compare("*") != 0 && name().compare(_Loc.name()) == 0);
431         }
432
433     bool __CLR_OR_THIS_CALL operator!=(const locale& _Right) const
434         {    // test for locale inequality
435         return (!(*this == _Right));
436         }
437
438     static _MRTIMP2_NPURE const locale& __cdecl classic();    // return classic "C" locale
439
440     static _MRTIMP2_NPURE locale __cdecl global(const locale&);    // return current locale
441
442     static _MRTIMP2_NPURE locale __cdecl empty();    // return empty (transparent) locale
443
444 private:
445     locale(_Locimp *_Ptrimp)
446         : _Ptr(_Ptrimp)
447         {    // construct from _Locimp pointer
448         }
449
450     static _MRTIMP2_NPURE _Locimp *__cdecl _Getgloballocale();
451     static _MRTIMP2_NPURE _Locimp *__cdecl _Init();    // initialize locale
452     static _MRTIMP2_NPURE void __cdecl _Setgloballocale(void *);
453
454     _Locimp *_Ptr;    // pointer to locale implementation object
455     };
456 #pragma warning(pop)
457
458         // SUPPORT TEMPLATES
459 template<class _Facet>
460     struct _Facetptr
461     {    // store pointer to lazy facet for use_facet
462     __PURE_APPDOMAIN_GLOBAL static const locale::facet *_Psave;
463     };
464
465 template<class _Facet>
466     __PURE_APPDOMAIN_GLOBAL const locale::facet *_Facetptr<_Facet>::_Psave = 0;
467
468 template<class _Facet> inline _DEPRECATED
469     locale _Addfac(locale _Loc, const _Facet *_Facptr)
470         {    // add facet to locale -- retained
471         size_t _Cat = _Facet::_Getcat(0, 0);
472         locale _Newloc = _Loc._Addfac((_Facet *)_Facptr, _Facet::id, _Cat);
473
474         return (_Newloc);
475         }
476
477   #define _ADDFAC(loc, pfac)    locale(loc, pfac)    /* add facet to locale */
478
479   #define _USE(loc, fac)    \
480     use_facet<fac >(loc)    /* get facet reference from locale */
481
482 template<class _Facet> inline
483     const _Facet& __CRTDECL use_facet(const locale& _Loc)
484
485
486 {    // get facet reference from locale
487     _BEGIN_LOCK(_LOCK_LOCALE)    // the thread lock, make get atomic
488         const locale::facet *_Psave =
489             _Facetptr<_Facet>::_Psave;    // static pointer to lazy facet
490
491         size_t _Id = _Facet::id;
492         const locale::facet *_Pf = _Loc._Getfacet(_Id);
493
494         if (_Pf != 0)
495             ;    // got facet from locale
496         else if (_Psave != 0)
497             _Pf = _Psave;    // lazy facet already allocated
498         else if (_Facet::_Getcat(&_Psave, &_Loc) == (size_t)(-1))
499
500  #if _HAS_EXCEPTIONS
501         _THROW_NCEE(bad_cast, _EMPTY_ARGUMENT);    // lazy disallowed
502
503     #else /* _HAS_EXCEPTIONS */
504             abort();    // lazy disallowed
505     #endif /* _HAS_EXCEPTIONS */
506
507         else
508             {    // queue up lazy facet for destruction
509             _Pf = _Psave;
510             _Facetptr<_Facet>::_Psave = _Psave;
511
512             locale::facet *_Pfmod = (_Facet *)_Psave;
513             _Pfmod->_Incref();
514             _Pfmod->_Register();
515             }
516
517         return ((const _Facet&)(*_Pf));    // should be dynamic_cast
518     _END_LOCK()
519     }
520
521 template<class _Facet> inline _DEPRECATED
522     const _Facet& __CRTDECL use_facet(const locale& _Loc, const _Facet *,
523         bool = false)
524     {    // get facet reference from locale -- retained, 2/3 arg versions
525     return use_facet<_Facet>(_Loc);
526     }
527
528         // TEMPLATE FUNCTION _Getloctxt
529 template<class _Elem,
530     class _InIt> inline
531     int __CRTDECL _Getloctxt(_InIt& _First, _InIt& _Last, size_t _Numfields,
532         const _Elem *_Ptr)
533     {    // find field at _Ptr that matches longest in [_First, _Last)
534     for (size_t _Off = 0; _Ptr[_Off] != (_Elem)0; ++_Off)
535         if (_Ptr[_Off] == _Ptr[0])
536             ++_Numfields;    // add fields with leading mark to initial count
537     string _Str(_Numfields, '\0');    // one column counter for each field
538
539     int _Ans = -2;    // no candidates so far
540     for (size_t _Column = 1; ; ++_Column, ++_First, _Ans = -1)
541         {    // test each element against all viable fields
542         bool  _Prefix = false;    // seen at least one valid prefix
543         size_t _Off = 0;    // offset into fields
544         size_t _Field = 0;    // current field number
545
546         for (; _Field < _Numfields; ++_Field)
547             {    // test element at _Column in field _Field
548             for (; _Ptr[_Off] != (_Elem)0 && _Ptr[_Off] != _Ptr[0]; ++_Off)
549                 ;    // find beginning of field
550
Lines 551 ... 829 are skipped.
830
831         // STATIC codecvt::id OBJECT
832 template<class _Elem,
833     class _Byte,
834     class _Statype>
835     __PURE_APPDOMAIN_GLOBAL locale::id codecvt<_Elem, _Byte, _Statype>::id;
836
837         // CLASS codecvt<wchar_t, char, _Mbstatet>
838 template<> class _CRTIMP2_PURE codecvt<wchar_t, char, _Mbstatet>
839     : public codecvt_base
840     {    // facet for converting between wchar_t and char (_Byte) sequences
841 public:
842     typedef wchar_t _Elem;
843     typedef char _Byte;
844     typedef _Mbstatet _Statype;
845     typedef _Elem intern_type;
846     typedef _Byte extern_type;
847     typedef _Statype state_type;
848
849     result __CLR_OR_THIS_CALL in(_Statype& _State,
850         const _Byte *_First1, const _Byte *_Last1, const _Byte *& _Mid1,
851         _Elem *_First2, _Elem *_Last2, _Elem *& _Mid2) const
852         {    // convert bytes [_First1, _Last1) to [_First2, _Last)
853         return (do_in(_State,
854             _First1, _Last1, _Mid1, _First2, _Last2, _Mid2));
855         }
856
857     result __CLR_OR_THIS_CALL out(_Statype& _State,
858         const _Elem *_First1, const _Elem *_Last1, const _Elem *& _Mid1,
859         _Byte *_First2, _Byte *_Last2, _Byte *& _Mid2) const
860         {    // convert [_First1, _Last1) to bytes [_First2, _Last)
861         return (do_out(_State,
862             _First1, _Last1, _Mid1, _First2, _Last2, _Mid2));
863         }
864
865     result __CLR_OR_THIS_CALL unshift(_Statype& _State,
866         _Byte *_First2, _Byte *_Last2, _Byte *& _Mid2) const
867         {    // generate bytes to return to default shift state
868         return (do_unshift(_State,
869             _First2, _Last2, _Mid2));
870         }
871
872     int __CLR_OR_THIS_CALL length(const _Statype& _State, const _Byte *_First1,
873         const _Byte *_Last1, size_t _Count) const
874         {    // return min(_Count, converted length of bytes [_First1, _Last1))
875         return (do_length(_State, _First1, _Last1, _Count));
876         }
877
878     static _MRTIMP2_NPURE locale::id& __cdecl _Id_func();
879 #ifdef _M_CEE_PURE
880     static locale::id& id;    // unique facet id
881 #else
882     __PURE_APPDOMAIN_GLOBAL static locale::id id;    // unique facet id
883 #endif
884
885     explicit __CLR_OR_THIS_CALL codecvt(size_t _Refs = 0)
886         : codecvt_base(_Refs)
887         {    // construct from current locale
888         _BEGIN_LOCINFO(_Lobj)
889             _Init(_Lobj);
890         _END_LOCINFO()
891         }
892
893     __CLR_OR_THIS_CALL codecvt(const _Locinfo& _Lobj, size_t _Refs = 0)
894         : codecvt_base(_Refs)
895         {    // construct from specified locale
896         _Init(_Lobj);
897         }
898
899     static size_t __CLRCALL_OR_CDECL _Getcat(const locale::facet **_Ppf = 0,
900         const locale *_Ploc = 0)
901         {    // return locale category mask and construct standard facet
902         if (_Ppf != 0 && *_Ppf == 0)
903             *_Ppf = _NEW_CRT codecvt<_Elem, _Byte, _Statype>(
904                 _Locinfo(_Ploc->name()));
905         return (_X_CTYPE);
906         }
907
908 _PROTECTED:
909     virtual __CLR_OR_THIS_CALL ~codecvt()
910         {    // destroy the object
911         }
912
913 protected:
914     void __CLR_OR_THIS_CALL _Init(const _Locinfo& _Lobj)
915         {    // initialize from _Lobj
916         _Cvt = _Lobj._Getcvt();
917         }
918
919     virtual result __CLR_OR_THIS_CALL do_in(_Statype& _State,
920         const _Byte *_First1, const _Byte *_Last1, const _Byte *& _Mid1,
921             _Elem *_First2, _Elem *_Last2, _Elem *& _Mid2) const
922         {    // convert bytes [_First1, _Last1) to [_First2, _Last)
923         _DEBUG_RANGE(_First1, _Last1);
924         _DEBUG_RANGE(_First2, _Last2);
925         _Mid1 = _First1, _Mid2 = _First2;
926         result _Ans = _Mid1 == _Last1 ? ok : partial;
927         int _Bytes;
928
929         while (_Mid1 != _Last1 && _Mid2 != _Last2)
930             switch (_Bytes = _Mbrtowc(_Mid2, _Mid1, _Last1 - _Mid1,
931                 &_State, &_Cvt))
932             {    // test result of locale-specific mbrtowc call
933             case -2:    // partial conversion
934                 _Mid1 = _Last1;
935                 return (_Ans);
936
937             case -1:    // failed conversion
938                 return (error);
939
940             case 0:    // may have converted null character
941                 if (*_Mid2 == (_Elem)0)
942                     _Bytes = (int)::strlen(_Mid1) + 1;
943                 // fall through
944
945             default:    // converted _Bytes bytes to a wchar_t
946                 if (_Bytes == -3)
947                     _Bytes = 0;    // wchar_t generated from state info
948                 _Mid1 += _Bytes;
949                 ++_Mid2;
950                 _Ans = ok;
951             }
952         return (_Ans);
953         }
954
955     virtual result __CLR_OR_THIS_CALL do_out(_Statype& _State,
956         const _Elem *_First1, const _Elem *_Last1, const _Elem *& _Mid1,
957             _Byte *_First2, _Byte *_Last2, _Byte *& _Mid2) const
958         {    // convert [_First1, _Last1) to bytes [_First2, _Last)
959         _DEBUG_RANGE(_First1, _Last1);
960         _DEBUG_RANGE(_First2, _Last2);
961         _Mid1 = _First1, _Mid2 = _First2;
962         result _Ans = _Mid1 == _Last1 ? ok : partial;
963         int _Bytes;
964
965         while (_Mid1 != _Last1 && _Mid2 != _Last2)
966             if ((int)MB_CUR_MAX <= _Last2 - _Mid2)
967                 if ((_Bytes = _Wcrtomb(_Mid2, *_Mid1,
968                     &_State, &_Cvt)) < 0)
969                     return (error);    // locale-specific wcrtomb failed
970                 else
971                     ++_Mid1, _Mid2 += _Bytes, _Ans = ok;
972             else
973                 {    // destination possibly too small, convert into buffer
974                 _Byte _Buf[MB_LEN_MAX];
975                 _Statype _Stsave = _State;
976
977                 if ((_Bytes = _Wcrtomb(_Buf, *_Mid1,
978                     &_State, &_Cvt)) < 0)
979                     return (error);    // locale-specific wcrtomb failed
980                 else if (_Last2 - _Mid2 < _Bytes)
981                     {    // converted too many, roll back and return previous
982                     _State = _Stsave;
983                     return (_Ans);
984                     }
985                 else
986                     {    // copy converted bytes from buffer
987                     _CRT_SECURE_MEMCPY(_Mid2, _Last2 - _Mid2, _Buf, _Bytes);
988                     ++_Mid1, _Mid2 += _Bytes, _Ans = ok;
989                     }
990                 }
991         return (_Ans);
992         }
993
994     virtual result __CLR_OR_THIS_CALL do_unshift(_Statype& _State,
995         _Byte *_First2, _Byte *_Last2, _Byte *& _Mid2) const
996         {    // generate bytes to return to default shift state
997         _DEBUG_RANGE(_First2, _Last2);
998         _Mid2 = _First2;
999         result _Ans = ok;
1000         int _Bytes;
1001         _Byte _Buf[MB_LEN_MAX];
1002         _Statype _Stsave = _State;
1003
1004         if ((_Bytes = _Wcrtomb(_Buf, L'\0', &_State, &_Cvt)) <= 0)
1005             _Ans = error;    // locale-specific wcrtomb failed
1006         else if (_Last2 - _Mid2 < --_Bytes)
1007             {    // converted too many, roll back and return
1008             _State = _Stsave;
1009             _Ans = partial;
1010             }
1011         else if (0 < _Bytes)
1012             {    // copy converted bytes from buffer
1013             _CRT_SECURE_MEMCPY(_Mid2, _Last2 - _Mid2, _Buf, _Bytes);
1014             _Mid2 += _Bytes;
1015             }
1016         return (_Ans);
1017         }
1018
1019     virtual int __CLR_OR_THIS_CALL do_length(const _Statype& _State, const _Byte *_First1,
1020         const _Byte *_Last1, size_t _Count) const
1021         {    // return min(_Count, converted length of bytes [_First1, _Last1))
1022
1023  #if _HAS_STRICT_CONFORMANCE
1024         return ((int)(_Count < (size_t)(_Last1 - _First1)
1025             ? _Count : _Last1 - _First1));    // assume 1-to-1 conversion
1026
1027  #else /* _HAS_STRICT_CONFORMANCE */
1028         _DEBUG_RANGE(_First1, _Last1);
1029         int _Wchars;
1030         const _Byte *_Mid1;
1031         _Statype _Mystate = _State;
1032
1033         for (_Wchars = 0, _Mid1 = _First1;
1034             (size_t)_Wchars < _Count && _Mid1 != _Last1; )
1035             {    // convert another wchar_t
1036             int _Bytes;
1037             _Elem _Ch;
1038
1039             switch (_Bytes = _Mbrtowc(&_Ch, _Mid1, _Last1 - _Mid1,
1040                 &_Mystate, &_Cvt))
1041                 {    // test result of locale-specific mbrtowc call
1042             case -2:    // partial conversion
1043                 return (_Wchars);
1044
1045             case -1:    // failed conversion
1046                 return (_Wchars);
1047
1048             case 0:    // may have converted null character
1049                 if (_Ch == (_Elem)0)
1050                     _Bytes = (int)::strlen(_Mid1) + 1;
1051                 // fall through
1052
1053             default:    // converted _Bytes bytes to a wchar_t
1054                 if (_Bytes == -3)
1055                     _Bytes = 0;    // wchar_t generated from state info
1056                 _Mid1 += _Bytes;
1057                 ++_Wchars;
1058                 }
1059             }
1060         return (_Wchars);
1061  #endif /* _HAS_STRICT_CONFORMANCE */
1062         }
1063
1064     virtual bool __CLR_OR_THIS_CALL do_always_noconv() const _THROW0()
1065         {    // return true if conversions never change input
1066         return (false);
1067         }
1068
1069     virtual int __CLR_OR_THIS_CALL do_max_length() const _THROW0()
1070         {    // return maximum length required for a conversion (from codecvt)
1071         return (MB_LEN_MAX);
1072         }
1073
1074 private:
1075     _Locinfo::_Cvtvec _Cvt;    // locale info passed to _Mbrtowc, _Wcrtomb
1076     };
1077
1078 #ifdef _NATIVE_WCHAR_T_DEFINED
1079         // CLASS codecvt<unsigned short, char, _Mbstatet>
1080 template<> class _CRTIMP2_PURE codecvt<unsigned short, char, _Mbstatet>
1081     : public codecvt_base
1082     {    // facet for converting between unsigned short and char sequences
1083 public:
1084     typedef unsigned short _Elem;
1085     typedef char _Byte;
1086     typedef _Mbstatet _Statype;
1087     typedef _Elem intern_type;
1088     typedef _Byte extern_type;
1089     typedef _Statype state_type;
1090
1091     result __CLR_OR_THIS_CALL in(_Statype& _State,
1092         const _Byte *_First1, const _Byte *_Last1, const _Byte *& _Mid1,
1093         _Elem *_First2, _Elem *_Last2, _Elem *& _Mid2) const
1094         {    // convert bytes [_First1, _Last1) to [_First2, _Last)
1095         return (do_in(_State,
1096             _First1, _Last1, _Mid1, _First2, _Last2, _Mid2));
1097         }
1098
1099     result __CLR_OR_THIS_CALL out(_Statype& _State,
1100         const _Elem *_First1, const _Elem *_Last1, const _Elem *& _Mid1,
1101         _Byte *_First2, _Byte *_Last2, _Byte *& _Mid2) const
1102         {    // convert [_First1, _Last1) to bytes [_First2, _Last)
1103         return (do_out(_State,
1104             _First1, _Last1, _Mid1, _First2, _Last2, _Mid2));
1105         }
1106
1107     result __CLR_OR_THIS_CALL unshift(_Statype& _State,
1108         _Byte *_First2, _Byte *_Last2, _Byte *& _Mid2) const
1109         {    // generate bytes to return to default shift state
1110         return (do_unshift(_State,
1111             _First2, _Last2, _Mid2));
1112         }
1113
1114     int __CLR_OR_THIS_CALL length(const _Statype& _State, const _Byte *_First1,
1115         const _Byte *_Last1, size_t _Count) const
1116         {    // return min(_Count, converted length of bytes [_First1, _Last1))
1117         return (do_length(_State, _First1, _Last1, _Count));
1118         }
1119
1120     static _MRTIMP2_NPURE locale::id& __cdecl _Id_func();
1121 #ifdef _M_CEE_PURE
1122     static locale::id& id;    // unique facet id
1123 #else
1124     __PURE_APPDOMAIN_GLOBAL static locale::id id;    // unique facet id
1125 #endif
1126
1127     explicit __CLR_OR_THIS_CALL codecvt(size_t _Refs = 0)
1128         : codecvt_base(_Refs)
1129         {    // construct from current locale
1130         _BEGIN_LOCINFO(_Lobj)
1131             _Init(_Lobj);
1132         _END_LOCINFO()
1133         }
1134
1135     __CLR_OR_THIS_CALL codecvt(const _Locinfo& _Lobj, size_t _Refs = 0)
1136         : codecvt_base(_Refs)
1137         {    // construct from specified locale
1138         _Init(_Lobj);
1139         }
1140
1141     static size_t __CLRCALL_OR_CDECL _Getcat(const locale::facet **_Ppf = 0,
1142         const locale *_Ploc = 0)
1143         {    // return locale category mask and construct standard facet
1144         if (_Ppf != 0 && *_Ppf == 0)
1145             *_Ppf = _NEW_CRT codecvt<_Elem, _Byte, _Statype>(
1146                 _Locinfo(_Ploc->name()));
1147         return (_X_CTYPE);
1148         }
1149
1150 _PROTECTED:
1151     virtual __CLR_OR_THIS_CALL ~codecvt()
1152         {    // destroy the object
1153         }
1154
1155 protected:
1156     __CLR_OR_THIS_CALL codecvt(const char *_Locname, size_t _Refs = 0)
1157         : codecvt_base(_Refs)
1158         {    // construct from specified locale
1159         _BEGIN_LOCINFO(_Lobj(_Locname))
1160             _Init(_Lobj);
1161         _END_LOCINFO()
1162         }
1163
1164     void __CLR_OR_THIS_CALL _Init(const _Locinfo& _Lobj)
1165         {    // initialize from _Lobj
1166         _Cvt = _Lobj._Getcvt();
1167         }
1168
1169     virtual result __CLR_OR_THIS_CALL do_in(_Statype& _State,
1170         const _Byte *_First1, const _Byte *_Last1, const _Byte *& _Mid1,
1171             _Elem *_First2, _Elem *_Last2, _Elem *& _Mid2) const
Lines 1172 ... 1710 are skipped.
1711         return (do_toupper(_First, _Last));
1712         }
1713
1714     _Elem __CLR_OR_THIS_CALL widen(char _Byte) const
1715         {    // widen char
1716         return (do_widen(_Byte));
1717         }
1718
1719     _SCL_INSECURE_DEPRECATE
1720     const _Elem *__CLR_OR_THIS_CALL widen(const char *_First, const char *_Last,
1721         _Elem *_Dest) const
1722         {    // widen chars in [_First, _Last)
1723         // assume there is enough space in _Dest
1724 #pragma warning(push)
1725 #pragma warning(disable:4996)
1726         return (do_widen(_First, _Last, _Dest));
1727 #pragma warning(pop)
1728         }
1729
1730     const _Elem *__CLR_OR_THIS_CALL _Widen_s(const char *_First, const char *_Last,
1731         _Elem *_Dest, size_t _Dest_size) const
1732         {    // widen chars in [_First, _Last)
1733         return (_Do_widen_s(_First, _Last, _Dest, _Dest_size));
1734         }
1735
1736     _Elem __CLR_OR_THIS_CALL narrow(_Elem _Ch, char _Dflt = '\0') const
1737         {    // narrow element to char
1738         return (do_narrow(_Ch, _Dflt));
1739         }
1740
1741     _SCL_INSECURE_DEPRECATE
1742     const _Elem *__CLR_OR_THIS_CALL narrow(const _Elem *_First, const _Elem *_Last,
1743         char _Dflt, _Out_cap_x_(_Last-_First) char *_Dest) const
1744         {    // narrow elements in [_First, _Last) to chars
1745         // assume there is enough space in _Dest
1746 #pragma warning(push)
1747 #pragma warning(disable:4996)
1748         return (do_narrow(_First, _Last, _Dflt, _Dest));
1749 #pragma warning(pop)
1750         }
1751
1752     const _Elem *__CLR_OR_THIS_CALL _Narrow_s(const _Elem *_First, const _Elem *_Last,
1753         char _Dflt, _Out_cap_(_Dest_size) _Post_count_x_( _Last-_First) char *_Dest, 
1754         size_t _Dest_size) const
1755         {    // narrow elements in [_First, _Last) to chars
1756         return (_Do_narrow_s(_First, _Last, _Dflt, _Dest, _Dest_size));
1757         }
1758
1759     static _MRTIMP2_NPURE locale::id& __cdecl _Id_func();
1760 #ifdef _M_CEE_PURE
1761     static locale::id& id;    // unique facet id
1762 #else
1763     __PURE_APPDOMAIN_GLOBAL static locale::id id;    // unique facet id
1764 #endif
1765
1766     explicit __CLR_OR_THIS_CALL ctype(const mask *_Table = 0,
1767         bool _Deletetable = false,
1768         size_t _Refs = 0)
1769         : ctype_base(_Refs)
1770         {    // construct with specified table and delete flag for table
1771         _BEGIN_LOCINFO(_Lobj)
1772             _Init(_Lobj);
1773         _END_LOCINFO()
1774         if (_Table != 0)
1775             {    // replace existing char to mask table
1776             _Tidy();
1777             _Ctype._Table = _Table;
1778             _Ctype._Delfl = _Deletetable ? -1 : 0;
1779             }
1780         }
1781
1782     __CLR_OR_THIS_CALL ctype(const _Locinfo& _Lobj, size_t _Refs = 0)
1783         : ctype_base(_Refs)
1784         {    // construct from current locale
1785         _Init(_Lobj);
1786         }
1787
1788     static size_t __CLRCALL_OR_CDECL _Getcat(const locale::facet **_Ppf = 0,
1789         const locale *_Ploc = 0)
1790         {    // return locale category mask and construct standard facet
1791         if (_Ppf != 0 && *_Ppf == 0)
1792             *_Ppf = _NEW_CRT ctype<_Elem>(
1793                 _Locinfo(_Ploc->name()));
1794         return (_X_CTYPE);
1795         }
1796
1797     _PGLOBAL static const size_t table_size = 1 << 8/*CHAR_BIT*/;    // size of _Ctype._Table (char to mask)
1798
1799 _PROTECTED:
1800     virtual __CLR_OR_THIS_CALL ~ctype()
1801         {    // destroy the object
1802         _Tidy();
1803         }
1804
1805 protected:
1806     void __CLR_OR_THIS_CALL _Init(const _Locinfo& _Lobj)
1807         {    // initialize from _Lobj
1808         _Ctype = _Lobj._Getctype();
1809         }
1810
1811     void __CLR_OR_THIS_CALL _Tidy()
1812         {    // free any allocated storage
1813         if (0 < _Ctype._Delfl)
1814             free((void *)_Ctype._Table);
1815         else if (_Ctype._Delfl < 0)
1816             delete[] (void *)_Ctype._Table;
1817         }
1818
1819     virtual _Elem __CLR_OR_THIS_CALL do_tolower(_Elem _Ch) const
1820         {    // convert element to lower case
1821         return ((_Elem)_Tolower((unsigned char)_Ch, &_Ctype));
1822         }
1823
1824     virtual const _Elem *__CLR_OR_THIS_CALL do_tolower(_Elem *_First,
1825         const _Elem *_Last) const
1826         {    // convert [_First, _Last) in place to lower case
1827         _DEBUG_RANGE((const _Elem *)_First, _Last);
1828         for (; _First != _Last; ++_First)
1829             *_First = (_Elem)_Tolower((unsigned char)*_First, &_Ctype);
1830         return ((const _Elem *)_First);
1831         }
1832
1833     virtual _Elem __CLR_OR_THIS_CALL do_toupper(_Elem _Ch) const
1834         {    // convert element to upper case
1835         return ((_Elem)_Toupper((unsigned char)_Ch, &_Ctype));
1836         }
1837
1838     virtual const _Elem *__CLR_OR_THIS_CALL do_toupper(_Elem *_First,
1839         const _Elem *_Last) const
1840         {    // convert [_First, _Last) in place to upper case
1841         _DEBUG_RANGE((const _Elem *)_First, _Last);
1842         for (; _First != _Last; ++_First)
1843             *_First = (_Elem)_Toupper((unsigned char)*_First, &_Ctype);
1844         return ((const _Elem *)_First);
1845         }
1846
1847     virtual _Elem __CLR_OR_THIS_CALL do_widen(char _Byte) const
1848         {    // widen char
1849         return (_Byte);
1850         }
1851
1852     _SCL_INSECURE_DEPRECATE
1853     virtual const _Elem *__CLR_OR_THIS_CALL do_widen(const char *_First,
1854         const char *_Last, _Elem *_Dest) const
1855         {    // widen chars in [_First, _Last)
1856         // assume there is enough space in _Dest
1857         return _Do_widen_s(_First, _Last, _Dest, _Last - _First);
1858         }
1859
1860     virtual const _Elem *__CLR_OR_THIS_CALL _Do_widen_s(const char *_First,
1861         const char *_Last, _Elem *_Dest, size_t _Dest_size) const
1862         {    // widen chars in [_First, _Last)
1863         _DEBUG_RANGE(_First, _Last);
1864         _DEBUG_POINTER(_Dest);
1865         _SCL_SECURE_ALWAYS_VALIDATE_RANGE(_Dest_size >= (size_t)(_Last - _First));
1866         _CRT_SECURE_MEMCPY(_Dest, _Dest_size, _First, _Last - _First);
1867         return (_Last);
1868         }
1869
1870     virtual _Elem __CLR_OR_THIS_CALL do_narrow(_Elem _Ch, char) const
1871         {    // narrow char
1872         return (_Ch);
1873         }
1874
1875     _SCL_INSECURE_DEPRECATE
1876     virtual const _Elem *__CLR_OR_THIS_CALL do_narrow(const _Elem *_First,
1877         const _Elem *_Last, char _Dflt, 
1878         _Out_cap_x_(_Last-_First) char *_Dest) const
1879         {    // narrow elements in [_First, _Last) to chars
1880         // assume there is enough space in _Dest
1881         return _Do_narrow_s(_First, _Last, _Dflt, _Dest, _Last - _First);
1882         }
1883
1884     virtual const _Elem *__CLR_OR_THIS_CALL _Do_narrow_s(const _Elem *_First,
1885         const _Elem *_Last, char, _Out_cap_(_Dest_size) _Post_count_x_( _Last-_First) char *_Dest, 
1886         size_t _Dest_size) const
1887         {    // narrow elements in [_First, _Last) to chars
1888         _DEBUG_RANGE(_First, _Last);
1889         _DEBUG_POINTER(_Dest);
1890         _SCL_SECURE_ALWAYS_VALIDATE_RANGE(_Dest_size >= (size_t)(_Last - _First));
1891         _CRT_SECURE_MEMCPY(_Dest, _Dest_size, _First, _Last - _First);
1892         return (_Last);
1893         }
1894
1895     const mask *__CLR_OR_THIS_CALL table() const _THROW0()
1896         {    // return address of char to mask table
1897         return (_Ctype._Table);
1898         }
1899
1900     static const mask *__CLRCALL_OR_CDECL classic_table() _THROW0()
1901         {    // return address of char to mask table for "C" locale
1902         const _Myt& _Ctype_fac = _USE(locale::classic(), _Myt);
1903         return (_Ctype_fac.table());
1904         }
1905
1906 private:
1907     _Locinfo::_Ctypevec _Ctype;    // information
1908     };
1909
1910         // CLASS ctype<wchar_t>
1911 template<> class _CRTIMP2_PURE ctype<wchar_t>
1912     : public ctype_base
1913     {    // facet for classifying wchar_t elements, converting cases
1914     typedef ctype<wchar_t> _Myt;
1915
1916 public:
1917     typedef wchar_t _Elem;
1918     typedef _Elem char_type;
1919
1920     bool __CLR_OR_THIS_CALL is(mask _Maskval, _Elem _Ch) const
1921         {    // test if element fits any mask classifications
1922         return (do_is(_Maskval, _Ch));
1923         }
1924
1925     const _Elem *__CLR_OR_THIS_CALL is(const _Elem *_First, const _Elem *_Last,
1926         mask *_Dest) const
1927         {    // get mask sequence for elements in [_First, _Last)
1928         return (do_is(_First, _Last, _Dest));
1929         }
1930
1931     const _Elem *__CLR_OR_THIS_CALL scan_is(mask _Maskval, const _Elem *_First,
1932         const _Elem *_Last) const
1933         {    // find first in [_First, _Last) that fits mask classification
1934         return (do_scan_is(_Maskval, _First, _Last));
1935         }
1936
1937     const _Elem *__CLR_OR_THIS_CALL scan_not(mask _Maskval, const _Elem *_First,
1938         const _Elem *_Last) const
1939         {    // find first in [_First, _Last) not fitting mask classification
1940         return (do_scan_not(_Maskval, _First, _Last));
1941         }
1942
1943     _Elem __CLR_OR_THIS_CALL tolower(_Elem _Ch) const
1944         {    // convert element to lower case
1945         return (do_tolower(_Ch));
1946         }
1947
1948     const _Elem *__CLR_OR_THIS_CALL tolower(_Elem *_First, const _Elem *_Last) const
1949         {    // convert [_First, _Last) in place to lower case
1950         return (do_tolower(_First, _Last));
1951         }
1952
1953     _Elem __CLR_OR_THIS_CALL toupper(_Elem _Ch) const
1954         {    // convert element to upper case
1955         return (do_toupper(_Ch));
1956         }
1957
1958     const _Elem *__CLR_OR_THIS_CALL toupper(_Elem *_First, const _Elem *_Last) const
1959         {    // convert [_First, _Last) in place to upper case
1960         return (do_toupper(_First, _Last));
1961         }
1962
1963     _Elem __CLR_OR_THIS_CALL widen(char _Byte) const
1964         {    // widen char
1965         return (do_widen(_Byte));
1966         }
1967
1968     _SCL_INSECURE_DEPRECATE
1969     const char *__CLR_OR_THIS_CALL widen(const char *_First, const char *_Last,
1970         _Elem *_Dest) const
1971         {    // widen chars in [_First, _Last)
1972         // assume there is enough space in _Dest
1973 #pragma warning(push)
1974 #pragma warning(disable:4996)
1975         return (do_widen(_First, _Last, _Dest));
1976 #pragma warning(pop)
1977         }
1978
1979     const char *__CLR_OR_THIS_CALL _Widen_s(const char *_First, const char *_Last,
1980         _Elem *_Dest, size_t _Dest_size) const
1981         {    // widen chars in [_First, _Last)
1982         return (_Do_widen_s(_First, _Last, _Dest, _Dest_size));
1983         }
1984
1985     char __CLR_OR_THIS_CALL narrow(_Elem _Ch, char _Dflt = '\0') const
1986         {    // narrow element to char
1987         return (do_narrow(_Ch, _Dflt));
1988         }
1989
1990     _SCL_INSECURE_DEPRECATE
1991     const _Elem *__CLR_OR_THIS_CALL narrow(const _Elem *_First, const _Elem *_Last,
1992         char _Dflt, _Out_cap_x_(_Last-_First) char *_Dest) const
1993         {    // narrow elements in [_First, _Last) to chars
1994         // assume there is enough space in _Dest
1995 #pragma warning(push)
1996 #pragma warning(disable:4996)
1997         return (do_narrow(_First, _Last, _Dflt, _Dest));
1998 #pragma warning(pop)
1999         }
2000
2001     const _Elem *__CLR_OR_THIS_CALL _Narrow_s(const _Elem *_First, const _Elem *_Last,
2002         char _Dflt, _Out_cap_(_Dest_size) _Post_count_x_( _Last-_First) char *_Dest, 
2003         size_t _Dest_size) const
2004         {    // narrow elements in [_First, _Last) to chars
2005         return (_Do_narrow_s(_First, _Last, _Dflt, _Dest, _Dest_size));
2006         }
2007
2008     static _MRTIMP2_NPURE locale::id& __cdecl _Id_func();
2009 #ifdef _M_CEE_PURE
2010     static locale::id& id;    // unique facet id
2011 #else
2012     __PURE_APPDOMAIN_GLOBAL static locale::id id;    // unique facet id
2013 #endif
2014
2015     explicit __CLR_OR_THIS_CALL ctype(size_t _Refs = 0)
2016         : ctype_base(_Refs)
2017         {    // construct from current locale
2018         _BEGIN_LOCINFO(_Lobj)
2019             _Init(_Lobj);
2020         _END_LOCINFO()
2021         }
2022
2023     __CLR_OR_THIS_CALL ctype(const _Locinfo& _Lobj, size_t _Refs = 0)
2024         : ctype_base(_Refs)
2025         {    // construct from specified locale
2026         _Init(_Lobj);
2027         }
2028
2029     static size_t __CLRCALL_OR_CDECL _Getcat(const locale::facet **_Ppf = 0,
2030         const locale *_Ploc = 0)
2031         {    // return locale category mask and construct standard facet
2032         if (_Ppf != 0 && *_Ppf == 0)
2033             *_Ppf = _NEW_CRT ctype<_Elem>(
2034                 _Locinfo(_Ploc->name()));
2035         return (_X_CTYPE);
2036         }
2037
2038 _PROTECTED:
2039     virtual __CLR_OR_THIS_CALL ~ctype()
2040         {    // destroy the object
2041         if (_Ctype._Delfl)
2042             free((void *)_Ctype._Table);
2043         }
2044
2045 protected:
2046     void __CLR_OR_THIS_CALL _Init(const _Locinfo& _Lobj)
2047         {    // initialize from _Lobj
2048         _Ctype = _Lobj._Getctype();
2049         _Cvt = _Lobj._Getcvt();
2050         }
2051
2052     virtual bool __CLR_OR_THIS_CALL do_is(mask _Maskval, _Elem _Ch) const
2053         {    // test if element fits any mask classifications
2054         return ((::_Getwctype(_Ch, &_Ctype) & _Maskval) != 0);
2055         }
2056
2057     virtual const wchar_t *__CLR_OR_THIS_CALL do_is(const _Elem *_First,
2058         const _Elem *_Last, mask *_Dest) const
2059         {    // get mask sequence for elements in [_First, _Last)
2060         _DEBUG_RANGE(_First, _Last);
2061         _DEBUG_POINTER(_Dest);
2062         return (::_Getwctypes(_First, _Last, _Dest, &_Ctype));
2063         }
2064
2065     virtual const _Elem *__CLR_OR_THIS_CALL do_scan_is(mask _Maskval,
2066         const _Elem *_First, const _Elem *_Last) const
2067         {    // find first in [_First, _Last) that fits mask classification
2068         _DEBUG_RANGE(_First, _Last);
2069         for (; _First != _Last && !is(_Maskval, *_First); ++_First)
2070             ;
2071         return (_First);
2072         }
2073
2074     virtual const _Elem *__CLR_OR_THIS_CALL do_scan_not(mask _Maskval,
2075         const _Elem *_First, const _Elem *_Last) const
2076         {    // find first in [_First, _Last) not fitting mask classification
2077         _DEBUG_RANGE(_First, _Last);
2078         for (; _First != _Last && is(_Maskval, *_First); ++_First)
2079             ;
2080         return (_First);
2081         }
2082
2083     virtual _Elem __CLR_OR_THIS_CALL do_tolower(_Elem _Ch) const
2084         {    // convert element to lower case
2085         return (_Towlower(_Ch, &_Ctype));
2086         }
2087
2088     virtual const _Elem *__CLR_OR_THIS_CALL do_tolower(_Elem *_First,
2089         const _Elem *_Last) const
2090         {    // convert [_First, _Last) in place to lower case
2091         _DEBUG_RANGE((const _Elem *)_First, _Last);
2092         for (; _First != _Last; ++_First)
2093             *_First = _Towlower(*_First, &_Ctype);
2094         return ((const _Elem *)_First);
2095         }
2096
2097     virtual _Elem __CLR_OR_THIS_CALL do_toupper(_Elem _Ch) const
2098         {    // convert element to upper case
2099         return (_Towupper(_Ch, &_Ctype));
2100         }
2101
2102     virtual const _Elem *__CLR_OR_THIS_CALL do_toupper(_Elem *_First,
2103         const _Elem *_Last) const
2104         {    // convert [_First, _Last) in place to upper case
2105         _DEBUG_RANGE((const _Elem *)_First, _Last);
2106         for (; _First != _Last; ++_First)
2107             *_First = _Towupper(*_First, &_Ctype);
2108         return ((const _Elem *)_First);
2109         }
2110
2111     _Elem __CLR_OR_THIS_CALL _Dowiden(char _Byte) const
2112         {    // widen char
2113         _Mbstinit(_Mbst);
2114         wchar_t _Wc;
2115         return (_Mbrtowc(&_Wc, &_Byte, 1, &_Mbst, &_Cvt) < 0
2116             ? (wchar_t)WEOF : _Wc);
2117         }
2118
2119     virtual _Elem __CLR_OR_THIS_CALL do_widen(char _Byte) const
2120         {    // widen char
2121         return (_Dowiden(_Byte));
2122         }
2123
2124     _SCL_INSECURE_DEPRECATE
2125     virtual const char *__CLR_OR_THIS_CALL do_widen(const char *_First,
2126         const char *_Last, _Elem *_Dest) const
2127         {    // widen chars in [_First, _Last)
2128         // assume there is enough space in _Dest
2129         return _Do_widen_s(_First, _Last, _Dest, _Last - _First);
2130         }
2131
2132     virtual const char *__CLR_OR_THIS_CALL _Do_widen_s(const char *_First,
2133         const char *_Last, _Elem *_Dest, size_t _Dest_size) const
2134         {    // widen chars in [_First, _Last)
2135         _DEBUG_RANGE(_First, _Last);
2136         _DEBUG_POINTER(_Dest);
2137         _SCL_SECURE_ALWAYS_VALIDATE_RANGE(_Dest_size >= (size_t)(_Last - _First));
2138         for (; _First != _Last; ++_First, ++_Dest)
2139             *_Dest = _Dowiden(*_First);
2140         return (_First);
2141         }
2142
2143     char __CLR_OR_THIS_CALL _Donarrow(_Elem _Ch, char _Dflt) const
2144         {    // narrow element to char
2145         char _Buf[MB_LEN_MAX];
2146         _Mbstinit(_Mbst);
2147         return (_Wcrtomb(_Buf, _Ch, &_Mbst, &_Cvt) != 1
2148             ? _Dflt : _Buf[0]);
2149         }
2150
2151     virtual char __CLR_OR_THIS_CALL do_narrow(_Elem _Ch, char _Dflt) const
2152         {    // narrow element to char
2153         return (_Donarrow(_Ch, _Dflt));
2154         }
2155
2156     _SCL_INSECURE_DEPRECATE
2157     virtual const _Elem *__CLR_OR_THIS_CALL do_narrow(const _Elem *_First,
2158         const _Elem *_Last, char _Dflt,  
2159         _Out_cap_x_(_Last-_First) char *_Dest) const
2160         {    // narrow elements in [_First, _Last) to chars
2161         // assume there is enough space in _Dest
2162         return _Do_narrow_s(_First, _Last, _Dflt, _Dest, _Last - _First);
2163         }
2164
2165     virtual const _Elem *__CLR_OR_THIS_CALL _Do_narrow_s(const _Elem *_First,
2166         const _Elem *_Last, char _Dflt, 
2167         _Out_cap_(_Dest_size) _Post_count_x_( _Last-_First) char *_Dest, 
2168         size_t _Dest_size) const
2169         {    // narrow elements in [_First, _Last) to chars
2170         _DEBUG_RANGE(_First, _Last);
2171         _DEBUG_POINTER(_Dest);
2172         _SCL_SECURE_ALWAYS_VALIDATE_RANGE(_Dest_size >= (size_t)(_Last - _First));
2173         for (; _First != _Last; ++_First, ++_Dest)
2174             *_Dest = _Donarrow(*_First, _Dflt);
2175         return (_First);
2176         }
2177
2178 private:
2179     _Locinfo::_Ctypevec _Ctype;    // locale info passed to _Tolower, etc.
2180     _Locinfo::_Cvtvec _Cvt;        // conversion information
2181     };
2182
2183 #ifdef _NATIVE_WCHAR_T_DEFINED
2184         // CLASS ctype<unsigned short>
2185 template<> class _CRTIMP2_PURE ctype<unsigned short>
2186     : public ctype_base
2187     {    // facet for classifying unsigned short elements, converting cases
2188     typedef ctype<unsigned short> _Myt;
2189
2190 public:
2191     typedef unsigned short _Elem;
2192     typedef _Elem char_type;
2193
2194     bool __CLR_OR_THIS_CALL is(mask _Maskval, _Elem _Ch) const
2195         {    // test if element fits any mask classifications
2196         return (do_is(_Maskval, _Ch));
2197         }
2198
2199     const _Elem *__CLR_OR_THIS_CALL is(const _Elem *_First, const _Elem *_Last,
2200         mask *_Dest) const
2201         {    // get mask sequence for elements in [_First, _Last)
2202         return (do_is(_First, _Last, _Dest));
2203         }
2204
2205     const _Elem *__CLR_OR_THIS_CALL scan_is(mask _Maskval, const _Elem *_First,
2206         const _Elem *_Last) const
2207         {    // find first in [_First, _Last) that fits mask classification
2208         return (do_scan_is(_Maskval, _First, _Last));
2209         }
2210
2211     const _Elem *__CLR_OR_THIS_CALL scan_not(mask _Maskval, const _Elem *_First,
2212         const _Elem *_Last) const
2213         {    // find first in [_First, _Last) not fitting mask classification
2214         return (do_scan_not(_Maskval, _First, _Last));
2215         }
2216
2217     _Elem __CLR_OR_THIS_CALL tolower(_Elem _Ch) const
2218         {    // convert element to lower case
2219         return (do_tolower(_Ch));
2220         }
2221
2222     const _Elem *__CLR_OR_THIS_CALL tolower(_Elem *_First, const _Elem *_Last) const
2223         {    // convert [_First, _Last) in place to lower case
2224         return (do_tolower(_First, _Last));
2225         }
2226
2227     _Elem __CLR_OR_THIS_CALL toupper(_Elem _Ch) const
2228         {    // convert element to upper case
2229         return (do_toupper(_Ch));
2230         }
2231
2232     const _Elem *__CLR_OR_THIS_CALL toupper(_Elem *_First, const _Elem *_Last) const
2233         {    // convert [_First, _Last) in place to upper case
2234         return (do_toupper(_First, _Last));
2235         }
2236
2237     _Elem __CLR_OR_THIS_CALL widen(char _Byte) const
2238         {    // widen char
2239         return (do_widen(_Byte));
2240         }
2241
2242     _SCL_INSECURE_DEPRECATE
2243     const char *__CLR_OR_THIS_CALL widen(const char *_First, const char *_Last,
2244         _Elem *_Dest) const
2245         {    // widen chars in [_First, _Last)
2246         // assume there is enough space in _Dest
2247 #pragma warning(push)
2248 #pragma warning(disable:4996)
2249         return (do_widen(_First, _Last, _Dest));
2250 #pragma warning(pop)
2251         }
2252
2253     const char *__CLR_OR_THIS_CALL _Widen_s(const char *_First, const char *_Last,
2254         _Elem *_Dest, size_t _Dest_size) const
2255         {    // widen chars in [_First, _Last)
2256         return (_Do_widen_s(_First, _Last, _Dest, _Dest_size));
2257         }
2258
2259     char __CLR_OR_THIS_CALL narrow(_Elem _Ch, char _Dflt = '\0') const
2260         {    // narrow element to char
2261         return (do_narrow(_Ch, _Dflt));
2262         }
2263
2264     _SCL_INSECURE_DEPRECATE
2265     const _Elem *__CLR_OR_THIS_CALL narrow(const _Elem *_First, const _Elem *_Last,
2266         char _Dflt, _Out_cap_x_(_Last-_First) char *_Dest) const
2267         {    // narrow elements in [_First, _Last) to chars
2268         // assume there is enough space in _Dest
2269 #pragma warning(push)
2270 #pragma warning(disable:4996)
2271         return (do_narrow(_First, _Last, _Dflt, _Dest));
2272 #pragma warning(pop)
2273         }
2274
2275     const _Elem *__CLR_OR_THIS_CALL _Narrow_s(const _Elem *_First, const _Elem *_Last,
2276         char _Dflt, _Out_cap_(_Dest_size) _Post_count_x_( _Last-_First) char *_Dest, 
2277         size_t _Dest_size) const
2278         {    // narrow elements in [_First, _Last) to chars
2279         return (_Do_narrow_s(_First, _Last, _Dflt, _Dest, _Dest_size));
2280         }
2281
2282     static _MRTIMP2_NPURE locale::id& __cdecl _Id_func();
2283 #ifdef _M_CEE_PURE
2284     static locale::id& id;    // unique facet id
2285 #else
2286     __PURE_APPDOMAIN_GLOBAL static locale::id id;    // unique facet id
2287 #endif
2288
2289     explicit __CLR_OR_THIS_CALL ctype(size_t _Refs = 0)
2290         : ctype_base(_Refs)
2291         {    // construct from current locale
2292         _BEGIN_LOCINFO(_Lobj)
2293             _Init(_Lobj);
2294         _END_LOCINFO()
2295         }
2296
2297     __CLR_OR_THIS_CALL ctype(const _Locinfo& _Lobj, size_t _Refs = 0)
2298         : ctype_base(_Refs)
2299         {    // construct from specified locale
2300         _Init(_Lobj);
2301         }
2302
2303     static size_t __CLRCALL_OR_CDECL _Getcat(const locale::facet **_Ppf = 0,
2304         const locale *_Ploc = 0)
2305         {    // return locale category mask and construct standard facet
2306         if (_Ppf != 0 && *_Ppf == 0)
2307             *_Ppf = _NEW_CRT ctype<_Elem>(
2308                 _Locinfo(_Ploc->name()));
2309         return (_X_CTYPE);
2310         }
2311
2312 _PROTECTED:
2313     virtual __CLR_OR_THIS_CALL ~ctype()
2314         {    // destroy the object
2315         if (_Ctype._Delfl)
2316             free((void *)_Ctype._Table);
2317         }
2318
2319 protected:
2320     __CLR_OR_THIS_CALL ctype(const char *_Locname, size_t _Refs = 0)
2321         : ctype_base(_Refs)
2322         {    // construct from specified locale
2323         _BEGIN_LOCINFO(_Lobj(_Locname))
2324             _Init(_Lobj);
2325         _END_LOCINFO()
2326         }
2327
2328     void __CLR_OR_THIS_CALL _Init(const _Locinfo& _Lobj)
2329         {    // initialize from _Lobj
2330         _Ctype = _Lobj._Getctype();
2331         _Cvt = _Lobj._Getcvt();
2332         }
2333
2334     virtual bool __CLR_OR_THIS_CALL do_is(mask _Maskval, _Elem _Ch) const
2335         {    // test if element fits any mask classifications
2336         return ((::_Getwctype(_Ch, &_Ctype) & _Maskval) != 0);
2337         }
2338
2339     virtual const _Elem *__CLR_OR_THIS_CALL do_is(const _Elem *_First,
2340         const _Elem *_Last, mask *_Dest) const
2341         {    // get mask sequence for elements in [_First, _Last)
2342         _DEBUG_RANGE(_First, _Last);
2343         _DEBUG_POINTER(_Dest);
2344         return ((const _Elem *)::_Getwctypes((const wchar_t *)_First,
2345             (const wchar_t *)_Last, _Dest, &_Ctype));
2346         }
2347
2348     virtual const _Elem *__CLR_OR_THIS_CALL do_scan_is(mask _Maskval,
2349         const _Elem *_First, const _Elem *_Last) const
2350         {    // find first in [_First, _Last) that fits mask classification
2351         _DEBUG_RANGE(_First, _Last);
2352         for (; _First != _Last && !is(_Maskval, *_First); ++_First)
2353             ;
2354         return (_First);
2355         }
2356
2357     virtual const _Elem *__CLR_OR_THIS_CALL do_scan_not(mask _Maskval,
2358         const _Elem *_First, const _Elem *_Last) const
2359         {    // find first in [_First, _Last) not fitting mask classification
2360         _DEBUG_RANGE(_First, _Last);
2361         for (; _First != _Last && is(_Maskval, *_First); ++_First)
2362             ;
2363         return (_First);
2364         }
2365
2366     virtual _Elem __CLR_OR_THIS_CALL do_tolower(_Elem _Ch) const
2367         {    // convert element to lower case
2368         return (_Towlower(_Ch, &_Ctype));
2369         }
2370
2371     virtual const _Elem *__CLR_OR_THIS_CALL do_tolower(_Elem *_First,
2372         const _Elem *_Last) const
2373         {    // convert [_First, _Last) in place to lower case
2374         _DEBUG_RANGE((const _Elem *)_First, _Last);
2375         for (; _First != _Last; ++_First)
2376             *_First = _Towlower(*_First, &_Ctype);
2377         return ((const _Elem *)_First);
2378         }
2379
2380     virtual _Elem __CLR_OR_THIS_CALL do_toupper(_Elem _Ch) const
2381         {    // convert element to upper case
2382         return (_Towupper(_Ch, &_Ctype));
2383         }
2384
2385     virtual const _Elem *__CLR_OR_THIS_CALL do_toupper(_Elem *_First,
2386         const _Elem *_Last) const
2387         {    // convert [_First, _Last) in place to upper case
2388         _DEBUG_RANGE((const _Elem *)_First, _Last);
2389         for (; _First != _Last; ++_First)
2390             *_First = _Towupper(*_First, &_Ctype);
2391         return ((const _Elem *)_First);
2392         }
2393
2394     _Elem __CLR_OR_THIS_CALL _Dowiden(char _Byte) const
2395         {    // widen char
2396         _Mbstinit(_Mbst);
2397         unsigned short _Wc;
2398         return (_Mbrtowc((wchar_t *)&_Wc, &_Byte, 1, &_Mbst, &_Cvt) < 0
2399             ? (unsigned short)WEOF : _Wc);
2400         }
2401
2402     virtual _Elem __CLR_OR_THIS_CALL do_widen(char _Byte) const
2403         {    // widen char
2404         return (_Dowiden(_Byte));
2405         }
2406
2407     _SCL_INSECURE_DEPRECATE
2408     virtual const char *__CLR_OR_THIS_CALL do_widen(const char *_First,
2409         const char *_Last, _Elem *_Dest) const
2410         {    // widen chars in [_First, _Last)
2411         // assume there is enough space in _Dest
2412         return _Do_widen_s(_First, _Last, _Dest, _Last - _First);
2413         }
2414
2415     virtual const char *__CLR_OR_THIS_CALL _Do_widen_s(const char *_First,
2416         const char *_Last, _Elem *_Dest, size_t _Dest_size) const
2417         {    // widen chars in [_First, _Last)
2418         _DEBUG_RANGE(_First, _Last);
2419         _DEBUG_POINTER(_Dest);
2420         _SCL_SECURE_ALWAYS_VALIDATE_RANGE(_Dest_size >= (size_t)(_Last - _First));
2421         for (; _First != _Last; ++_First, ++_Dest)
2422             *_Dest = _Dowiden(*_First);
2423         return (_First);
2424         }
2425
2426     char __CLR_OR_THIS_CALL _Donarrow(_Elem _Ch, char _Dflt) const
2427         {    // narrow element to char
2428         char _Buf[MB_LEN_MAX];
2429         _Mbstinit(_Mbst);
2430         return (_Wcrtomb(_Buf, _Ch, &_Mbst, &_Cvt) != 1
2431             ? _Dflt : _Buf[0]);
2432         }
2433
2434     virtual char __CLR_OR_THIS_CALL do_narrow(_Elem _Ch, char _Dflt) const
2435         {    // narrow element to char
2436         return (_Donarrow(_Ch, _Dflt));
2437         }
2438
2439     _SCL_INSECURE_DEPRECATE
2440     virtual const _Elem *__CLR_OR_THIS_CALL do_narrow(const _Elem *_First,
2441         const _Elem *_Last, char _Dflt, _Out_cap_x_(_Last-_First) char *_Dest) const
2442         {    // narrow elements in [_First, _Last) to chars
2443         // assume there is enough space in _Dest
2444         return _Do_narrow_s(_First, _Last, _Dflt, _Dest, _Last - _First);
2445         }
2446
2447     virtual const _Elem *__CLR_OR_THIS_CALL _Do_narrow_s(const _Elem *_First,
2448         const _Elem *_Last, char _Dflt, 
2449         _Out_cap_(_Dest_size) _Post_count_x_( _Last-_First) char *_Dest, 
2450         size_t _Dest_size) const
2451         {    // narrow elements in [_First, _Last) to chars
2452         _DEBUG_RANGE(_First, _Last);
2453         _DEBUG_POINTER(_Dest);
2454         _SCL_SECURE_ALWAYS_VALIDATE_RANGE(_Dest_size >= (size_t)(_Last - _First));
2455         for (; _First != _Last; ++_First, ++_Dest)
2456             *_Dest = _Donarrow(*_First, _Dflt);
2457         return (_First);
2458         }
2459
2460 private:
2461     _Locinfo::_Ctypevec _Ctype;    // locale info passed to _Tolower, etc.
2462     _Locinfo::_Cvtvec _Cvt;        // conversion information
2463     };
2464 #endif /* _NATIVE_WCHAR_T_DEFINED */
2465
2466         // TEMPLATE CLASS ctype_byname
2467 template<class _Elem>
2468     class ctype_byname
2469     : public ctype<_Elem>
2470     {    // ctype for named locale
2471 public:
2472     explicit __CLR_OR_THIS_CALL ctype_byname(const char *_Locname, size_t _Refs = 0)
2473         : ctype<_Elem>(_Locname, _Refs)
2474         {    // construct from named locale
2475         }
2476
2477 _PROTECTED:
2478     virtual __CLR_OR_THIS_CALL ~ctype_byname()
2479         {    // destroy the object
2480         }
2481     };
2482
2483         // TEMPLATE CLASS ctype_byname<char>
2484 template<> class ctype_byname<char>
2485     : public ctype<char>
2486     {    // ctype_byname<char> for named locale
2487 public:
2488     explicit __CLR_OR_THIS_CALL ctype_byname(const char *_Locname, size_t _Refs = 0)
2489         : ctype<char>(_Locname, _Refs)
2490         {    // construct from named locale
2491         }
2492
2493 _PROTECTED:
2494     virtual __CLR_OR_THIS_CALL ~ctype_byname()
2495         {    // destroy the object
2496         }
2497     };
2498
2499  #if defined(_DLL_CPPLIB) && !defined(_M_CEE_PURE)
2500
2501 template class _CRTIMP2_PURE codecvt<char, char, _Mbstatet>;
2502
2503  #endif /* _DLL_CPPLIB */
2504 _STD_END
2505
2506 #ifdef _MSC_VER
2507  #pragma warning(pop)
2508  #pragma pack(pop)
2509 #endif  /* _MSC_VER */
2510
2511 #endif /* RC_INVOKED */
2512 #endif /* _XLOCALE_ */
2513
2514 /*
2515  * Copyright (c) 1992-2007 by P.J. Plauger.  ALL RIGHTS RESERVED.
2516  * Consult your license regarding permissions and restrictions.
2517  V5.03:0009 */
2518