be86cc2dab6c999778a11a3ac561b44890956978
[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 #if !NET_2_1
481                         case Latin1Encoding.ISOLATIN_CODE_PAGE:
482                                 return ISOLatin1;
483 #endif
484                         default: break;
485                 }
486 #if !NET_2_1
487                 // Try to obtain a code page handler from the I18N handler.
488                 Encoding enc = (Encoding)(InvokeI18N ("GetEncoding", codepage));
489                 if (enc != null) {
490 #if NET_2_0
491                         enc.is_readonly = true;
492 #endif
493                         return enc;
494                 }
495
496                 // Build a code page class name.
497                 String cpName = "System.Text.CP" + codepage.ToString ();
498
499                 // Look for a code page converter in this assembly.
500                 Assembly assembly = Assembly.GetExecutingAssembly ();
501                 Type type = assembly.GetType (cpName);
502                 if (type != null) {
503                         enc = (Encoding)(Activator.CreateInstance (type));
504 #if NET_2_0
505                         enc.is_readonly = true;
506 #endif
507                         return enc;
508                 }
509
510                 // Look in any assembly, in case the application
511                 // has provided its own code page handler.
512                 type = Type.GetType (cpName);
513                 if (type != null) {
514                         enc = (Encoding)(Activator.CreateInstance (type));
515 #if NET_2_0
516                         enc.is_readonly = true;
517 #endif
518                         return enc;
519                 }
520 #endif // !NET_2_1
521                 // We have no idea how to handle this code page.
522                 throw new NotSupportedException
523                         (String.Format ("CodePage {0} not supported", codepage.ToString ()));
524         }
525
526 #if !ECMA_COMPAT
527
528 #if NET_2_0
529         [ComVisible (false)]
530         public virtual object Clone ()
531         {
532                 Encoding e = (Encoding) MemberwiseClone ();
533                 e.is_readonly = false;
534                 return e;
535         }
536
537 #if !NET_2_1
538
539         public static Encoding GetEncoding (int codepage,
540                 EncoderFallback encoderFallback, DecoderFallback decoderFallback)
541         {
542                 if (encoderFallback == null)
543                         throw new ArgumentNullException ("encoderFallback");
544                 if (decoderFallback == null)
545                         throw new ArgumentNullException ("decoderFallback");
546
547                 Encoding e = GetEncoding (codepage).Clone () as Encoding;
548                 e.is_readonly = false;
549                 e.encoder_fallback = encoderFallback;
550                 e.decoder_fallback = decoderFallback;
551                 return e;
552         }
553
554         public static Encoding GetEncoding (string name,
555                 EncoderFallback encoderFallback, DecoderFallback decoderFallback)
556         {
557                 if (encoderFallback == null)
558                         throw new ArgumentNullException ("encoderFallback");
559                 if (decoderFallback == null)
560                         throw new ArgumentNullException ("decoderFallback");
561
562                 Encoding e = GetEncoding (name).Clone () as Encoding;
563                 e.is_readonly = false;
564                 e.encoder_fallback = encoderFallback;
565                 e.decoder_fallback = decoderFallback;
566                 return e;
567         }
568
569 #endif // !NET_2_1
570
571         static EncodingInfo [] encoding_infos;
572
573         // FIXME: As everyone would agree, this implementation is so *hacky*
574         // and could be very easily broken. But since there is a test for
575         // this method to make sure that this method always returns
576         // the same number and content of encoding infos, this won't
577         // matter practically.
578         public static EncodingInfo[] GetEncodings ()
579         {
580                 if (encoding_infos == null) {
581                         int [] codepages = new int [] {
582                                 37, 437, 500, 708,
583                                 850, 852, 855, 857, 858, 860, 861, 862, 863, 
584                                 864, 865, 866, 869, 870, 874, 875,
585                                 932, 936, 949, 950,
586                                 1026, 1047, 1140, 1141, 1142, 1143, 1144,
587                                 1145, 1146, 1147, 1148, 1149,
588                                 1200, 1201, 1250, 1251, 1252, 1253, 1254,
589                                 1255, 1256, 1257, 1258,
590                                 10000, 10079, 12000, 12001,
591                                 20127, 20273, 20277, 20278, 20280, 20284,
592                                 20285, 20290, 20297, 20420, 20424, 20866,
593                                 20871, 21025, 21866, 28591, 28592, 28593,
594                                 28594, 28595, 28596, 28597, 28598, 28599,
595                                 28605, 38598,
596                                 50220, 50221, 50222, 51932, 51949, 54936,
597                                 57002, 57003, 57004, 57005, 57006, 57007,
598                                 57008, 57009, 57010, 57011,
599                                 65000, 65001};
600
601                         encoding_infos = new EncodingInfo [codepages.Length];
602                         for (int i = 0; i < codepages.Length; i++)
603                                 encoding_infos [i] = new EncodingInfo (codepages [i]);
604                 }
605                 return encoding_infos;
606         }
607
608 #if !NET_2_1 || MONOTOUCH
609         [ComVisible (false)]
610         public bool IsAlwaysNormalized ()
611         {
612                 return IsAlwaysNormalized (NormalizationForm.FormC);
613         }
614
615         [ComVisible (false)]
616         public virtual bool IsAlwaysNormalized (NormalizationForm form)
617         {
618                 // umm, ASCIIEncoding should have overriden this method, no?
619                 return form == NormalizationForm.FormC && this is ASCIIEncoding;
620         }
621 #endif // NET_2_1
622
623 #endif
624
625         // Table of builtin web encoding names and the corresponding code pages.
626         private static readonly object[] encodings =
627                 {
628                         ASCIIEncoding.ASCII_CODE_PAGE,
629                         "ascii", "us_ascii", "us", "ansi_x3.4_1968",
630                         "ansi_x3.4_1986", "cp367", "csascii", "ibm367",
631                         "iso_ir_6", "iso646_us", "iso_646.irv:1991",
632
633                         UTF7Encoding.UTF7_CODE_PAGE,
634                         "utf_7", "csunicode11utf7", "unicode_1_1_utf_7",
635                         "unicode_2_0_utf_7", "x_unicode_1_1_utf_7",
636                         "x_unicode_2_0_utf_7",
637
638                         UTF8Encoding.UTF8_CODE_PAGE,
639                         "utf_8", "unicode_1_1_utf_8", "unicode_2_0_utf_8",
640                         "x_unicode_1_1_utf_8", "x_unicode_2_0_utf_8",
641
642                         UnicodeEncoding.UNICODE_CODE_PAGE,
643                         "utf_16", "UTF_16LE", "ucs_2", "unicode",
644                         "iso_10646_ucs2",
645
646                         UnicodeEncoding.BIG_UNICODE_CODE_PAGE,
647                         "unicodefffe", "utf_16be",
648 #if NET_2_0
649                         UTF32Encoding.UTF32_CODE_PAGE,
650                         "utf_32", "UTF_32LE", "ucs_4",
651
652                         UTF32Encoding.BIG_UTF32_CODE_PAGE,
653                         "UTF_32BE",
654 #endif
655
656 #if !NET_2_1
657                         Latin1Encoding.ISOLATIN_CODE_PAGE,
658                         "iso_8859_1", "latin1"
659 #endif // !NET_2_1
660                 };
661
662         // Get an encoding object for a specific web encoding name.
663         public static Encoding GetEncoding (String name)
664         {
665                 // Validate the parameters.
666                 if (name == null) {
667                         throw new ArgumentNullException ("name");
668                 }
669
670                 string converted = name.ToLowerInvariant ().Replace ('-', '_');
671                 
672                 // Search the table for a name match.
673                 int code = 0;
674                 for (int i = 0; i < encodings.Length; ++i) {
675                         object o = encodings [i];
676                         
677                         if (o is int){
678                                 code = (int) o;
679                                 continue;
680                         }
681                         
682                         if (converted == ((string)encodings [i]))
683                                 return GetEncoding (code);
684                 }
685 #if !NET_2_1
686                 // Try to obtain a web encoding handler from the I18N handler.
687                 Encoding enc = (Encoding)(InvokeI18N ("GetEncoding", name));
688                 if (enc != null) {
689                         return enc;
690                 }
691
692                 // Build a web encoding class name.
693                 String encName = "System.Text.ENC" + converted;
694                                                  
695
696                 // Look for a code page converter in this assembly.
697                 Assembly assembly = Assembly.GetExecutingAssembly ();
698                 Type type = assembly.GetType (encName);
699                 if (type != null) {
700                         return (Encoding)(Activator.CreateInstance (type));
701                 }
702
703                 // Look in any assembly, in case the application
704                 // has provided its own code page handler.
705                 type = Type.GetType (encName);
706                 if (type != null) {
707                         return (Encoding)(Activator.CreateInstance (type));
708                 }
709 #endif
710                 // We have no idea how to handle this encoding name.
711                 throw new ArgumentException (String.Format ("Encoding name '{0}' not "
712                         + "supported", name), "name");
713         }
714
715 #endif // !ECMA_COMPAT
716
717         // Get a hash code for this instance.
718         public override int GetHashCode ()
719         {
720 #if NET_2_0
721                 return DecoderFallback.GetHashCode () << 24 + EncoderFallback.GetHashCode () << 16 + codePage;
722 #else
723                 return codePage;
724 #endif
725         }
726
727         // Get the maximum number of bytes needed to encode a
728         // specified number of characters.
729         public abstract int GetMaxByteCount (int charCount);
730
731         // Get the maximum number of characters needed to decode a
732         // specified number of bytes.
733         public abstract int GetMaxCharCount (int byteCount);
734
735         // Get the identifying preamble for this encoding.
736         public virtual byte[] GetPreamble ()
737         {
738                 return new byte [0];
739         }
740
741         // Decode a buffer of bytes into a string.
742         public virtual String GetString (byte[] bytes, int index, int count)
743         {
744                 return new String (GetChars(bytes, index, count));
745         }
746         public virtual String GetString (byte[] bytes)
747         {
748                 if (bytes == null)
749                         throw new ArgumentNullException ("bytes");
750
751                 return GetString (bytes, 0, bytes.Length);
752         }
753
754 #if !ECMA_COMPAT
755
756         internal string body_name;
757         internal string encoding_name;
758         internal string header_name;
759         internal bool is_mail_news_display;
760         internal bool is_mail_news_save;
761         internal bool is_browser_save = false;
762         internal bool is_browser_display = false;
763         internal string web_name;
764
765         // Get the mail body name for this encoding.
766         public virtual String BodyName
767         {
768                 get {
769                         return body_name;
770                 }
771         }
772
773         // Get the code page represented by this object.
774         public virtual int CodePage
775         {
776                 get {
777                         return codePage;
778                 }
779         }
780
781         // Get the human-readable name for this encoding.
782         public virtual String EncodingName
783         {
784                 get {
785                         return encoding_name;
786                 }
787         }
788
789         // Get the mail agent header name for this encoding.
790         public virtual String HeaderName
791         {
792                 get {
793                         return header_name;
794                 }
795         }
796
797         // Determine if this encoding can be displayed in a Web browser.
798         public virtual bool IsBrowserDisplay
799         {
800                 get {
801                         return is_browser_display;
802                 }
803         }
804
805         // Determine if this encoding can be saved from a Web browser.
806         public virtual bool IsBrowserSave
807         {
808                 get {
809                         return is_browser_save;
810                 }
811         }
812
813         // Determine if this encoding can be displayed in a mail/news agent.
814         public virtual bool IsMailNewsDisplay
815         {
816                 get {
817                         return is_mail_news_display;
818                 }
819         }
820
821         // Determine if this encoding can be saved from a mail/news agent.
822         public virtual bool IsMailNewsSave
823         {
824                 get {
825                         return is_mail_news_save;
826                 }
827         }
828
829         // Get the IANA-preferred Web name for this encoding.
830         public virtual String WebName
831         {
832                 get {
833                         return web_name;
834                 }
835         }
836
837         // Get the Windows code page represented by this object.
838         public virtual int WindowsCodePage
839         {
840                 get {
841                         // We make no distinction between normal and
842                         // Windows code pages in this implementation.
843                         return windows_code_page;
844                 }
845         }
846
847 #endif // !ECMA_COMPAT
848
849         // Storage for standard encoding objects.
850         static volatile Encoding asciiEncoding;
851         static volatile Encoding bigEndianEncoding;
852         static volatile Encoding defaultEncoding;
853         static volatile Encoding utf7Encoding;
854         static volatile Encoding utf8EncodingWithMarkers;
855         static volatile Encoding utf8EncodingWithoutMarkers;
856         static volatile Encoding unicodeEncoding;
857         static volatile Encoding isoLatin1Encoding;
858 #if NET_2_0
859         static volatile Encoding utf8EncodingUnsafe;
860         static volatile Encoding utf32Encoding;
861         static volatile Encoding bigEndianUTF32Encoding;
862 #endif
863
864         static readonly object lockobj = new object ();
865
866         // Get the standard ASCII encoding object.
867         public static Encoding ASCII
868         {
869                 get {
870                         if (asciiEncoding == null) {
871                                 lock (lockobj) {
872                                         if (asciiEncoding == null) {
873                                                 asciiEncoding = new ASCIIEncoding ();
874 //                                              asciiEncoding.is_readonly = true;
875                                         }
876                                 }
877                         }
878
879                         return asciiEncoding;
880                 }
881         }
882
883         // Get the standard big-endian Unicode encoding object.
884         public static Encoding BigEndianUnicode
885         {
886                 get {
887                         if (bigEndianEncoding == null) {
888                                 lock (lockobj) {
889                                         if (bigEndianEncoding == null) {
890                                                 bigEndianEncoding = new UnicodeEncoding (true, true);
891 //                                              bigEndianEncoding.is_readonly = true;
892                                         }
893                                 }
894                         }
895
896                         return bigEndianEncoding;
897                 }
898         }
899
900         [MethodImpl (MethodImplOptions.InternalCall)]
901         extern internal static string InternalCodePage (ref int code_page);
902         
903         // Get the default encoding object.
904         public static Encoding Default
905         {
906                 get {
907                         if (defaultEncoding == null) {
908                                 lock (lockobj) {
909                                         if (defaultEncoding == null) {
910                                                 // See if the underlying system knows what
911                                                 // code page handler we should be using.
912                                                 int code_page = 1;
913                                                 
914                                                 string code_page_name = InternalCodePage (ref code_page);
915                                                 try {
916                                                         if (code_page == -1)
917                                                                 defaultEncoding = GetEncoding (code_page_name);
918                                                         else {
919                                                                 // map the codepage from internal to our numbers
920                                                                 code_page = code_page & 0x0fffffff;
921                                                                 switch (code_page){
922                                                                 case 1: code_page = ASCIIEncoding.ASCII_CODE_PAGE; break;
923                                                                 case 2: code_page = UTF7Encoding.UTF7_CODE_PAGE; break;
924                                                                 case 3: code_page = UTF8Encoding.UTF8_CODE_PAGE; break;
925                                                                 case 4: code_page = UnicodeEncoding.UNICODE_CODE_PAGE; break;
926                                                                 case 5: code_page = UnicodeEncoding.BIG_UNICODE_CODE_PAGE; break;
927 #if !NET_2_1
928                                                                 case 6: code_page = Latin1Encoding.ISOLATIN_CODE_PAGE; break;
929 #endif
930                                                                 }
931                                                                 defaultEncoding = GetEncoding (code_page);
932                                                         }
933                                                 } catch (NotSupportedException) {
934                                                         // code_page is not supported on underlying platform
935                                                         defaultEncoding = UTF8Unmarked;
936                                                 } catch (ArgumentException) {
937                                                         // code_page_name is not a valid code page, or is 
938                                                         // not supported by underlying OS
939                                                         defaultEncoding = UTF8Unmarked;
940                                                 }
941 #if NET_2_0
942                                                 defaultEncoding.is_readonly = true;
943 #endif                                          
944                                         }
945                                 }
946                         }
947
948                         return defaultEncoding;
949                 }
950         }
951
952 #if !NET_2_1
953
954         // Get the ISO Latin1 encoding object.
955         private static Encoding ISOLatin1
956         {
957                 get {
958                         if (isoLatin1Encoding == null) {
959                                 lock (lockobj) {
960                                         if (isoLatin1Encoding == null) {
961                                                 isoLatin1Encoding = new Latin1Encoding ();
962 //                                              isoLatin1Encoding.is_readonly = true;
963                                         }
964                                 }
965                         }
966
967                         return isoLatin1Encoding;
968                 }
969         }
970
971 #endif
972
973         // Get the standard UTF-7 encoding object.
974 #if ECMA_COMPAT
975         private
976 #else
977         public
978 #endif
979         static Encoding UTF7
980         {
981                 get {
982                         if (utf7Encoding == null) {
983                                 lock (lockobj) {
984                                         if (utf7Encoding == null) {
985                                                 utf7Encoding = new UTF7Encoding ();
986 //                                              utf7Encoding.is_readonly = true;
987                                         }
988                                 }
989                         }
990
991                         return utf7Encoding;
992                 }
993         }
994
995         // Get the standard UTF-8 encoding object.
996         public static Encoding UTF8
997         {
998                 get {
999                         if (utf8EncodingWithMarkers == null) {
1000                                 lock (lockobj) {
1001                                         if (utf8EncodingWithMarkers == null) {
1002                                                 utf8EncodingWithMarkers = new UTF8Encoding (true);
1003 //                                              utf8EncodingWithMarkers.is_readonly = true;
1004                                         }
1005                                 }
1006                         }
1007
1008                         return utf8EncodingWithMarkers;
1009                 }
1010         }
1011
1012         //
1013         // Only internal, to be used by the class libraries: Unmarked and non-input-validating
1014         //
1015         internal static Encoding UTF8Unmarked {
1016                 get {
1017                         if (utf8EncodingWithoutMarkers == null) {
1018                                 lock (lockobj){
1019                                         if (utf8EncodingWithoutMarkers == null){
1020                                                 utf8EncodingWithoutMarkers = new UTF8Encoding (false, false);
1021 //                                              utf8EncodingWithoutMarkers.is_readonly = true;
1022                                         }
1023                                 }
1024                         }
1025
1026                         return utf8EncodingWithoutMarkers;
1027                 }
1028         }
1029         
1030         //
1031         // Only internal, to be used by the class libraries: Unmarked and non-input-validating
1032         //
1033         internal static Encoding UTF8UnmarkedUnsafe {
1034                 get {
1035 #if NET_2_0
1036                         if (utf8EncodingUnsafe == null) {
1037                                 lock (lockobj){
1038                                         if (utf8EncodingUnsafe == null){
1039                                                 utf8EncodingUnsafe = new UTF8Encoding (false, false);
1040                                                 utf8EncodingUnsafe.is_readonly = false;
1041                                                 utf8EncodingUnsafe.DecoderFallback = new DecoderReplacementFallback (String.Empty);
1042                                                 utf8EncodingUnsafe.is_readonly = true;
1043                                         }
1044                                 }
1045                         }
1046
1047                         return utf8EncodingUnsafe;
1048 #else
1049                         return UTF8Unmarked;
1050 #endif
1051                 }
1052         }
1053         
1054         // Get the standard little-endian Unicode encoding object.
1055         public static Encoding Unicode
1056         {
1057                 get {
1058                         if (unicodeEncoding == null) {
1059                                 lock (lockobj) {
1060                                         if (unicodeEncoding == null) {
1061                                                 unicodeEncoding = new UnicodeEncoding (false, true);
1062 //                                              unicodeEncoding.is_readonly = true;
1063                                         }
1064                                 }
1065                         }
1066
1067                         return unicodeEncoding;
1068                 }
1069         }
1070
1071 #if NET_2_0
1072         // Get the standard little-endian UTF-32 encoding object.
1073         public static Encoding UTF32
1074         {
1075                 get {
1076                         if (utf32Encoding == null) {
1077                                 lock (lockobj) {
1078                                         if (utf32Encoding == null) {
1079                                                 utf32Encoding = new UTF32Encoding (false, true);
1080 //                                              utf32Encoding.is_readonly = true;
1081                                         }
1082                                 }
1083                         }
1084
1085                         return utf32Encoding;
1086                 }
1087         }
1088
1089         // Get the standard big-endian UTF-32 encoding object.
1090         internal static Encoding BigEndianUTF32
1091         {
1092                 get {
1093                         if (bigEndianUTF32Encoding == null) {
1094                                 lock (lockobj) {
1095                                         if (bigEndianUTF32Encoding == null) {
1096                                                 bigEndianUTF32Encoding = new UTF32Encoding (true, true);
1097 //                                              bigEndianUTF32Encoding.is_readonly = true;
1098                                         }
1099                                 }
1100                         }
1101
1102                         return bigEndianUTF32Encoding;
1103                 }
1104         }
1105 #endif
1106
1107         // Forwarding decoder implementation.
1108         private sealed class ForwardingDecoder : Decoder
1109         {
1110                 private Encoding encoding;
1111
1112                 // Constructor.
1113                 public ForwardingDecoder (Encoding enc)
1114                 {
1115                         encoding = enc;
1116 #if NET_2_0
1117                         DecoderFallback fallback = encoding.DecoderFallback;
1118                         if (fallback != null)
1119                                 Fallback = fallback;
1120 #endif
1121                 }
1122
1123                 // Override inherited methods.
1124                 public override int GetCharCount (byte[] bytes, int index, int count)
1125                 {
1126                         return encoding.GetCharCount (bytes, index, count);
1127                 }
1128                 public override int GetChars (byte[] bytes, int byteIndex,
1129                                                                          int byteCount, char[] chars,
1130                                                                          int charIndex)
1131                 {
1132                         return encoding.GetChars (bytes, byteIndex, byteCount, chars, charIndex);
1133                 }
1134
1135         } // class ForwardingDecoder
1136
1137         // Forwarding encoder implementation.
1138         private sealed class ForwardingEncoder : Encoder
1139         {
1140                 private Encoding encoding;
1141
1142                 // Constructor.
1143                 public ForwardingEncoder (Encoding enc)
1144                 {
1145                         encoding = enc;
1146 #if NET_2_0
1147                         EncoderFallback fallback = encoding.EncoderFallback;
1148                         if (fallback != null)
1149                                 Fallback = fallback;
1150 #endif
1151                 }
1152
1153                 // Override inherited methods.
1154                 public override int GetByteCount (char[] chars, int index, int count, bool flush)
1155                 {
1156                         return encoding.GetByteCount (chars, index, count);
1157                 }
1158                 public override int GetBytes (char[] chars, int charIndex,
1159                                                                          int charCount, byte[] bytes,
1160                                                                          int byteCount, bool flush)
1161                 {
1162                         return encoding.GetBytes (chars, charIndex, charCount, bytes, byteCount);
1163                 }
1164
1165         } // class ForwardingEncoder
1166
1167 #if NET_2_0
1168         [CLSCompliantAttribute(false)]
1169         [ComVisible (false)]
1170         public unsafe virtual int GetByteCount (char *chars, int count)
1171         {
1172                 if (chars == null)
1173                         throw new ArgumentNullException ("chars");
1174                 if (count < 0)
1175                         throw new ArgumentOutOfRangeException ("count");
1176                 char [] c = new char [count];
1177
1178                 for (int p = 0; p < count; p++)
1179                         c [p] = chars [p];
1180
1181                 return GetByteCount (c);
1182         }
1183
1184         [CLSCompliantAttribute(false)]
1185         [ComVisible (false)]
1186         public unsafe virtual int GetCharCount (byte *bytes, int count)
1187         {
1188                 if (bytes == null)
1189                         throw new ArgumentNullException ("bytes");
1190                 if (count < 0)
1191                         throw new ArgumentOutOfRangeException ("count");
1192                 
1193                 byte [] ba = new byte [count];
1194                 for (int i = 0; i < count; i++)
1195                         ba [i] = bytes [i];
1196                 return GetCharCount (ba, 0, count);
1197         }
1198
1199         [CLSCompliantAttribute(false)]
1200         [ComVisible (false)]
1201         public unsafe virtual int GetChars (byte *bytes, int byteCount, char *chars, int charCount)
1202         {
1203                 if (bytes == null)
1204                         throw new ArgumentNullException ("bytes");
1205                 if (chars == null)
1206                         throw new ArgumentNullException ("chars");
1207                 if (charCount < 0)
1208                         throw new ArgumentOutOfRangeException ("charCount");
1209                 if (byteCount < 0)
1210                         throw new ArgumentOutOfRangeException ("byteCount");
1211                 
1212                 byte [] ba = new byte [byteCount];
1213                 for (int i = 0; i < byteCount; i++)
1214                         ba [i] = bytes [i];
1215                 char [] ret = GetChars (ba, 0, byteCount);
1216                 int top = ret.Length;
1217
1218                 if (top > charCount)
1219                         throw new ArgumentException ("charCount is less than the number of characters produced", "charCount");
1220                 
1221                 for (int i = 0; i < top; i++)
1222                         chars [i] = ret [i];
1223                 return top;
1224         }
1225
1226         [CLSCompliantAttribute(false)]
1227         [ComVisible (false)]
1228         public unsafe virtual int GetBytes (char *chars, int charCount, byte *bytes, int byteCount)
1229         {
1230                 if (bytes == null)
1231                         throw new ArgumentNullException ("bytes");
1232                 if (chars == null)
1233                         throw new ArgumentNullException ("chars");
1234                 if (charCount < 0)
1235                         throw new ArgumentOutOfRangeException ("charCount");
1236                 if (byteCount < 0)
1237                         throw new ArgumentOutOfRangeException ("byteCount");
1238                 
1239                 char [] c = new char [charCount];
1240                 
1241                 for (int i = 0; i < charCount; i++)
1242                         c [i] = chars [i];
1243
1244                 byte [] b = GetBytes (c, 0, charCount);
1245                 int top = b.Length;
1246                 if (top > byteCount)
1247                         throw new ArgumentException ("byteCount is less that the number of bytes produced", "byteCount");
1248
1249                 for (int i = 0; i < top; i++)
1250                         bytes [i] = b [i];
1251                 
1252                 return b.Length;
1253         }
1254 #endif
1255
1256 }; // class Encoding
1257
1258 }; // namespace System.Text