Mark tests as not working under TARGET_JVM
[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         bool is_readonly = true;
50
51         // Constructor.
52         protected Encoding ()
53         {
54         }
55
56 #if ECMA_COMPAT
57         protected internal
58 #else
59         protected
60 #endif
61         Encoding (int codePage)
62         {
63                 this.codePage = windows_code_page = codePage;
64
65 #if NET_2_0
66                 switch (codePage) {
67                 default:
68                         // MS has "InternalBestFit{Decoder|Encoder}Fallback
69                         // here, but we dunno what they are for.
70                         decoder_fallback = DecoderFallback.ReplacementFallback;
71                         encoder_fallback = EncoderFallback.ReplacementFallback;
72                         break;
73                 case 20127: // ASCII
74                 case 54936: // GB18030
75                         decoder_fallback = DecoderFallback.ReplacementFallback;
76                         encoder_fallback = EncoderFallback.ReplacementFallback;
77                         break;
78                 case 1200: // UTF16
79                 case 1201: // UTF16
80                 case 12000: // UTF32
81                 case 12001: // UTF32
82                 case 65000: // UTF7
83                 case 65001: // UTF8
84                         decoder_fallback = new DecoderReplacementFallback (String.Empty);
85                         encoder_fallback = new EncoderReplacementFallback (String.Empty);
86                         break;
87                 }
88 #endif
89         }
90
91         // until we change the callers:
92         internal static string _ (string arg) {
93                 return arg;
94         }
95
96 #if NET_2_0
97         DecoderFallback decoder_fallback;
98         EncoderFallback encoder_fallback;
99
100         [ComVisible (false)]
101         public bool IsReadOnly {
102                 get { return is_readonly; }
103         }
104
105         [ComVisible (false)]
106         public virtual bool IsSingleByte {
107                 get { return false; }
108         }
109
110         [MonoTODO ("not used yet")]
111         [ComVisible (false)]
112         public DecoderFallback DecoderFallback {
113                 get {
114                         if (decoder_fallback == null)
115                                 decoder_fallback = new DecoderReplacementFallback (String.Empty);
116                         return decoder_fallback;
117                 }
118                 set {
119                         if (IsReadOnly)
120                                 throw new InvalidOperationException ("This Encoding is readonly.");
121                         if (value == null)
122                                 throw new ArgumentNullException ();
123                         decoder_fallback = value;
124                 }
125         }
126
127         [MonoTODO ("not used yet")]
128         [ComVisible (false)]
129         public EncoderFallback EncoderFallback {
130                 get {
131                         if (encoder_fallback == null)
132                                 encoder_fallback = new EncoderReplacementFallback (String.Empty);
133                         return encoder_fallback;
134                 }
135                 set {
136                         if (IsReadOnly)
137                                 throw new InvalidOperationException ("This Encoding is readonly.");
138                         if (value == null)
139                                 throw new ArgumentNullException ();
140                         encoder_fallback = value;
141                 }
142         }
143
144         internal void SetFallbackInternal (EncoderFallback e, DecoderFallback d)
145         {
146                 if (e != null)
147                         encoder_fallback = e;
148                 if (d != null)
149                         decoder_fallback = d;
150         }
151 #endif
152
153         // Convert between two encodings.
154         public static byte[] Convert (Encoding srcEncoding, Encoding dstEncoding,
155                                                                  byte[] bytes)
156         {
157                 if (srcEncoding == null) {
158                         throw new ArgumentNullException ("srcEncoding");
159                 }
160                 if (dstEncoding == null) {
161                         throw new ArgumentNullException ("dstEncoding");
162                 }
163                 if (bytes == null) {
164                         throw new ArgumentNullException ("bytes");
165                 }
166                 return dstEncoding.GetBytes (srcEncoding.GetChars (bytes, 0, bytes.Length));
167         }
168         public static byte[] Convert (Encoding srcEncoding, Encoding dstEncoding,
169                                                                  byte[] bytes, int index, int count)
170         {
171                 if (srcEncoding == null) {
172                         throw new ArgumentNullException ("srcEncoding");
173                 }
174                 if (dstEncoding == null) {
175                         throw new ArgumentNullException ("dstEncoding");
176                 }
177                 if (bytes == null) {
178                         throw new ArgumentNullException ("bytes");
179                 }
180                 if (index < 0 || index > bytes.Length) {
181                         throw new ArgumentOutOfRangeException
182                                 ("index", _("ArgRange_Array"));
183                 }
184                 if (count < 0 || (bytes.Length - index) < count) {
185                         throw new ArgumentOutOfRangeException
186                                 ("count", _("ArgRange_Array"));
187                 }
188                 return dstEncoding.GetBytes (srcEncoding.GetChars (bytes, index, count));
189         }
190
191         // Determine if two Encoding objects are equal.
192         public override bool Equals (Object obj)
193         {
194                 Encoding enc = (obj as Encoding);
195                 if (enc != null) {
196 #if NET_2_0
197                         return codePage == enc.codePage &&
198                                 DecoderFallback.Equals (enc.DecoderFallback) &&
199                                 EncoderFallback.Equals (enc.EncoderFallback);
200 #else
201                         return (codePage == enc.codePage);
202 #endif
203                 } else {
204                         return false;
205                 }
206         }
207
208         // Get the number of characters needed to encode a character buffer.
209         public abstract int GetByteCount (char[] chars, int index, int count);
210
211         // Convenience wrappers for "GetByteCount".
212         public virtual int GetByteCount (String s)
213         {
214                 if (s == null)
215                         throw new ArgumentNullException ("s");
216
217                 if (s.Length == 0)
218                         return 0;
219 #if NET_2_0
220                 unsafe {
221                         fixed (char* cptr = s) {
222                                 return GetByteCount (cptr, s.Length);
223                         }
224                 }
225 #else
226                 char[] chars = s.ToCharArray ();
227                 return GetByteCount (chars, 0, chars.Length);
228 #endif
229         }
230         public virtual int GetByteCount (char[] chars)
231         {
232                 if (chars != null) {
233                         return GetByteCount (chars, 0, chars.Length);
234                 } else {
235                         throw new ArgumentNullException ("chars");
236                 }
237         }
238
239         // Get the bytes that result from encoding a character buffer.
240         public abstract int GetBytes (char[] chars, int charIndex, int charCount,
241                                                                  byte[] bytes, int byteIndex);
242
243         // Convenience wrappers for "GetBytes".
244         public virtual int GetBytes (String s, int charIndex, int charCount,
245                                                                 byte[] bytes, int byteIndex)
246         {
247                 if (s == null)
248                         throw new ArgumentNullException ("s");
249 #if NET_2_0
250                 if (charIndex < 0 || charIndex > s.Length)
251                         throw new ArgumentOutOfRangeException ("charIndex", _("ArgRange_Array"));
252                 if (charCount < 0 || charIndex + charCount > s.Length)
253                         throw new ArgumentOutOfRangeException ("charCount", _("ArgRange_Array"));
254                 if (byteIndex < 0 || byteIndex > bytes.Length)
255                         throw new ArgumentOutOfRangeException ("byteIndex", _("ArgRange_Array"));
256
257                 if (charCount == 0 || bytes.Length == byteIndex)
258                         return 0;
259                 unsafe {
260                         fixed (char* cptr = s) {
261                                 fixed (byte* bptr = bytes) {
262                                         return GetBytes (cptr + charIndex,
263                                                 charCount,
264                                                 bptr + byteIndex,
265                                                 bytes.Length - byteIndex);
266                                 }
267                         }
268                 }
269 #else
270                 return GetBytes (s.ToCharArray(), charIndex, charCount, bytes, byteIndex);
271 #endif
272         }
273         public virtual byte[] GetBytes (String s)
274         {
275                 if (s == null)
276                         throw new ArgumentNullException ("s");
277
278 #if NET_2_0
279                 if (s.Length == 0)
280                         return new byte [0];
281                 int byteCount = GetByteCount (s);
282                 if (byteCount == 0)
283                         return new byte [0];
284                 unsafe {
285                         fixed (char* cptr = s) {
286                                 byte [] bytes = new byte [byteCount];
287                                 fixed (byte* bptr = bytes) {
288                                         GetBytes (cptr, s.Length,
289                                                 bptr, byteCount);
290                                         return bytes;
291                                 }
292                         }
293                 }
294 #else
295                 char[] chars = s.ToCharArray ();
296                 int numBytes = GetByteCount (chars, 0, chars.Length);
297                 byte[] bytes = new byte [numBytes];
298                 GetBytes (chars, 0, chars.Length, bytes, 0);
299                 return bytes;
300 #endif
301         }
302         public virtual byte[] GetBytes (char[] chars, int index, int count)
303         {
304                 int numBytes = GetByteCount (chars, index, count);
305                 byte[] bytes = new byte [numBytes];
306                 GetBytes (chars, index, count, bytes, 0);
307                 return bytes;
308         }
309         public virtual byte[] GetBytes (char[] chars)
310         {
311                 int numBytes = GetByteCount (chars, 0, chars.Length);
312                 byte[] bytes = new byte [numBytes];
313                 GetBytes (chars, 0, chars.Length, bytes, 0);
314                 return bytes;
315         }
316
317         // Get the number of characters needed to decode a byte buffer.
318         public abstract int GetCharCount (byte[] bytes, int index, int count);
319
320         // Convenience wrappers for "GetCharCount".
321         public virtual int GetCharCount (byte[] bytes)
322         {
323                 if (bytes == null) {
324                         throw new ArgumentNullException ("bytes");
325                 }
326                 return GetCharCount (bytes, 0, bytes.Length);
327         }
328
329         // Get the characters that result from decoding a byte buffer.
330         public abstract int GetChars (byte[] bytes, int byteIndex, int byteCount,
331                                                                  char[] chars, int charIndex);
332
333         // Convenience wrappers for "GetChars".
334         public virtual char[] GetChars (byte[] bytes, int index, int count)
335         {
336                 int numChars = GetCharCount (bytes, index, count);
337                 char[] chars = new char [numChars];
338                 GetChars (bytes, index, count, chars, 0);
339                 return chars;
340         }
341         public virtual char[] GetChars (byte[] bytes)
342         {
343                 if (bytes == null) {
344                         throw new ArgumentNullException ("bytes");
345                 }
346                 int numChars = GetCharCount (bytes, 0, bytes.Length);
347                 char[] chars = new char [numChars];
348                 GetChars (bytes, 0, bytes.Length, chars, 0);
349                 return chars;
350         }
351
352         // Get a decoder that forwards requests to this object.
353         public virtual Decoder GetDecoder ()
354         {
355                 return new ForwardingDecoder (this);
356         }
357
358         // Get an encoder that forwards requests to this object.
359         public virtual Encoder GetEncoder ()
360         {
361                 return new ForwardingEncoder (this);
362         }
363
364         // Loaded copy of the "I18N" assembly.  We need to move
365         // this into a class in "System.Private" eventually.
366         private static Assembly i18nAssembly;
367         private static bool i18nDisabled;
368
369         // Invoke a specific method on the "I18N" manager object.
370         // Returns NULL if the method failed.
371         private static Object InvokeI18N (String name, params Object[] args)
372         {
373                 lock (lockobj) {
374                         // Bail out if we previously detected that there
375                         // is insufficent engine support for I18N handling.
376                         if (i18nDisabled) {
377                                 return null;
378                         }
379
380                         // Find or load the "I18N" assembly.
381                         if (i18nAssembly == null) {
382                                 try {
383                                         try {
384                                                 i18nAssembly = Assembly.Load (Consts.AssemblyI18N);
385                                         } catch (NotImplementedException) {
386                                                 // Assembly loading unsupported by the engine.
387                                                 i18nDisabled = true;
388                                                 return null;
389                                         }
390                                         if (i18nAssembly == null) {
391                                                 return null;
392                                         }
393                                 } catch (SystemException) {
394                                         return null;
395                                 }
396                         }
397
398                         // Find the "I18N.Common.Manager" class.
399                         Type managerClass;
400                         try {
401                                 managerClass = i18nAssembly.GetType ("I18N.Common.Manager");
402                         } catch (NotImplementedException) {
403                                 // "GetType" is not supported by the engine.
404                                 i18nDisabled = true;
405                                 return null;
406                         }
407                         if (managerClass == null) {
408                                 return null;
409                         }
410
411                         // Get the value of the "PrimaryManager" property.
412                         Object manager;
413                         try {
414                                 manager = managerClass.InvokeMember
415                                                 ("PrimaryManager",
416                                                  BindingFlags.GetProperty |
417                                                         BindingFlags.Static |
418                                                         BindingFlags.Public,
419                                                  null, null, null, null, null, null);
420                                 if (manager == null) {
421                                         return null;
422                                 }
423                         } catch (MissingMethodException) {
424                                 return null;
425                         } catch (SecurityException) {
426                                 return null;
427                         } catch (NotImplementedException) {
428                                 // "InvokeMember" is not supported by the engine.
429                                 i18nDisabled = true;
430                                 return null;
431                         }
432
433                         // Invoke the requested method on the manager.
434                         try {
435                                 return managerClass.InvokeMember
436                                                 (name,
437                                                  BindingFlags.InvokeMethod |
438                                                         BindingFlags.Instance |
439                                                         BindingFlags.Public,
440                                                  null, manager, args, null, null, null);
441                         } catch (MissingMethodException) {
442                                 return null;
443                         } catch (SecurityException) {
444                                 return null;
445                         }
446                 }
447         }
448
449         // Get an encoder for a specific code page.
450 #if ECMA_COMPAT
451         private
452 #else
453         public
454 #endif
455         static Encoding GetEncoding (int codePage)
456         {
457                 if (codePage < 0 || codePage > 0xffff)
458                         throw new ArgumentOutOfRangeException ("codepage", 
459                                 "Valid values are between 0 and 65535, inclusive.");
460
461                 // Check for the builtin code pages first.
462                 switch (codePage) {
463                         case 0: return Default;
464
465                         case ASCIIEncoding.ASCII_CODE_PAGE:
466                                 return ASCII;
467
468                         case UTF7Encoding.UTF7_CODE_PAGE:
469                                 return UTF7;
470
471                         case UTF8Encoding.UTF8_CODE_PAGE:
472                                 return UTF8;
473
474 #if NET_2_0
475                         case UTF32Encoding.UTF32_CODE_PAGE:
476                                 return UTF32;
477
478                         case UTF32Encoding.BIG_UTF32_CODE_PAGE:
479                                 return BigEndianUTF32;
480 #endif
481
482                         case UnicodeEncoding.UNICODE_CODE_PAGE:
483                                 return Unicode;
484
485                         case UnicodeEncoding.BIG_UNICODE_CODE_PAGE:
486                                 return BigEndianUnicode;
487
488                         case Latin1Encoding.ISOLATIN_CODE_PAGE:
489                                 return ISOLatin1;
490
491                         default: break;
492                 }
493
494                 // Try to obtain a code page handler from the I18N handler.
495                 Encoding enc = (Encoding)(InvokeI18N ("GetEncoding", codePage));
496                 if (enc != null) {
497                         enc.is_readonly = true;
498                         return enc;
499                 }
500
501                 // Build a code page class name.
502                 String cpName = "System.Text.CP" + codePage.ToString ();
503
504                 // Look for a code page converter in this assembly.
505                 Assembly assembly = Assembly.GetExecutingAssembly ();
506                 Type type = assembly.GetType (cpName);
507                 if (type != null) {
508                         enc = (Encoding)(Activator.CreateInstance (type));
509                         enc.is_readonly = true;
510                         return enc;
511                 }
512
513                 // Look in any assembly, in case the application
514                 // has provided its own code page handler.
515                 type = Type.GetType (cpName);
516                 if (type != null) {
517                         enc = (Encoding)(Activator.CreateInstance (type));
518                         enc.is_readonly = true;
519                         return enc;
520                 }
521
522                 // We have no idea how to handle this code page.
523                 throw new NotSupportedException
524                         (String.Format ("CodePage {0} not supported", codePage.ToString ()));
525         }
526
527 #if !ECMA_COMPAT
528
529 #if NET_2_0
530         [ComVisible (false)]
531         public virtual object Clone ()
532         {
533                 Encoding e = (Encoding) MemberwiseClone ();
534                 e.is_readonly = false;
535                 return e;
536         }
537
538         public static Encoding GetEncoding (int codePage,
539                 EncoderFallback encoderFallback, DecoderFallback decoderFallback)
540         {
541                 if (encoderFallback == null)
542                         throw new ArgumentNullException ("encoderFallback");
543                 if (decoderFallback == null)
544                         throw new ArgumentNullException ("decoderFallback");
545
546                 Encoding e = GetEncoding (codePage).Clone () as Encoding;
547                 e.is_readonly = false;
548                 e.encoder_fallback = encoderFallback;
549                 e.decoder_fallback = decoderFallback;
550                 return e;
551         }
552
553         public static Encoding GetEncoding (string name,
554                 EncoderFallback encoderFallback, DecoderFallback decoderFallback)
555         {
556                 if (encoderFallback == null)
557                         throw new ArgumentNullException ("encoderFallback");
558                 if (decoderFallback == null)
559                         throw new ArgumentNullException ("decoderFallback");
560
561                 Encoding e = GetEncoding (name).Clone () as Encoding;
562                 e.is_readonly = false;
563                 e.encoder_fallback = encoderFallback;
564                 e.decoder_fallback = decoderFallback;
565                 return e;
566         }
567
568         static EncodingInfo [] encoding_infos;
569
570         // FIXME: As everyone would agree, this implementation is so *hacky*
571         // and could be very easily broken. But since there is a test for
572         // this method to make sure that this method always returns
573         // the same number and content of encoding infos, this won't
574         // matter practically.
575         public static EncodingInfo[] GetEncodings ()
576         {
577                 if (encoding_infos == null) {
578                         int [] codepages = new int [] {
579                                 37, 437, 500, 708,
580                                 850, 852, 855, 857, 858, 860, 861, 862, 863, 
581                                 864, 865, 866, 869, 870, 874, 875,
582                                 932, 936, 949, 950,
583                                 1026, 1047, 1140, 1141, 1142, 1143, 1144,
584                                 1145, 1146, 1147, 1148, 1149,
585                                 1200, 1201, 1250, 1251, 1252, 1253, 1254,
586                                 1255, 1256, 1257, 1258,
587                                 10000, 10079, 12000, 12001,
588                                 20127, 20273, 20277, 20278, 20280, 20284,
589                                 20285, 20290, 20297, 20420, 20424, 20866,
590                                 20871, 21025, 21866, 28591, 28592, 28593,
591                                 28594, 28595, 28596, 28597, 28598, 28599,
592                                 28605, 38598,
593                                 50220, 50221, 50222, 51932, 51949, 54936,
594                                 57002, 57003, 57004, 57005, 57006, 57007,
595                                 57008, 57009, 57010, 57011,
596                                 65000, 65001};
597
598                         encoding_infos = new EncodingInfo [codepages.Length];
599                         for (int i = 0; i < codepages.Length; i++)
600                                 encoding_infos [i] = new EncodingInfo (codepages [i]);
601                 }
602                 return encoding_infos;
603         }
604
605         public bool IsAlwaysNormalized ()
606         {
607                 return IsAlwaysNormalized (NormalizationForm.FormC);
608         }
609
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         static volatile Encoding unixConsoleEncoding;
850 #if NET_2_0
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                                                 defaultEncoding.is_readonly = true;
931                                         }
932                                 }
933                         }
934
935                         return defaultEncoding;
936                 }
937         }
938
939         // Get the ISO Latin1 encoding object.
940         private static Encoding ISOLatin1
941         {
942                 get {
943                         if (isoLatin1Encoding == null) {
944                                 lock (lockobj) {
945                                         if (isoLatin1Encoding == null) {
946                                                 isoLatin1Encoding = new Latin1Encoding ();
947                                                 isoLatin1Encoding.is_readonly = true;
948                                         }
949                                 }
950                         }
951
952                         return isoLatin1Encoding;
953                 }
954         }
955
956         // Get the standard UTF-7 encoding object.
957 #if ECMA_COMPAT
958         private
959 #else
960         public
961 #endif
962         static Encoding UTF7
963         {
964                 get {
965                         if (utf7Encoding == null) {
966                                 lock (lockobj) {
967                                         if (utf7Encoding == null) {
968                                                 utf7Encoding = new UTF7Encoding ();
969                                                 utf7Encoding.is_readonly = true;
970                                         }
971                                 }
972                         }
973
974                         return utf7Encoding;
975                 }
976         }
977
978         // Get the standard UTF-8 encoding object.
979         public static Encoding UTF8
980         {
981                 get {
982                         if (utf8EncodingWithMarkers == null) {
983                                 lock (lockobj) {
984                                         if (utf8EncodingWithMarkers == null) {
985                                                 utf8EncodingWithMarkers = new UTF8Encoding (true);
986                                                 utf8EncodingWithMarkers.is_readonly = true;
987                                         }
988                                 }
989                         }
990
991                         return utf8EncodingWithMarkers;
992                 }
993         }
994
995         //
996         // Only internal, to be used by the class libraries: Unmarked and non-input-validating
997         //
998         internal static Encoding UTF8Unmarked {
999                 get {
1000                         if (utf8EncodingWithoutMarkers == null) {
1001                                 lock (lockobj){
1002                                         if (utf8EncodingWithoutMarkers == null){
1003                                                 utf8EncodingWithoutMarkers = new UTF8Encoding (false, false);
1004                                                 utf8EncodingWithoutMarkers.is_readonly = true;
1005                                         }
1006                                 }
1007                         }
1008
1009                         return utf8EncodingWithoutMarkers;
1010                 }
1011         }
1012         
1013         // Get the standard little-endian Unicode encoding object.
1014         public static Encoding Unicode
1015         {
1016                 get {
1017                         if (unicodeEncoding == null) {
1018                                 lock (lockobj) {
1019                                         if (unicodeEncoding == null) {
1020                                                 unicodeEncoding = new UnicodeEncoding (false, true);
1021                                                 unicodeEncoding.is_readonly = true;
1022                                         }
1023                                 }
1024                         }
1025
1026                         return unicodeEncoding;
1027                 }
1028         }
1029
1030 #if NET_2_0
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 #endif
1065
1066         // Forwarding decoder implementation.
1067         private sealed class ForwardingDecoder : Decoder
1068         {
1069                 private Encoding encoding;
1070
1071                 // Constructor.
1072                 public ForwardingDecoder (Encoding enc)
1073                 {
1074                         encoding = enc;
1075 #if NET_2_0
1076                         Fallback = encoding.DecoderFallback;
1077 #endif
1078                 }
1079
1080                 // Override inherited methods.
1081                 public override int GetCharCount (byte[] bytes, int index, int count)
1082                 {
1083                         return encoding.GetCharCount (bytes, index, count);
1084                 }
1085                 public override int GetChars (byte[] bytes, int byteIndex,
1086                                                                          int byteCount, char[] chars,
1087                                                                          int charIndex)
1088                 {
1089                         return encoding.GetChars (bytes, byteIndex, byteCount, chars, charIndex);
1090                 }
1091
1092         } // class ForwardingDecoder
1093
1094         // Forwarding encoder implementation.
1095         private sealed class ForwardingEncoder : Encoder
1096         {
1097                 private Encoding encoding;
1098
1099                 // Constructor.
1100                 public ForwardingEncoder (Encoding enc)
1101                 {
1102                         encoding = enc;
1103 #if NET_2_0
1104                         Fallback = encoding.EncoderFallback;
1105 #endif
1106                 }
1107
1108                 // Override inherited methods.
1109                 public override int GetByteCount (char[] chars, int index, int count, bool flush)
1110                 {
1111                         return encoding.GetByteCount (chars, index, count);
1112                 }
1113                 public override int GetBytes (char[] chars, int charIndex,
1114                                                                          int charCount, byte[] bytes,
1115                                                                          int byteCount, bool flush)
1116                 {
1117                         return encoding.GetBytes (chars, charIndex, charCount, bytes, byteCount);
1118                 }
1119
1120         } // class ForwardingEncoder
1121
1122 #if NET_2_0
1123         [CLSCompliantAttribute(false)]
1124         [ComVisible (false)]
1125         public unsafe virtual int GetByteCount (char *chars, int count)
1126         {
1127                 if (chars == null)
1128                         throw new ArgumentNullException ("chars");
1129                 if (count < 0)
1130                         throw new ArgumentOutOfRangeException ("count");
1131                 char [] c = new char [count];
1132
1133                 for (int p = 0; p < count; p++)
1134                         c [p] = chars [p];
1135
1136                 return GetByteCount (c);
1137         }
1138
1139         [CLSCompliantAttribute(false)]
1140         [ComVisible (false)]
1141         public unsafe virtual int GetCharCount (byte *bytes, int count)
1142         {
1143                 if (bytes == null)
1144                         throw new ArgumentNullException ("bytes");
1145                 if (count < 0)
1146                         throw new ArgumentOutOfRangeException ("count");
1147                 
1148                 byte [] ba = new byte [count];
1149                 for (int i = 0; i < count; i++)
1150                         ba [i] = bytes [i];
1151                 return GetCharCount (ba, 0, count);
1152         }
1153
1154         [CLSCompliantAttribute(false)]
1155         [ComVisible (false)]
1156         public unsafe virtual int GetChars (byte *bytes, int byteCount, char *chars, int charCount)
1157         {
1158                 if (bytes == null)
1159                         throw new ArgumentNullException ("bytes");
1160                 if (chars == null)
1161                         throw new ArgumentNullException ("chars");
1162                 if (charCount < 0)
1163                         throw new ArgumentOutOfRangeException ("charCount");
1164                 if (byteCount < 0)
1165                         throw new ArgumentOutOfRangeException ("byteCount");
1166                 
1167                 byte [] ba = new byte [byteCount];
1168                 for (int i = 0; i < byteCount; i++)
1169                         ba [i] = bytes [i];
1170                 char [] ret = GetChars (ba, 0, byteCount);
1171                 int top = ret.Length;
1172
1173                 if (top > charCount)
1174                         throw new ArgumentException ("charCount is less than the number of characters produced", "charCount");
1175                 
1176                 for (int i = 0; i < top; i++)
1177                         chars [i] = ret [i];
1178                 return top;
1179         }
1180
1181         [CLSCompliantAttribute(false)]
1182         [ComVisible (false)]
1183         public unsafe virtual int GetBytes (char *chars, int charCount, byte *bytes, int byteCount)
1184         {
1185                 if (bytes == null)
1186                         throw new ArgumentNullException ("bytes");
1187                 if (chars == null)
1188                         throw new ArgumentNullException ("chars");
1189                 if (charCount < 0)
1190                         throw new ArgumentOutOfRangeException ("charCount");
1191                 if (byteCount < 0)
1192                         throw new ArgumentOutOfRangeException ("byteCount");
1193                 
1194                 char [] c = new char [charCount];
1195                 
1196                 for (int i = 0; i < charCount; i++)
1197                         c [i] = chars [i];
1198
1199                 byte [] b = GetBytes (c, 0, charCount);
1200                 int top = b.Length;
1201                 if (top > byteCount)
1202                         throw new ArgumentException ("byteCount is less that the number of bytes produced", "byteCount");
1203
1204                 for (int i = 0; i < top; i++)
1205                         bytes [i] = b [i];
1206                 
1207                 return b.Length;
1208         }
1209 #endif
1210
1211 }; // class Encoding
1212
1213 }; // namespace System.Text