2005-11-22 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / corlib / System.Text / Latin1Encoding.cs
1 /*
2  * Latin1Encoding.cs - Implementation of the
3  *                      "System.Text.Latin1Encoding" class.
4  *
5  * Copyright (c) 2002  Southern Storm Software, Pty Ltd
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining
8  * a copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23  * OTHER DEALINGS IN THE SOFTWARE.
24  */
25
26 namespace System.Text
27 {
28
29 using System;
30
31 [Serializable]
32 internal class Latin1Encoding : Encoding
33 {
34         // Magic number used by Windows for the ISO Latin1 code page.
35         internal const int ISOLATIN_CODE_PAGE = 28591;
36
37         // Constructor.
38         public Latin1Encoding () : base (ISOLATIN_CODE_PAGE)
39         {
40                 // Nothing to do here.
41         }
42
43         // Get the number of bytes needed to encode a character buffer.
44         public override int GetByteCount (char[] chars, int index, int count)
45         {
46                 if (chars == null) {
47                         throw new ArgumentNullException ("chars");
48                 }
49                 if (index < 0 || index > chars.Length) {
50                         throw new ArgumentOutOfRangeException ("index", _("ArgRange_Array"));
51                 }
52                 if (count < 0 || count > (chars.Length - index)) {
53                         throw new ArgumentOutOfRangeException ("count", _("ArgRange_Array"));
54                 }
55                 return count;
56         }
57
58         // Convenience wrappers for "GetByteCount".
59         public override int GetByteCount (String s)
60         {
61                 if (s == null) {
62                         throw new ArgumentNullException ("s");
63                 }
64                 return s.Length;
65         }
66
67         // Get the bytes that result from encoding a character buffer.
68         public override int GetBytes (char[] chars, int charIndex, int charCount,
69                                                                  byte[] bytes, int byteIndex)
70         {
71 #if NET_2_0
72 // well, yes, I know this #if is ugly, but I think it is the simplest switch.
73                 EncoderFallbackBuffer buffer = null;
74                 char [] fallback_chars = null;
75                 return GetBytes (chars, charIndex, charCount, bytes,
76                         byteIndex, ref buffer, ref fallback_chars);
77         }
78
79         int GetBytes (char[] chars, int charIndex, int charCount,
80                       byte[] bytes, int byteIndex,
81                       ref EncoderFallbackBuffer buffer,
82                       ref char [] fallback_chars)
83         {
84 #endif
85                 if (chars == null) {
86                         throw new ArgumentNullException ("chars");
87                 }
88                 if (bytes == null) {
89                         throw new ArgumentNullException ("bytes");
90                 }
91                 if (charIndex < 0 || charIndex > chars.Length) {
92                         throw new ArgumentOutOfRangeException ("charIndex", _("ArgRange_Array"));
93                 }
94                 if (charCount < 0 || charCount > (chars.Length - charIndex)) {
95                         throw new ArgumentOutOfRangeException ("charCount", _("ArgRange_Array"));
96                 }
97                 if (byteIndex < 0 || byteIndex > bytes.Length) {
98                         throw new ArgumentOutOfRangeException ("byteIndex", _("ArgRange_Array"));
99                 }
100                 if ((bytes.Length - byteIndex) < charCount) {
101                         throw new ArgumentException (_("Arg_InsufficientSpace"));
102                 }
103                 int count = charCount;
104                 char ch;
105                 while (count-- > 0) {
106                         ch = chars [charIndex++];
107                         if (ch < (char)0x0100) {
108                                 bytes [byteIndex++] = (byte)ch;
109                         } else if (ch >= '\uFF01' && ch <= '\uFF5E') {
110                                 bytes [byteIndex++] = (byte)(ch - 0xFEE0);
111                         } else {
112 #if NET_2_0
113                                 if (buffer == null)
114                                         buffer = EncoderFallback.CreateFallbackBuffer ();
115                                 if (Char.IsSurrogate (ch) && count > 1 &&
116                                     Char.IsSurrogate (chars [charIndex]))
117                                         buffer.Fallback (ch, chars [charIndex], charIndex++ - 1);
118                                 else
119                                         buffer.Fallback (ch, charIndex - 1);
120                                 if (fallback_chars == null || fallback_chars.Length < buffer.Remaining)
121                                         fallback_chars = new char [buffer.Remaining];
122                                 for (int i = 0; i < fallback_chars.Length; i++)
123                                         fallback_chars [i] = buffer.GetNextChar ();
124                                 byteIndex += GetBytes (fallback_chars, 0, 
125                                         fallback_chars.Length, bytes, byteIndex,
126                                         ref buffer, ref fallback_chars);
127 #else
128                                 bytes [byteIndex++] = (byte)'?';
129 #endif
130                         }
131                 }
132                 return charCount;
133         }
134
135         // Convenience wrappers for "GetBytes".
136         public override int GetBytes (String s, int charIndex, int charCount,
137                                                                  byte[] bytes, int byteIndex)
138         {
139 #if NET_2_0
140 // I know this #if is ugly, but I think it is the simplest switch.
141                 EncoderFallbackBuffer buffer = null;
142                 char [] fallback_chars = null;
143                 return GetBytes (s, charIndex, charCount, bytes, byteIndex,
144                         ref buffer, ref fallback_chars);
145         }
146
147         int GetBytes (String s, int charIndex, int charCount,
148                       byte[] bytes, int byteIndex,
149                       ref EncoderFallbackBuffer buffer,
150                       ref char [] fallback_chars)
151         {
152 #endif
153                 if (s == null) {
154                         throw new ArgumentNullException ("s");
155                 }
156                 if (bytes == null) {
157                         throw new ArgumentNullException ("bytes");
158                 }
159                 if (charIndex < 0 || charIndex > s.Length) {
160                         throw new ArgumentOutOfRangeException ("charIndex", _("ArgRange_StringIndex"));
161                 }
162                 if (charCount < 0 || charCount > (s.Length - charIndex)) {
163                         throw new ArgumentOutOfRangeException ("charCount", _("ArgRange_StringRange"));
164                 }
165                 if (byteIndex < 0 || byteIndex > bytes.Length) {
166                         throw new ArgumentOutOfRangeException ("byteIndex", _("ArgRange_Array"));
167                 }
168                 if ((bytes.Length - byteIndex) < charCount) {
169                         throw new ArgumentException (_("Arg_InsufficientSpace"));
170                 }
171                 int count = charCount;
172                 char ch;
173                 while (count-- > 0) {
174                         ch = s [charIndex++];
175                         if (ch < (char)0x0100) {
176                                 bytes [byteIndex++] = (byte)ch;
177                         } else if (ch >= '\uFF01' && ch <= '\uFF5E') {
178                                 bytes [byteIndex++] = (byte)(ch - 0xFEE0);
179                         } else {
180
181 #if NET_2_0
182                                 if (buffer == null)
183                                         buffer = EncoderFallback.CreateFallbackBuffer ();
184                                 if (Char.IsSurrogate (ch) && count > 1 &&
185                                     Char.IsSurrogate (s [charIndex]))
186                                         buffer.Fallback (ch, s [charIndex], charIndex++ - 1);
187                                 else
188                                         buffer.Fallback (ch, charIndex - 1);
189                                 if (fallback_chars == null || fallback_chars.Length < buffer.Remaining)
190                                         fallback_chars = new char [buffer.Remaining];
191                                 for (int i = 0; i < fallback_chars.Length; i++)
192                                         fallback_chars [i] = buffer.GetNextChar ();
193                                 byteIndex += GetBytes (fallback_chars, 0, 
194                                         fallback_chars.Length, bytes, byteIndex,
195                                         ref buffer, ref fallback_chars);
196 #else
197                                 bytes [byteIndex++] = (byte)'?';
198 #endif
199                         }
200                 }
201                 return charCount;
202         }
203
204         // Get the number of characters needed to decode a byte buffer.
205         public override int GetCharCount (byte[] bytes, int index, int count)
206         {
207                 if (bytes == null) {
208                         throw new ArgumentNullException ("bytes");
209                 }
210                 if (index < 0 || index > bytes.Length) {
211                         throw new ArgumentOutOfRangeException ("index", _("ArgRange_Array"));
212                 }
213                 if (count < 0 || count > (bytes.Length - index)) {
214                         throw new ArgumentOutOfRangeException ("count", _("ArgRange_Array"));
215                 }
216                 return count;
217         }
218
219         // Get the characters that result from decoding a byte buffer.
220         public override int GetChars (byte[] bytes, int byteIndex, int byteCount,
221                                                                  char[] chars, int charIndex)
222         {
223                 if (bytes == null) {
224                         throw new ArgumentNullException ("bytes");
225                 }
226                 if (chars == null) {
227                         throw new ArgumentNullException ("chars");
228                 }
229                 if (byteIndex < 0 || byteIndex > bytes.Length) {
230                         throw new ArgumentOutOfRangeException ("byteIndex", _("ArgRange_Array"));
231                 }
232                 if (byteCount < 0 || byteCount > (bytes.Length - byteIndex)) {
233                         throw new ArgumentOutOfRangeException ("byteCount", _("ArgRange_Array"));
234                 }
235                 if (charIndex < 0 || charIndex > chars.Length) {
236                         throw new ArgumentOutOfRangeException ("charIndex", _("ArgRange_Array"));
237                 }
238                 if ((chars.Length - charIndex) < byteCount) {
239                         throw new ArgumentException (_("Arg_InsufficientSpace"));
240                 }
241                 int count = byteCount;
242                 while (count-- > 0) {
243                         chars [charIndex++] = (char)(bytes [byteIndex++]);
244                 }
245                 return byteCount;
246         }
247
248         // Get the maximum number of bytes needed to encode a
249         // specified number of characters.
250         public override int GetMaxByteCount (int charCount)
251         {
252                 if (charCount < 0) {
253                         throw new ArgumentOutOfRangeException ("charCount", _("ArgRange_NonNegative"));
254                 }
255                 return charCount;
256         }
257
258         // Get the maximum number of characters needed to decode a
259         // specified number of bytes.
260         public override int GetMaxCharCount (int byteCount)
261         {
262                 if (byteCount < 0) {
263                         throw new ArgumentOutOfRangeException ("byteCount", _("ArgRange_NonNegative"));
264                 }
265                 return byteCount;
266         }
267
268         // Decode a buffer of bytes into a string.
269         public override String GetString (byte[] bytes, int index, int count)
270         {
271                 if (bytes == null) {
272                         throw new ArgumentNullException ("bytes");
273                 }
274                 if (index < 0 || index > bytes.Length) {
275                         throw new ArgumentOutOfRangeException ("index", _("ArgRange_Array"));
276                 }
277                 if (count < 0 || count > (bytes.Length - index)) {
278                         throw new ArgumentOutOfRangeException ("count", _("ArgRange_Array"));
279                 }
280                 if (count == 0)
281                     return String.Empty;
282                 unsafe {
283                         fixed (byte *ss = &bytes [0]) {
284                                 return new String ((sbyte*)ss, index, count);
285                         }
286                 }
287         }
288         public override String GetString (byte[] bytes)
289         {
290                 if (bytes == null) {
291                         throw new ArgumentNullException ("bytes");
292                 }
293                 int count = bytes.Length;
294                 if (count == 0)
295                     return String.Empty;
296                 unsafe {
297                         fixed (byte *ss = &bytes [0]) {
298                                 return new String ((sbyte*)ss, 0, count);
299                         }
300                 }
301         }
302
303 #if !ECMA_COMPAT
304
305         // Get the mail body name for this encoding.
306         public override String BodyName
307         {
308                 get {
309                         return "iso-8859-1";
310                 }
311         }
312
313         // Get the human-readable name for this encoding.
314         public override String EncodingName
315         {
316                 get {
317                         return "Western European (ISO)";
318                 }
319         }
320
321         // Get the mail agent header name for this encoding.
322         public override String HeaderName
323         {
324                 get {
325                         return "iso-8859-1";
326                 }
327         }
328
329         // Determine if this encoding can be displayed in a Web browser.
330         public override bool IsBrowserDisplay
331         {
332                 get {
333                         return true;
334                 }
335         }
336
337         // Determine if this encoding can be saved from a Web browser.
338         public override bool IsBrowserSave
339         {
340                 get {
341                         return true;
342                 }
343         }
344
345         // Determine if this encoding can be displayed in a mail/news agent.
346         public override bool IsMailNewsDisplay
347         {
348                 get {
349                         return true;
350                 }
351         }
352
353         // Determine if this encoding can be saved from a mail/news agent.
354         public override bool IsMailNewsSave
355         {
356                 get {
357                         return true;
358                 }
359         }
360
361         // Get the IANA-preferred Web name for this encoding.
362         public override String WebName
363         {
364                 get {
365                         return "iso-8859-1";
366                 }
367         }
368
369 #endif // !ECMA_COMPAT
370
371 }; // class Latin1Encoding
372
373 }; // namespace System.Text