Merge remote-tracking branch 'joncham/sgen-msvc2'
[mono.git] / mcs / class / corlib / System.Text / Encoding.cs
1 /*
2          * Encoding.cs - Implementation of the "System.Text.Encoding" class.
3  *
4  * Copyright (c) 2001, 2002  Southern Storm Software, Pty Ltd
5  * Copyright (c) 2002, Ximian, Inc.
6  * Copyright (c) 2003, 2004 Novell, Inc.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining
9  * a copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included
16  * in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24  * OTHER DEALINGS IN THE SOFTWARE.
25  */
26
27 namespace System.Text
28 {
29
30 using System;
31 using System.Reflection;
32 using System.Globalization;
33 using System.Security;
34 using System.Runtime.CompilerServices;
35 using System.Runtime.InteropServices;
36
37 [Serializable]
38 [ComVisible (true)]
39 public abstract class Encoding : ICloneable
40 {
41         // Code page used by this encoding.
42         internal int codePage;
43         internal int windows_code_page;
44         bool is_readonly = true;
45
46         // Constructor.
47         protected Encoding ()
48         {
49         }
50
51 #if ECMA_COMPAT
52         protected internal
53 #else
54         protected
55 #endif
56         Encoding (int codePage)
57         {
58                 this.codePage = windows_code_page = codePage;
59
60                 switch (codePage) {
61                 default:
62                         // MS has "InternalBestFit{Decoder|Encoder}Fallback
63                         // here, but we dunno what they are for.
64                         decoder_fallback = DecoderFallback.ReplacementFallback;
65                         encoder_fallback = EncoderFallback.ReplacementFallback;
66                         break;
67                 case 20127: // ASCII
68                 case 54936: // GB18030
69                         decoder_fallback = DecoderFallback.ReplacementFallback;
70                         encoder_fallback = EncoderFallback.ReplacementFallback;
71                         break;
72                 case 1200: // UTF16
73                 case 1201: // UTF16
74                 case 12000: // UTF32
75                 case 12001: // UTF32
76                 case 65000: // UTF7
77                 case 65001: // UTF8
78                         decoder_fallback = DecoderFallback.StandardSafeFallback;
79                         encoder_fallback = EncoderFallback.StandardSafeFallback;
80                         break;
81                 }
82         }
83
84         // until we change the callers:
85         internal static string _ (string arg) {
86                 return arg;
87         }
88
89         DecoderFallback decoder_fallback;
90         EncoderFallback encoder_fallback;
91
92         [ComVisible (false)]
93         public bool IsReadOnly {
94                 get { return is_readonly; }
95         }
96
97         [ComVisible (false)]
98         public virtual bool IsSingleByte {
99                 get { return false; }
100         }
101
102         [ComVisible (false)]
103         public DecoderFallback DecoderFallback {
104                 get { return decoder_fallback; }
105                 set {
106                         if (IsReadOnly)
107                                 throw new InvalidOperationException ("This Encoding is readonly.");
108                         if (value == null)
109                                 throw new ArgumentNullException ();
110                         decoder_fallback = value;
111                 }
112         }
113
114         [ComVisible (false)]
115         public EncoderFallback EncoderFallback {
116                 get { return encoder_fallback; }
117                 set {
118                         if (IsReadOnly)
119                                 throw new InvalidOperationException ("This Encoding is readonly.");
120                         if (value == null)
121                                 throw new ArgumentNullException ();
122                         encoder_fallback = value;
123                 }
124         }
125
126         internal void SetFallbackInternal (EncoderFallback e, DecoderFallback d)
127         {
128                 if (e != null)
129                         encoder_fallback = e;
130                 if (d != null)
131                         decoder_fallback = d;
132         }
133
134         // Convert between two encodings.
135         public static byte[] Convert (Encoding srcEncoding, Encoding dstEncoding,
136                                                                  byte[] bytes)
137         {
138                 if (srcEncoding == null) {
139                         throw new ArgumentNullException ("srcEncoding");
140                 }
141                 if (dstEncoding == null) {
142                         throw new ArgumentNullException ("dstEncoding");
143                 }
144                 if (bytes == null) {
145                         throw new ArgumentNullException ("bytes");
146                 }
147                 return dstEncoding.GetBytes (srcEncoding.GetChars (bytes, 0, bytes.Length));
148         }
149         public static byte[] Convert (Encoding srcEncoding, Encoding dstEncoding,
150                                                                  byte[] bytes, int index, int count)
151         {
152                 if (srcEncoding == null) {
153                         throw new ArgumentNullException ("srcEncoding");
154                 }
155                 if (dstEncoding == null) {
156                         throw new ArgumentNullException ("dstEncoding");
157                 }
158                 if (bytes == null) {
159                         throw new ArgumentNullException ("bytes");
160                 }
161                 if (index < 0 || index > bytes.Length) {
162                         throw new ArgumentOutOfRangeException
163                                 ("index", _("ArgRange_Array"));
164                 }
165                 if (count < 0 || (bytes.Length - index) < count) {
166                         throw new ArgumentOutOfRangeException
167                                 ("count", _("ArgRange_Array"));
168                 }
169                 return dstEncoding.GetBytes (srcEncoding.GetChars (bytes, index, count));
170         }
171
172         // Determine if two Encoding objects are equal.
173         public override bool Equals (Object value)
174         {
175                 Encoding enc = (value as Encoding);
176                 if (enc != null) {
177                         return codePage == enc.codePage &&
178                                 DecoderFallback.Equals (enc.DecoderFallback) &&
179                                 EncoderFallback.Equals (enc.EncoderFallback);
180                 } else {
181                         return false;
182                 }
183         }
184
185         // Get the number of characters needed to encode a character buffer.
186         public abstract int GetByteCount (char[] chars, int index, int count);
187
188         // Convenience wrappers for "GetByteCount".
189         public virtual int GetByteCount (String s)
190         {
191                 if (s == null)
192                         throw new ArgumentNullException ("s");
193
194                 if (s.Length == 0)
195                         return 0;
196                 unsafe {
197                         fixed (char* cptr = s) {
198                                 return GetByteCount (cptr, s.Length);
199                         }
200                 }
201         }
202         public virtual int GetByteCount (char[] chars)
203         {
204                 if (chars != null) {
205                         return GetByteCount (chars, 0, chars.Length);
206                 } else {
207                         throw new ArgumentNullException ("chars");
208                 }
209         }
210
211         // Get the bytes that result from encoding a character buffer.
212         public abstract int GetBytes (char[] chars, int charIndex, int charCount,
213                                                                  byte[] bytes, int byteIndex);
214
215         // Convenience wrappers for "GetBytes".
216         public virtual int GetBytes (String s, int charIndex, int charCount,
217                                                                 byte[] bytes, int byteIndex)
218         {
219                 if (s == null)
220                         throw new ArgumentNullException ("s");
221                 if (charIndex < 0 || charIndex > s.Length)
222                         throw new ArgumentOutOfRangeException ("charIndex", _("ArgRange_Array"));
223                 if (charCount < 0 || charIndex > (s.Length - charCount))
224                         throw new ArgumentOutOfRangeException ("charCount", _("ArgRange_Array"));
225                 if (byteIndex < 0 || byteIndex > bytes.Length)
226                         throw new ArgumentOutOfRangeException ("byteIndex", _("ArgRange_Array"));
227
228                 if (charCount == 0 || bytes.Length == byteIndex)
229                         return 0;
230                 unsafe {
231                         fixed (char* cptr = s) {
232                                 fixed (byte* bptr = bytes) {
233                                         return GetBytes (cptr + charIndex,
234                                                 charCount,
235                                                 bptr + byteIndex,
236                                                 bytes.Length - byteIndex);
237                                 }
238                         }
239                 }
240         }
241         public virtual byte[] GetBytes (String s)
242         {
243                 if (s == null)
244                         throw new ArgumentNullException ("s");
245
246                 if (s.Length == 0)
247                         return EmptyArray<byte>.Value;
248                 int byteCount = GetByteCount (s);
249                 if (byteCount == 0)
250                         return EmptyArray<byte>.Value;
251                 unsafe {
252                         fixed (char* cptr = s) {
253                                 byte [] bytes = new byte [byteCount];
254                                 fixed (byte* bptr = bytes) {
255                                         GetBytes (cptr, s.Length,
256                                                 bptr, byteCount);
257                                         return bytes;
258                                 }
259                         }
260                 }
261         }
262
263         public virtual byte[] GetBytes (char[] chars, int index, int count)
264         {
265                 int numBytes = GetByteCount (chars, index, count);
266                 byte[] bytes = new byte [numBytes];
267                 GetBytes (chars, index, count, bytes, 0);
268                 return bytes;
269         }
270         public virtual byte[] GetBytes (char[] chars)
271         {
272                 int numBytes = GetByteCount (chars, 0, chars.Length);
273                 byte[] bytes = new byte [numBytes];
274                 GetBytes (chars, 0, chars.Length, bytes, 0);
275                 return bytes;
276         }
277
278         // Get the number of characters needed to decode a byte buffer.
279         public abstract int GetCharCount (byte[] bytes, int index, int count);
280
281         // Convenience wrappers for "GetCharCount".
282         public virtual int GetCharCount (byte[] bytes)
283         {
284                 if (bytes == null) {
285                         throw new ArgumentNullException ("bytes");
286                 }
287                 return GetCharCount (bytes, 0, bytes.Length);
288         }
289
290         // Get the characters that result from decoding a byte buffer.
291         public abstract int GetChars (byte[] bytes, int byteIndex, int byteCount,
292                                                                  char[] chars, int charIndex);
293
294         // Convenience wrappers for "GetChars".
295         public virtual char[] GetChars (byte[] bytes, int index, int count)
296         {
297                 int numChars = GetCharCount (bytes, index, count);
298                 char[] chars = new char [numChars];
299                 GetChars (bytes, index, count, chars, 0);
300                 return chars;
301         }
302         public virtual char[] GetChars (byte[] bytes)
303         {
304                 if (bytes == null) {
305                         throw new ArgumentNullException ("bytes");
306                 }
307                 int numChars = GetCharCount (bytes, 0, bytes.Length);
308                 char[] chars = new char [numChars];
309                 GetChars (bytes, 0, bytes.Length, chars, 0);
310                 return chars;
311         }
312
313         // Get a decoder that forwards requests to this object.
314         public virtual Decoder GetDecoder ()
315         {
316                 return new ForwardingDecoder (this);
317         }
318
319         // Get an encoder that forwards requests to this object.
320         public virtual Encoder GetEncoder ()
321         {
322                 return new ForwardingEncoder (this);
323         }
324
325         // Loaded copy of the "I18N" assembly.  We need to move
326         // this into a class in "System.Private" eventually.
327         private static Assembly i18nAssembly;
328         private static bool i18nDisabled;
329
330         // Invoke a specific method on the "I18N" manager object.
331         // Returns NULL if the method failed.
332         private static Object InvokeI18N (String name, params Object[] args)
333         {
334                 lock (lockobj) {
335                         // Bail out if we previously detected that there
336                         // is insufficent engine support for I18N handling.
337                         if (i18nDisabled) {
338                                 return null;
339                         }
340
341                         // Find or load the "I18N" assembly.
342                         if (i18nAssembly == null) {
343                                 try {
344                                         try {
345                                                 i18nAssembly = Assembly.Load (Consts.AssemblyI18N);
346                                         } catch (NotImplementedException) {
347                                                 // Assembly loading unsupported by the engine.
348                                                 i18nDisabled = true;
349                                                 return null;
350                                         }
351                                         if (i18nAssembly == null) {
352                                                 return null;
353                                         }
354                                 } catch (SystemException) {
355                                         return null;
356                                 }
357                         }
358
359                         // Find the "I18N.Common.Manager" class.
360                         Type managerClass;
361                         try {
362                                 managerClass = i18nAssembly.GetType ("I18N.Common.Manager");
363                         } catch (NotImplementedException) {
364                                 // "GetType" is not supported by the engine.
365                                 i18nDisabled = true;
366                                 return null;
367                         }
368                         if (managerClass == null) {
369                                 return null;
370                         }
371
372                         // Get the value of the "PrimaryManager" property.
373                         Object manager;
374                         try {
375                                 manager = managerClass.InvokeMember
376                                                 ("PrimaryManager",
377                                                  BindingFlags.GetProperty |
378                                                         BindingFlags.Static |
379                                                         BindingFlags.Public,
380                                                  null, null, null, null, null, null);
381                                 if (manager == null) {
382                                         return null;
383                                 }
384                         } catch (MissingMethodException) {
385                                 return null;
386                         } catch (SecurityException) {
387                                 return null;
388                         } catch (NotImplementedException) {
389                                 // "InvokeMember" is not supported by the engine.
390                                 i18nDisabled = true;
391                                 return null;
392                         }
393
394                         // Invoke the requested method on the manager.
395                         try {
396                                 return managerClass.InvokeMember
397                                                 (name,
398                                                  BindingFlags.InvokeMethod |
399                                                         BindingFlags.Instance |
400                                                         BindingFlags.Public,
401                                                  null, manager, args, null, null, null);
402                         } catch (MissingMethodException) {
403                                 return null;
404                         } catch (SecurityException) {
405                                 return null;
406                         }
407                 }
408         }
409
410         // Get an encoder for a specific code page.
411 #if ECMA_COMPAT
412         private
413 #else
414         public
415 #endif
416         static Encoding GetEncoding (int codepage)
417         {
418                 if (codepage < 0 || codepage > 0xffff)
419                         throw new ArgumentOutOfRangeException ("codepage", 
420                                 "Valid values are between 0 and 65535, inclusive.");
421
422                 // Check for the builtin code pages first.
423                 switch (codepage) {
424                         case 0: return Default;
425
426                         case ASCIIEncoding.ASCII_CODE_PAGE:
427                                 return ASCII;
428
429                         case UTF7Encoding.UTF7_CODE_PAGE:
430                                 return UTF7;
431
432                         case UTF8Encoding.UTF8_CODE_PAGE:
433                                 return UTF8;
434
435                         case UTF32Encoding.UTF32_CODE_PAGE:
436                                 return UTF32;
437
438                         case UTF32Encoding.BIG_UTF32_CODE_PAGE:
439                                 return BigEndianUTF32;
440
441                         case UnicodeEncoding.UNICODE_CODE_PAGE:
442                                 return Unicode;
443
444                         case UnicodeEncoding.BIG_UNICODE_CODE_PAGE:
445                                 return BigEndianUnicode;
446
447 #if !MOONLIGHT
448                         case Latin1Encoding.ISOLATIN_CODE_PAGE:
449                                 return ISOLatin1;
450 #endif
451                         default: break;
452                 }
453 #if !MOONLIGHT
454                 // Try to obtain a code page handler from the I18N handler.
455                 Encoding enc = (Encoding)(InvokeI18N ("GetEncoding", codepage));
456                 if (enc != null) {
457                         enc.is_readonly = true;
458                         return enc;
459                 }
460
461                 // Build a code page class name.
462                 String cpName = "System.Text.CP" + codepage.ToString ();
463
464                 // Look for a code page converter in this assembly.
465                 Assembly assembly = Assembly.GetExecutingAssembly ();
466                 Type type = assembly.GetType (cpName);
467                 if (type != null) {
468                         enc = (Encoding)(Activator.CreateInstance (type));
469                         enc.is_readonly = true;
470                         return enc;
471                 }
472
473                 // Look in any assembly, in case the application
474                 // has provided its own code page handler.
475                 type = Type.GetType (cpName);
476                 if (type != null) {
477                         enc = (Encoding)(Activator.CreateInstance (type));
478                         enc.is_readonly = true;
479                         return enc;
480                 }
481 #endif // !NET_2_1
482                 // We have no idea how to handle this code page.
483                 throw new NotSupportedException
484                         (String.Format ("CodePage {0} not supported", codepage.ToString ()));
485         }
486
487 #if !ECMA_COMPAT
488
489         [ComVisible (false)]
490         public virtual object Clone ()
491         {
492                 Encoding e = (Encoding) MemberwiseClone ();
493                 e.is_readonly = false;
494                 return e;
495         }
496
497 #if !MOONLIGHT
498
499         public static Encoding GetEncoding (int codepage,
500                 EncoderFallback encoderFallback, DecoderFallback decoderFallback)
501         {
502                 if (encoderFallback == null)
503                         throw new ArgumentNullException ("encoderFallback");
504                 if (decoderFallback == null)
505                         throw new ArgumentNullException ("decoderFallback");
506
507                 Encoding e = GetEncoding (codepage).Clone () as Encoding;
508                 e.is_readonly = false;
509                 e.encoder_fallback = encoderFallback;
510                 e.decoder_fallback = decoderFallback;
511                 return e;
512         }
513
514         public static Encoding GetEncoding (string name,
515                 EncoderFallback encoderFallback, DecoderFallback decoderFallback)
516         {
517                 if (encoderFallback == null)
518                         throw new ArgumentNullException ("encoderFallback");
519                 if (decoderFallback == null)
520                         throw new ArgumentNullException ("decoderFallback");
521
522                 Encoding e = GetEncoding (name).Clone () as Encoding;
523                 e.is_readonly = false;
524                 e.encoder_fallback = encoderFallback;
525                 e.decoder_fallback = decoderFallback;
526                 return e;
527         }
528
529 #endif // !NET_2_1
530
531         static EncodingInfo [] encoding_infos;
532
533         // FIXME: As everyone would agree, this implementation is so *hacky*
534         // and could be very easily broken. But since there is a test for
535         // this method to make sure that this method always returns
536         // the same number and content of encoding infos, this won't
537         // matter practically.
538         public static EncodingInfo[] GetEncodings ()
539         {
540                 if (encoding_infos == null) {
541                         int [] codepages = new int [] {
542                                 37, 437, 500, 708,
543                                 850, 852, 855, 857, 858, 860, 861, 862, 863, 
544                                 864, 865, 866, 869, 870, 874, 875,
545                                 932, 936, 949, 950,
546                                 1026, 1047, 1140, 1141, 1142, 1143, 1144,
547                                 1145, 1146, 1147, 1148, 1149,
548                                 1200, 1201, 1250, 1251, 1252, 1253, 1254,
549                                 1255, 1256, 1257, 1258,
550                                 10000, 10079, 12000, 12001,
551                                 20127, 20273, 20277, 20278, 20280, 20284,
552                                 20285, 20290, 20297, 20420, 20424, 20866,
553                                 20871, 21025, 21866, 28591, 28592, 28593,
554                                 28594, 28595, 28596, 28597, 28598, 28599,
555                                 28605, 38598,
556                                 50220, 50221, 50222, 51932, 51949, 54936,
557                                 57002, 57003, 57004, 57005, 57006, 57007,
558                                 57008, 57009, 57010, 57011,
559                                 65000, 65001};
560
561                         encoding_infos = new EncodingInfo [codepages.Length];
562                         for (int i = 0; i < codepages.Length; i++)
563                                 encoding_infos [i] = new EncodingInfo (codepages [i]);
564                 }
565                 return encoding_infos;
566         }
567
568 #if !MOONLIGHT
569         [ComVisible (false)]
570         public bool IsAlwaysNormalized ()
571         {
572                 return IsAlwaysNormalized (NormalizationForm.FormC);
573         }
574
575         [ComVisible (false)]
576         public virtual bool IsAlwaysNormalized (NormalizationForm form)
577         {
578                 // umm, ASCIIEncoding should have overriden this method, no?
579                 return form == NormalizationForm.FormC && this is ASCIIEncoding;
580         }
581 #endif // NET_2_1
582
583         // Get an encoding object for a specific web encoding name.
584         public static Encoding GetEncoding (string name)
585         {
586                 // Validate the parameters.
587                 if (name == null) {
588                         throw new ArgumentNullException ("name");
589                 }
590                 
591                 string converted = name.ToLowerInvariant ().Replace ('-', '_');
592                 
593                 // Builtin web encoding names and the corresponding code pages.
594                 switch (converted) {
595                 case "ascii":
596                 case "us_ascii":
597                 case "us":
598                 case "ansi_x3.4_1968":
599                 case "ansi_x3.4_1986":
600                 case "cp367":
601                 case "csascii":
602                 case "ibm367":
603                 case "iso_ir_6":
604                 case "iso646_us":
605                 case "iso_646.irv:1991":
606                         return GetEncoding (ASCIIEncoding.ASCII_CODE_PAGE);
607
608                 case "utf_7":
609                 case "csunicode11utf7":
610                 case "unicode_1_1_utf_7":
611                 case "unicode_2_0_utf_7":
612                 case "x_unicode_1_1_utf_7":
613                 case "x_unicode_2_0_utf_7":
614                         return GetEncoding (UTF7Encoding.UTF7_CODE_PAGE);
615                 
616                 case "utf_8":
617                 case "unicode_1_1_utf_8":
618                 case "unicode_2_0_utf_8":
619                 case "x_unicode_1_1_utf_8":
620                 case "x_unicode_2_0_utf_8":
621                         return GetEncoding (UTF8Encoding.UTF8_CODE_PAGE);
622                 
623                 case "utf_16":
624                 case "utf_16le":
625                 case "ucs_2":
626                 case "unicode":
627                 case "iso_10646_ucs2":
628                         return GetEncoding (UnicodeEncoding.UNICODE_CODE_PAGE);
629
630                 case "unicodefffe":
631                 case "utf_16be":
632                         return GetEncoding (UnicodeEncoding.BIG_UNICODE_CODE_PAGE);
633                 
634                 case "utf_32":
635                 case "utf_32le":
636                 case "ucs_4":
637                         return GetEncoding (UTF32Encoding.UTF32_CODE_PAGE);
638
639                 case "utf_32be":
640                         return GetEncoding (UTF32Encoding.BIG_UTF32_CODE_PAGE);
641
642 #if !MOONLIGHT
643                 case "iso_8859_1":
644                 case "latin1":
645                         return GetEncoding (Latin1Encoding.ISOLATIN_CODE_PAGE);
646 #endif
647                 }
648                 
649 #if !MOONLIGHT
650                 // Try to obtain a web encoding handler from the I18N handler.
651                 Encoding enc = (Encoding)(InvokeI18N ("GetEncoding", name));
652                 if (enc != null) {
653                         return enc;
654                 }
655
656                 // Build a web encoding class name.
657                 String encName = "System.Text.ENC" + converted;
658                                                  
659
660                 // Look for a code page converter in this assembly.
661                 Assembly assembly = Assembly.GetExecutingAssembly ();
662                 Type type = assembly.GetType (encName);
663                 if (type != null) {
664                         return (Encoding)(Activator.CreateInstance (type));
665                 }
666
667                 // Look in any assembly, in case the application
668                 // has provided its own code page handler.
669                 type = Type.GetType (encName);
670                 if (type != null) {
671                         return (Encoding)(Activator.CreateInstance (type));
672                 }
673 #endif
674                 // We have no idea how to handle this encoding name.
675                 throw new ArgumentException (String.Format ("Encoding name '{0}' not "
676                         + "supported", name), "name");
677         }
678
679 #endif // !ECMA_COMPAT
680
681         // Get a hash code for this instance.
682         public override int GetHashCode ()
683         {
684                 return DecoderFallback.GetHashCode () << 24 + EncoderFallback.GetHashCode () << 16 + codePage;
685         }
686
687         // Get the maximum number of bytes needed to encode a
688         // specified number of characters.
689         public abstract int GetMaxByteCount (int charCount);
690
691         // Get the maximum number of characters needed to decode a
692         // specified number of bytes.
693         public abstract int GetMaxCharCount (int byteCount);
694
695         // Get the identifying preamble for this encoding.
696         public virtual byte[] GetPreamble ()
697         {
698                 return EmptyArray<byte>.Value;
699         }
700
701         // Decode a buffer of bytes into a string.
702         public virtual String GetString (byte[] bytes, int index, int count)
703         {
704                 return new String (GetChars(bytes, index, count));
705         }
706         public virtual String GetString (byte[] bytes)
707         {
708                 if (bytes == null)
709                         throw new ArgumentNullException ("bytes");
710
711                 return GetString (bytes, 0, bytes.Length);
712         }
713
714 #if !ECMA_COMPAT
715
716         internal bool is_mail_news_display;
717         internal bool is_mail_news_save;
718         internal bool is_browser_save = false;
719         internal bool is_browser_display = false;
720         internal string body_name;
721         internal string encoding_name;
722         internal string header_name;
723         internal string web_name;
724
725         // Get the mail body name for this encoding.
726         public virtual String BodyName
727         {
728                 get {
729                         return body_name;
730                 }
731         }
732
733         // Get the code page represented by this object.
734         public virtual int CodePage
735         {
736                 get {
737                         return codePage;
738                 }
739         }
740
741         // Get the human-readable name for this encoding.
742         public virtual String EncodingName
743         {
744                 get {
745                         return encoding_name;
746                 }
747         }
748
749         // Get the mail agent header name for this encoding.
750         public virtual String HeaderName
751         {
752                 get {
753                         return header_name;
754                 }
755         }
756
757         // Determine if this encoding can be displayed in a Web browser.
758         public virtual bool IsBrowserDisplay
759         {
760                 get {
761                         return is_browser_display;
762                 }
763         }
764
765         // Determine if this encoding can be saved from a Web browser.
766         public virtual bool IsBrowserSave
767         {
768                 get {
769                         return is_browser_save;
770                 }
771         }
772
773         // Determine if this encoding can be displayed in a mail/news agent.
774         public virtual bool IsMailNewsDisplay
775         {
776                 get {
777                         return is_mail_news_display;
778                 }
779         }
780
781         // Determine if this encoding can be saved from a mail/news agent.
782         public virtual bool IsMailNewsSave
783         {
784                 get {
785                         return is_mail_news_save;
786                 }
787         }
788
789         // Get the IANA-preferred Web name for this encoding.
790         public virtual String WebName
791         {
792                 get {
793                         return web_name;
794                 }
795         }
796
797         // Get the Windows code page represented by this object.
798         public virtual int WindowsCodePage
799         {
800                 get {
801                         // We make no distinction between normal and
802                         // Windows code pages in this implementation.
803                         return windows_code_page;
804                 }
805         }
806
807 #endif // !ECMA_COMPAT
808
809         // Storage for standard encoding objects.
810         static volatile Encoding asciiEncoding;
811         static volatile Encoding bigEndianEncoding;
812         static volatile Encoding defaultEncoding;
813         static volatile Encoding utf7Encoding;
814         static volatile Encoding utf8EncodingWithMarkers;
815         static volatile Encoding utf8EncodingWithoutMarkers;
816         static volatile Encoding unicodeEncoding;
817         static volatile Encoding isoLatin1Encoding;
818         static volatile Encoding utf8EncodingUnsafe;
819         static volatile Encoding utf32Encoding;
820         static volatile Encoding bigEndianUTF32Encoding;
821
822         static readonly object lockobj = new object ();
823
824         // Get the standard ASCII encoding object.
825         public static Encoding ASCII
826         {
827                 get {
828                         if (asciiEncoding == null) {
829                                 lock (lockobj) {
830                                         if (asciiEncoding == null) {
831                                                 asciiEncoding = new ASCIIEncoding ();
832 //                                              asciiEncoding.is_readonly = true;
833                                         }
834                                 }
835                         }
836
837                         return asciiEncoding;
838                 }
839         }
840
841         // Get the standard big-endian Unicode encoding object.
842         public static Encoding BigEndianUnicode
843         {
844                 get {
845                         if (bigEndianEncoding == null) {
846                                 lock (lockobj) {
847                                         if (bigEndianEncoding == null) {
848                                                 bigEndianEncoding = new UnicodeEncoding (true, true);
849 //                                              bigEndianEncoding.is_readonly = true;
850                                         }
851                                 }
852                         }
853
854                         return bigEndianEncoding;
855                 }
856         }
857
858         [MethodImpl (MethodImplOptions.InternalCall)]
859         extern internal static string InternalCodePage (ref int code_page);
860         
861         // Get the default encoding object.
862         public static Encoding Default
863         {
864                 get {
865                         if (defaultEncoding == null) {
866                                 lock (lockobj) {
867                                         if (defaultEncoding == null) {
868                                                 // See if the underlying system knows what
869                                                 // code page handler we should be using.
870                                                 int code_page = 1;
871                                                 
872                                                 string code_page_name = InternalCodePage (ref code_page);
873                                                 try {
874                                                         if (code_page == -1)
875                                                                 defaultEncoding = GetEncoding (code_page_name);
876                                                         else {
877                                                                 // map the codepage from internal to our numbers
878                                                                 code_page = code_page & 0x0fffffff;
879                                                                 switch (code_page){
880                                                                 case 1: code_page = ASCIIEncoding.ASCII_CODE_PAGE; break;
881                                                                 case 2: code_page = UTF7Encoding.UTF7_CODE_PAGE; break;
882                                                                 case 3: code_page = UTF8Encoding.UTF8_CODE_PAGE; break;
883                                                                 case 4: code_page = UnicodeEncoding.UNICODE_CODE_PAGE; break;
884                                                                 case 5: code_page = UnicodeEncoding.BIG_UNICODE_CODE_PAGE; break;
885 #if !MOONLIGHT
886                                                                 case 6: code_page = Latin1Encoding.ISOLATIN_CODE_PAGE; break;
887 #endif
888                                                                 }
889                                                                 defaultEncoding = GetEncoding (code_page);
890                                                         }
891                                                 } catch (NotSupportedException) {
892 #if MOONLIGHT
893                                                         defaultEncoding = UTF8;
894 #else
895                                                         // code_page is not supported on underlying platform
896                                                         defaultEncoding = UTF8Unmarked;
897 #endif
898                                                 } catch (ArgumentException) {
899                                                         // code_page_name is not a valid code page, or is 
900                                                         // not supported by underlying OS
901 #if MOONLIGHT
902                                                         defaultEncoding = UTF8;
903 #else
904                                                         defaultEncoding = UTF8Unmarked;
905 #endif
906                                                 }
907                                                 defaultEncoding.is_readonly = true;
908                                         }
909                                 }
910                         }
911
912                         return defaultEncoding;
913                 }
914         }
915
916 #if !MOONLIGHT
917
918         // Get the ISO Latin1 encoding object.
919         private static Encoding ISOLatin1
920         {
921                 get {
922                         if (isoLatin1Encoding == null) {
923                                 lock (lockobj) {
924                                         if (isoLatin1Encoding == null) {
925                                                 isoLatin1Encoding = new Latin1Encoding ();
926 //                                              isoLatin1Encoding.is_readonly = true;
927                                         }
928                                 }
929                         }
930
931                         return isoLatin1Encoding;
932                 }
933         }
934
935 #endif
936
937         // Get the standard UTF-7 encoding object.
938 #if ECMA_COMPAT
939         private
940 #else
941         public
942 #endif
943         static Encoding UTF7
944         {
945                 get {
946                         if (utf7Encoding == null) {
947                                 lock (lockobj) {
948                                         if (utf7Encoding == null) {
949                                                 utf7Encoding = new UTF7Encoding ();
950 //                                              utf7Encoding.is_readonly = true;
951                                         }
952                                 }
953                         }
954
955                         return utf7Encoding;
956                 }
957         }
958
959         // Get the standard UTF-8 encoding object.
960         public static Encoding UTF8
961         {
962                 get {
963                         if (utf8EncodingWithMarkers == null) {
964                                 lock (lockobj) {
965                                         if (utf8EncodingWithMarkers == null) {
966                                                 utf8EncodingWithMarkers = new UTF8Encoding (true);
967 //                                              utf8EncodingWithMarkers.is_readonly = true;
968                                         }
969                                 }
970                         }
971
972                         return utf8EncodingWithMarkers;
973                 }
974         }
975
976         //
977         // Only internal, to be used by the class libraries: Unmarked and non-input-validating
978         //
979         internal static Encoding UTF8Unmarked {
980                 get {
981                         if (utf8EncodingWithoutMarkers == null) {
982                                 lock (lockobj){
983                                         if (utf8EncodingWithoutMarkers == null){
984                                                 utf8EncodingWithoutMarkers = new UTF8Encoding (false, false);
985 //                                              utf8EncodingWithoutMarkers.is_readonly = true;
986                                         }
987                                 }
988                         }
989
990                         return utf8EncodingWithoutMarkers;
991                 }
992         }
993         
994         //
995         // Only internal, to be used by the class libraries: Unmarked and non-input-validating
996         //
997         internal static Encoding UTF8UnmarkedUnsafe {
998                 get {
999                         if (utf8EncodingUnsafe == null) {
1000                                 lock (lockobj){
1001                                         if (utf8EncodingUnsafe == null){
1002                                                 utf8EncodingUnsafe = new UTF8Encoding (false, false);
1003                                                 utf8EncodingUnsafe.is_readonly = false;
1004                                                 utf8EncodingUnsafe.DecoderFallback = new DecoderReplacementFallback (String.Empty);
1005                                                 utf8EncodingUnsafe.is_readonly = true;
1006                                         }
1007                                 }
1008                         }
1009
1010                         return utf8EncodingUnsafe;
1011                 }
1012         }
1013         
1014         // Get the standard little-endian Unicode encoding object.
1015         public static Encoding Unicode
1016         {
1017                 get {
1018                         if (unicodeEncoding == null) {
1019                                 lock (lockobj) {
1020                                         if (unicodeEncoding == null) {
1021                                                 unicodeEncoding = new UnicodeEncoding (false, true);
1022 //                                              unicodeEncoding.is_readonly = true;
1023                                         }
1024                                 }
1025                         }
1026
1027                         return unicodeEncoding;
1028                 }
1029         }
1030
1031         // Get the standard little-endian UTF-32 encoding object.
1032         public static Encoding UTF32
1033         {
1034                 get {
1035                         if (utf32Encoding == null) {
1036                                 lock (lockobj) {
1037                                         if (utf32Encoding == null) {
1038                                                 utf32Encoding = new UTF32Encoding (false, true);
1039 //                                              utf32Encoding.is_readonly = true;
1040                                         }
1041                                 }
1042                         }
1043
1044                         return utf32Encoding;
1045                 }
1046         }
1047
1048         // Get the standard big-endian UTF-32 encoding object.
1049         internal static Encoding BigEndianUTF32
1050         {
1051                 get {
1052                         if (bigEndianUTF32Encoding == null) {
1053                                 lock (lockobj) {
1054                                         if (bigEndianUTF32Encoding == null) {
1055                                                 bigEndianUTF32Encoding = new UTF32Encoding (true, true);
1056 //                                              bigEndianUTF32Encoding.is_readonly = true;
1057                                         }
1058                                 }
1059                         }
1060
1061                         return bigEndianUTF32Encoding;
1062                 }
1063         }
1064
1065         // Forwarding decoder implementation.
1066         private sealed class ForwardingDecoder : Decoder
1067         {
1068                 private Encoding encoding;
1069
1070                 // Constructor.
1071                 public ForwardingDecoder (Encoding enc)
1072                 {
1073                         encoding = enc;
1074                         DecoderFallback fallback = encoding.DecoderFallback;
1075                         if (fallback != null)
1076                                 Fallback = fallback;
1077                 }
1078
1079                 // Override inherited methods.
1080                 public override int GetCharCount (byte[] bytes, int index, int count)
1081                 {
1082                         return encoding.GetCharCount (bytes, index, count);
1083                 }
1084                 public override int GetChars (byte[] bytes, int byteIndex,
1085                                                                          int byteCount, char[] chars,
1086                                                                          int charIndex)
1087                 {
1088                         return encoding.GetChars (bytes, byteIndex, byteCount, chars, charIndex);
1089                 }
1090
1091         } // class ForwardingDecoder
1092
1093         // Forwarding encoder implementation.
1094         private sealed class ForwardingEncoder : Encoder
1095         {
1096                 private Encoding encoding;
1097
1098                 // Constructor.
1099                 public ForwardingEncoder (Encoding enc)
1100                 {
1101                         encoding = enc;
1102                         EncoderFallback fallback = encoding.EncoderFallback;
1103                         if (fallback != null)
1104                                 Fallback = fallback;
1105                 }
1106
1107                 // Override inherited methods.
1108                 public override int GetByteCount (char[] chars, int index, int count, bool flush)
1109                 {
1110                         return encoding.GetByteCount (chars, index, count);
1111                 }
1112                 public override int GetBytes (char[] chars, int charIndex,
1113                                                                          int charCount, byte[] bytes,
1114                                                                          int byteCount, bool flush)
1115                 {
1116                         return encoding.GetBytes (chars, charIndex, charCount, bytes, byteCount);
1117                 }
1118
1119         } // class ForwardingEncoder
1120
1121         [CLSCompliantAttribute(false)]
1122         [ComVisible (false)]
1123         public unsafe virtual int GetByteCount (char *chars, int count)
1124         {
1125                 if (chars == null)
1126                         throw new ArgumentNullException ("chars");
1127                 if (count < 0)
1128                         throw new ArgumentOutOfRangeException ("count");
1129                 char [] c = new char [count];
1130
1131                 for (int p = 0; p < count; p++)
1132                         c [p] = chars [p];
1133
1134                 return GetByteCount (c);
1135         }
1136
1137         [CLSCompliantAttribute(false)]
1138         [ComVisible (false)]
1139         public unsafe virtual int GetCharCount (byte *bytes, int count)
1140         {
1141                 if (bytes == null)
1142                         throw new ArgumentNullException ("bytes");
1143                 if (count < 0)
1144                         throw new ArgumentOutOfRangeException ("count");
1145                 
1146                 byte [] ba = new byte [count];
1147                 for (int i = 0; i < count; i++)
1148                         ba [i] = bytes [i];
1149                 return GetCharCount (ba, 0, count);
1150         }
1151
1152         [CLSCompliantAttribute(false)]
1153         [ComVisible (false)]
1154         public unsafe virtual int GetChars (byte *bytes, int byteCount, char *chars, int charCount)
1155         {
1156                 if (bytes == null)
1157                         throw new ArgumentNullException ("bytes");
1158                 if (chars == null)
1159                         throw new ArgumentNullException ("chars");
1160                 if (charCount < 0)
1161                         throw new ArgumentOutOfRangeException ("charCount");
1162                 if (byteCount < 0)
1163                         throw new ArgumentOutOfRangeException ("byteCount");
1164                 
1165                 byte [] ba = new byte [byteCount];
1166                 for (int i = 0; i < byteCount; i++)
1167                         ba [i] = bytes [i];
1168                 char [] ret = GetChars (ba, 0, byteCount);
1169                 int top = ret.Length;
1170
1171                 if (top > charCount)
1172                         throw new ArgumentException ("charCount is less than the number of characters produced", "charCount");
1173                 
1174                 for (int i = 0; i < top; i++)
1175                         chars [i] = ret [i];
1176                 return top;
1177         }
1178
1179         [CLSCompliantAttribute(false)]
1180         [ComVisible (false)]
1181         public unsafe virtual int GetBytes (char *chars, int charCount, byte *bytes, int byteCount)
1182         {
1183                 if (bytes == null)
1184                         throw new ArgumentNullException ("bytes");
1185                 if (chars == null)
1186                         throw new ArgumentNullException ("chars");
1187                 if (charCount < 0)
1188                         throw new ArgumentOutOfRangeException ("charCount");
1189                 if (byteCount < 0)
1190                         throw new ArgumentOutOfRangeException ("byteCount");
1191                 
1192                 char [] c = new char [charCount];
1193                 
1194                 for (int i = 0; i < charCount; i++)
1195                         c [i] = chars [i];
1196
1197                 byte [] b = GetBytes (c, 0, charCount);
1198                 int top = b.Length;
1199                 if (top > byteCount)
1200                         throw new ArgumentException ("byteCount is less that the number of bytes produced", "byteCount");
1201
1202                 for (int i = 0; i < top; i++)
1203                         bytes [i] = b [i];
1204                 
1205                 return b.Length;
1206         }
1207 }; // class Encoding
1208
1209 }; // namespace System.Text