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