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