New test.
[mono.git] / mcs / class / corlib / System.Text / ASCIIEncoding.cs
1 /*
2  * ASCIIEncoding.cs - Implementation of the "System.Text.ASCIIEncoding" class.
3  *
4  * Copyright (c) 2001  Southern Storm Software, Pty Ltd
5  * Copyright (C) 2003 Novell, Inc.
6  * Copyright (C) 2004 Novell, Inc (http://www.novell.com)
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.Runtime.InteropServices;
32
33 [Serializable]
34 #if NET_2_0
35 [ComVisible (true)]
36 #endif
37 [MonoTODO ("Serialization format not compatible with .NET")]
38 public class ASCIIEncoding : Encoding
39 {
40         // Magic number used by Windows for "ASCII".
41         internal const int ASCII_CODE_PAGE = 20127;
42
43         // Constructor.
44         public ASCIIEncoding () : base(ASCII_CODE_PAGE) {
45                 body_name = header_name = web_name= "us-ascii";
46                 encoding_name = "US-ASCII";
47                 is_mail_news_display = true;
48                 is_mail_news_save = true;
49         }
50
51 #if NET_2_0
52         [ComVisible (false)]
53         public override bool IsSingleByte {
54                 get { return true; }
55         }
56 #endif
57
58         // Get the number of bytes needed to encode a character buffer.
59         public override int GetByteCount (char[] chars, int index, int count)
60         {
61                 if (chars == null) {
62                         throw new ArgumentNullException ("chars");
63                 }
64                 if (index < 0 || index > chars.Length) {
65                         throw new ArgumentOutOfRangeException ("index", _("ArgRange_Array"));
66                 }
67                 if (count < 0 || count > (chars.Length - index)) {
68                         throw new ArgumentOutOfRangeException ("count", _("ArgRange_Array"));
69                 }
70                 return count;
71         }
72
73         // Convenience wrappers for "GetByteCount".
74         public override int GetByteCount (String s)
75         {
76                 if (s == null) {
77                         throw new ArgumentNullException ("s");
78                 }
79                 return s.Length;
80         }
81
82         // Get the bytes that result from encoding a character buffer.
83         public override int GetBytes (char[] chars, int charIndex, int charCount,
84                                                                  byte[] bytes, int byteIndex)
85         {
86 #if NET_2_0
87 // well, yes, I know this #if is ugly, but I think it is the simplest switch.
88                 EncoderFallbackBuffer buffer = null;
89                 char [] fallback_chars = null;
90                 return GetBytes (chars, charIndex, charCount, bytes,
91                         byteIndex, ref buffer, ref fallback_chars);
92         }
93
94         int GetBytes (char[] chars, int charIndex, int charCount,
95                       byte[] bytes, int byteIndex,
96                       ref EncoderFallbackBuffer buffer,
97                       ref char [] fallback_chars)
98         {
99 #endif
100                 if (chars == null) {
101                         throw new ArgumentNullException ("chars");
102                 }
103                 if (bytes == null) {
104                         throw new ArgumentNullException ("bytes");
105                 }
106                 if (charIndex < 0 || charIndex > chars.Length) {
107                         throw new ArgumentOutOfRangeException ("charIndex", _("ArgRange_Array"));
108                 }
109                 if (charCount < 0 || charCount > (chars.Length - charIndex)) {
110                         throw new ArgumentOutOfRangeException ("charCount", _("ArgRange_Array"));
111                 }
112                 if (byteIndex < 0 || byteIndex > bytes.Length) {
113                         throw new ArgumentOutOfRangeException ("byteIndex", _("ArgRange_Array"));
114                 }
115                 if ((bytes.Length - byteIndex) < charCount) {
116                         throw new ArgumentException (_("Arg_InsufficientSpace"));
117                 }
118                 int count = charCount;
119                 char ch;
120                 while (count-- > 0) {
121                         ch = chars [charIndex++];
122                         if (ch < (char)0x80) {
123                                 bytes [byteIndex++] = (byte)ch;
124                         } else {
125 #if NET_2_0
126                                 if (buffer == null)
127                                         buffer = EncoderFallback.CreateFallbackBuffer ();
128                                 if (Char.IsSurrogate (ch) && count > 1 &&
129                                     Char.IsSurrogate (chars [charIndex]))
130                                         buffer.Fallback (ch, chars [charIndex], charIndex++ - 1);
131                                 else
132                                         buffer.Fallback (ch, charIndex - 1);
133                                 if (fallback_chars == null || fallback_chars.Length < buffer.Remaining)
134                                         fallback_chars = new char [buffer.Remaining];
135                                 for (int i = 0; i < fallback_chars.Length; i++)
136                                         fallback_chars [i] = buffer.GetNextChar ();
137                                 byteIndex += GetBytes (fallback_chars, 0, 
138                                         fallback_chars.Length, bytes, byteIndex,
139                                         ref buffer, ref fallback_chars);
140 #else
141                                 bytes [byteIndex++] = (byte)'?';
142 #endif
143                         }
144                 }
145                 return charCount;
146         }
147
148         // Convenience wrappers for "GetBytes".
149         public override int GetBytes (String s, int charIndex, int charCount, byte[] bytes, int byteIndex)
150         {
151 #if NET_2_0
152 // I know this #if is ugly, but I think it is the simplest switch.
153                 EncoderFallbackBuffer buffer = null;
154                 char [] fallback_chars = null;
155                 return GetBytes (s, charIndex, charCount, bytes, byteIndex,
156                         ref buffer, ref fallback_chars);
157         }
158
159         int GetBytes (String s, int charIndex, int charCount,
160                       byte[] bytes, int byteIndex,
161                       ref EncoderFallbackBuffer buffer,
162                       ref char [] fallback_chars)
163         {
164 #endif
165                 if (s == null) {
166                         throw new ArgumentNullException ("s");
167                 }
168                 if (bytes == null) {
169                         throw new ArgumentNullException ("bytes");
170                 }
171                 if (charIndex < 0 || charIndex > s.Length) {
172                         throw new ArgumentOutOfRangeException ("charIndex", _("ArgRange_StringIndex"));
173                 }
174                 if (charCount < 0 || charCount > (s.Length - charIndex)) {
175                         throw new ArgumentOutOfRangeException ("charCount", _("ArgRange_StringRange"));
176                 }
177                 if (byteIndex < 0 || byteIndex > bytes.Length) {
178                         throw new ArgumentOutOfRangeException ("byteIndex", _("ArgRange_Array"));
179                 }
180                 if ((bytes.Length - byteIndex) < charCount) {
181                         throw new ArgumentException (_("Arg_InsufficientSpace"));
182                 }
183                 int count = charCount;
184                 char ch;
185                 while (count-- > 0) {
186                         ch = s [charIndex++];
187                         if (ch < (char)0x80) {
188                                 bytes [byteIndex++] = (byte)ch;
189                         } else {
190 #if NET_2_0
191                                 if (buffer == null)
192                                         buffer = EncoderFallback.CreateFallbackBuffer ();
193                                 if (Char.IsSurrogate (ch) && count > 1 &&
194                                     Char.IsSurrogate (s [charIndex]))
195                                         buffer.Fallback (ch, s [charIndex], charIndex++ - 1);
196                                 else
197                                         buffer.Fallback (ch, charIndex - 1);
198                                 if (fallback_chars == null || fallback_chars.Length < buffer.Remaining)
199                                         fallback_chars = new char [buffer.Remaining];
200                                 for (int i = 0; i < fallback_chars.Length; i++)
201                                         fallback_chars [i] = buffer.GetNextChar ();
202                                 byteIndex += GetBytes (fallback_chars, 0, 
203                                         fallback_chars.Length, bytes, byteIndex,
204                                         ref buffer, ref fallback_chars);
205 #else
206                                 bytes [byteIndex++] = (byte)'?';
207 #endif
208                         }
209                 }
210                 return charCount;
211         }
212
213         // Get the number of characters needed to decode a byte buffer.
214         public override int GetCharCount (byte[] bytes, int index, int count)
215         {
216                 if (bytes == null) {
217                         throw new ArgumentNullException ("bytes");
218                 }
219                 if (index < 0 || index > bytes.Length) {
220                         throw new ArgumentOutOfRangeException ("index", _("ArgRange_Array"));
221                 }
222                 if (count < 0 || count > (bytes.Length - index)) {
223                         throw new ArgumentOutOfRangeException ("count", _("ArgRange_Array"));
224                 }
225                 return count;
226         }
227
228         // Get the characters that result from decoding a byte buffer.
229         public override int GetChars (byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
230         {
231 #if NET_2_0
232 // well, yes, I know this #if is ugly, but I think it is the simplest switch.
233                 DecoderFallbackBuffer buffer = null;
234                 return GetChars (bytes, byteIndex, byteCount, chars,
235                         charIndex, ref buffer);
236         }
237
238         int GetChars (byte[] bytes, int byteIndex, int byteCount,
239                       char[] chars, int charIndex,
240                       ref DecoderFallbackBuffer buffer)
241         {
242 #endif
243                 if (bytes == null)
244                         throw new ArgumentNullException ("bytes");
245                 if (chars == null) 
246                         throw new ArgumentNullException ("chars");
247                 if (byteIndex < 0 || byteIndex > bytes.Length) 
248                         throw new ArgumentOutOfRangeException ("byteIndex", _("ArgRange_Array"));
249                 if (byteCount < 0 || byteCount > (bytes.Length - byteIndex)) 
250                         throw new ArgumentOutOfRangeException ("byteCount", _("ArgRange_Array"));
251                 if (charIndex < 0 || charIndex > chars.Length) 
252                         throw new ArgumentOutOfRangeException ("charIndex", _("ArgRange_Array"));
253
254                 if ((chars.Length - charIndex) < byteCount) 
255                         throw new ArgumentException (_("Arg_InsufficientSpace"));
256
257                 int count = byteCount;
258                 while (count-- > 0) {
259                         char c = (char) bytes [byteIndex++];
260                         if (c < '\x80')
261                                 chars [charIndex++] = c;
262                         else {
263 #if NET_2_0
264                                 if (buffer == null)
265                                         buffer = DecoderFallback.CreateFallbackBuffer ();
266                                 buffer.Fallback (bytes, byteIndex);
267                                 while (buffer.Remaining > 0)
268                                         chars [charIndex++] = buffer.GetNextChar ();
269 #else
270                                 chars [charIndex++] = '?';
271 #endif
272                         }
273                 }
274                 return byteCount;
275         }
276
277         // Get the maximum number of bytes needed to encode a
278         // specified number of characters.
279         public override int GetMaxByteCount (int charCount)
280         {
281                 if (charCount < 0) {
282                         throw new ArgumentOutOfRangeException ("charCount", _("ArgRange_NonNegative"));
283                 }
284                 return charCount;
285         }
286
287         // Get the maximum number of characters needed to decode a
288         // specified number of bytes.
289         public override int GetMaxCharCount (int byteCount)
290         {
291                 if (byteCount < 0) {
292                         throw new ArgumentOutOfRangeException ("byteCount", _("ArgRange_NonNegative"));
293                 }
294                 return byteCount;
295         }
296
297         // Decode a buffer of bytes into a string.
298         public override String GetString (byte[] bytes, int index, int count)
299         {
300                 if (bytes == null) {
301                         throw new ArgumentNullException ("bytes");
302                 }
303                 if (index < 0 || index > bytes.Length) {
304                         throw new ArgumentOutOfRangeException ("index", _("ArgRange_Array"));
305                 }
306                 if (count < 0 || count > (bytes.Length - index)) {
307                         throw new ArgumentOutOfRangeException ("count", _("ArgRange_Array"));
308                 }
309                 if (count == 0)
310                         return String.Empty;
311                 
312                 unsafe {
313                         fixed (byte* bytePtr = bytes) {
314                                 string s = string.InternalAllocateStr (count);
315
316                                 fixed (char* charPtr = s) {
317                                         byte* currByte = bytePtr + index;
318                                         byte* lastByte = currByte + count;
319                                         char* currChar = charPtr;
320
321                                         while (currByte < lastByte) {
322 #if NET_2_0
323                                                 byte b = currByte++ [0];
324                                                 currChar++ [0] = b <= 0x7F ? (char) b : (char) '?';
325 #else
326                                                 // GetString is incompatible with GetChars
327                                                 currChar++ [0] = (char) (currByte++ [0] & 0x7F);
328 #endif
329                                         }
330                                 }
331
332                                 return s;
333                         }
334                 }
335         }
336
337 #if NET_2_0
338         [CLSCompliantAttribute (false)]
339         [ComVisible (false)]
340         public unsafe override int GetBytes (char *chars, int charCount, byte *bytes, int byteCount)
341         {
342                 if (chars == null)
343                         throw new ArgumentNullException ("chars");
344                 if (bytes == null)
345                         throw new ArgumentNullException ("bytes");
346                 if (charCount < 0)
347                         throw new ArgumentOutOfRangeException ("charCount");
348                 if (byteCount < 0)
349                         throw new ArgumentOutOfRangeException ("byteCount");
350
351                 if (byteCount < charCount)
352                         throw new ArgumentException ("bytecount is less than the number of bytes required", "byteCount");
353
354                 for (int i = 0; i < charCount; i++){
355                         char c = chars [i];
356                         bytes [i] = (byte) ((c < (char) 0x80) ? c : '?');
357                 }
358                 return charCount;
359         }
360
361         [CLSCompliantAttribute(false)]
362         [ComVisible (false)]
363         public unsafe override int GetChars (byte *bytes, int byteCount, char *chars, int charCount)
364         {
365                 if (bytes == null)
366                         throw new ArgumentNullException ("bytes");
367                 if (chars == null) 
368                         throw new ArgumentNullException ("chars");
369                 if (charCount < 0)
370                         throw new ArgumentOutOfRangeException ("charCount");
371                 if (byteCount < 0)
372                         throw new ArgumentOutOfRangeException ("byteCount");
373                 if (charCount < byteCount)
374                         throw new ArgumentException ("charcount is less than the number of bytes required", "charCount");
375
376                 for (int i = 0; i < byteCount; i++){
377                         byte b = bytes [i];
378                         chars [i] = b > 127 ? '?' : (char) b;
379                 }
380                 return byteCount;
381                 
382         }
383
384         [CLSCompliantAttribute(false)]
385         [ComVisible (false)]
386         public unsafe override int GetCharCount (byte *bytes, int count)
387         {
388                 return count;
389         }
390
391         [CLSCompliantAttribute(false)]
392         [ComVisible (false)]
393         public unsafe override int GetByteCount (char *chars, int count)
394         {
395                 return count;
396         }
397 #else
398         // This routine is gone in 2.x
399         public override String GetString (byte[] bytes)
400         {
401                 if (bytes == null) {
402                         throw new ArgumentNullException ("bytes");
403                 }
404
405                 return GetString (bytes, 0, bytes.Length);
406         }
407 #endif
408
409 #if NET_2_0
410         [MonoTODO ("we have simple override to match method signature.")]
411         [ComVisible (false)]
412         public override Decoder GetDecoder ()
413         {
414                 return base.GetDecoder ();
415         }
416
417         [MonoTODO ("we have simple override to match method signature.")]
418         [ComVisible (false)]
419         public override Encoder GetEncoder ()
420         {
421                 return base.GetEncoder ();
422         }
423 #endif
424 }; // class ASCIIEncoding
425
426 }; // namespace System.Text