New test.
[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 #if NET_2_0
44         public override bool IsSingleByte {
45                 get { return true; }
46         }
47
48         public override bool IsAlwaysNormalized (NormalizationForm form)
49         {
50                 return form == NormalizationForm.FormC;
51         }
52 #endif
53
54         // Get the number of bytes needed to encode a character buffer.
55         public override int GetByteCount (char[] chars, int index, int count)
56         {
57                 if (chars == null) {
58                         throw new ArgumentNullException ("chars");
59                 }
60                 if (index < 0 || index > chars.Length) {
61                         throw new ArgumentOutOfRangeException ("index", _("ArgRange_Array"));
62                 }
63                 if (count < 0 || count > (chars.Length - index)) {
64                         throw new ArgumentOutOfRangeException ("count", _("ArgRange_Array"));
65                 }
66                 return count;
67         }
68
69         // Convenience wrappers for "GetByteCount".
70         public override int GetByteCount (String s)
71         {
72                 if (s == null) {
73                         throw new ArgumentNullException ("s");
74                 }
75                 return s.Length;
76         }
77
78         // Get the bytes that result from encoding a character buffer.
79         public override int GetBytes (char[] chars, int charIndex, int charCount,
80                                                                  byte[] bytes, int byteIndex)
81         {
82 #if NET_2_0
83 // well, yes, I know this #if is ugly, but I think it is the simplest switch.
84                 EncoderFallbackBuffer buffer = null;
85                 char [] fallback_chars = null;
86                 return GetBytes (chars, charIndex, charCount, bytes,
87                         byteIndex, ref buffer, ref fallback_chars);
88         }
89
90         int GetBytes (char[] chars, int charIndex, int charCount,
91                       byte[] bytes, int byteIndex,
92                       ref EncoderFallbackBuffer buffer,
93                       ref char [] fallback_chars)
94         {
95 #endif
96                 if (chars == null) {
97                         throw new ArgumentNullException ("chars");
98                 }
99                 if (bytes == null) {
100                         throw new ArgumentNullException ("bytes");
101                 }
102                 if (charIndex < 0 || charIndex > chars.Length) {
103                         throw new ArgumentOutOfRangeException ("charIndex", _("ArgRange_Array"));
104                 }
105                 if (charCount < 0 || charCount > (chars.Length - charIndex)) {
106                         throw new ArgumentOutOfRangeException ("charCount", _("ArgRange_Array"));
107                 }
108                 if (byteIndex < 0 || byteIndex > bytes.Length) {
109                         throw new ArgumentOutOfRangeException ("byteIndex", _("ArgRange_Array"));
110                 }
111                 if ((bytes.Length - byteIndex) < charCount) {
112                         throw new ArgumentException (_("Arg_InsufficientSpace"));
113                 }
114                 int count = charCount;
115                 char ch;
116                 while (count-- > 0) {
117                         ch = chars [charIndex++];
118                         if (ch < (char)0x0100) {
119                                 bytes [byteIndex++] = (byte)ch;
120                         } else if (ch >= '\uFF01' && ch <= '\uFF5E') {
121                                 bytes [byteIndex++] = (byte)(ch - 0xFEE0);
122                         } else {
123 #if NET_2_0
124                                 if (buffer == null)
125                                         buffer = EncoderFallback.CreateFallbackBuffer ();
126                                 if (Char.IsSurrogate (ch) && count > 1 &&
127                                     Char.IsSurrogate (chars [charIndex]))
128                                         buffer.Fallback (ch, chars [charIndex], charIndex++ - 1);
129                                 else
130                                         buffer.Fallback (ch, charIndex - 1);
131                                 if (fallback_chars == null || fallback_chars.Length < buffer.Remaining)
132                                         fallback_chars = new char [buffer.Remaining];
133                                 for (int i = 0; i < fallback_chars.Length; i++)
134                                         fallback_chars [i] = buffer.GetNextChar ();
135                                 byteIndex += GetBytes (fallback_chars, 0, 
136                                         fallback_chars.Length, bytes, byteIndex,
137                                         ref buffer, ref fallback_chars);
138 #else
139                                 bytes [byteIndex++] = (byte)'?';
140 #endif
141                         }
142                 }
143                 return charCount;
144         }
145
146         // Convenience wrappers for "GetBytes".
147         public override int GetBytes (String s, int charIndex, int charCount,
148                                                                  byte[] bytes, int byteIndex)
149         {
150 #if NET_2_0
151 // I know this #if is ugly, but I think it is the simplest switch.
152                 EncoderFallbackBuffer buffer = null;
153                 char [] fallback_chars = null;
154                 return GetBytes (s, charIndex, charCount, bytes, byteIndex,
155                         ref buffer, ref fallback_chars);
156         }
157
158         int GetBytes (String s, int charIndex, int charCount,
159                       byte[] bytes, int byteIndex,
160                       ref EncoderFallbackBuffer buffer,
161                       ref char [] fallback_chars)
162         {
163 #endif
164                 if (s == null) {
165                         throw new ArgumentNullException ("s");
166                 }
167                 if (bytes == null) {
168                         throw new ArgumentNullException ("bytes");
169                 }
170                 if (charIndex < 0 || charIndex > s.Length) {
171                         throw new ArgumentOutOfRangeException ("charIndex", _("ArgRange_StringIndex"));
172                 }
173                 if (charCount < 0 || charCount > (s.Length - charIndex)) {
174                         throw new ArgumentOutOfRangeException ("charCount", _("ArgRange_StringRange"));
175                 }
176                 if (byteIndex < 0 || byteIndex > bytes.Length) {
177                         throw new ArgumentOutOfRangeException ("byteIndex", _("ArgRange_Array"));
178                 }
179                 if ((bytes.Length - byteIndex) < charCount) {
180                         throw new ArgumentException (_("Arg_InsufficientSpace"));
181                 }
182                 int count = charCount;
183                 char ch;
184                 while (count-- > 0) {
185                         ch = s [charIndex++];
186                         if (ch < (char)0x0100) {
187                                 bytes [byteIndex++] = (byte)ch;
188                         } else if (ch >= '\uFF01' && ch <= '\uFF5E') {
189                                 bytes [byteIndex++] = (byte)(ch - 0xFEE0);
190                         } else {
191
192 #if NET_2_0
193                                 if (buffer == null)
194                                         buffer = EncoderFallback.CreateFallbackBuffer ();
195                                 if (Char.IsSurrogate (ch) && count > 1 &&
196                                     Char.IsSurrogate (s [charIndex]))
197                                         buffer.Fallback (ch, s [charIndex], charIndex++ - 1);
198                                 else
199                                         buffer.Fallback (ch, charIndex - 1);
200                                 if (fallback_chars == null || fallback_chars.Length < buffer.Remaining)
201                                         fallback_chars = new char [buffer.Remaining];
202                                 for (int i = 0; i < fallback_chars.Length; i++)
203                                         fallback_chars [i] = buffer.GetNextChar ();
204                                 byteIndex += GetBytes (fallback_chars, 0, 
205                                         fallback_chars.Length, bytes, byteIndex,
206                                         ref buffer, ref fallback_chars);
207 #else
208                                 bytes [byteIndex++] = (byte)'?';
209 #endif
210                         }
211                 }
212                 return charCount;
213         }
214
215         // Get the number of characters needed to decode a byte buffer.
216         public override int GetCharCount (byte[] bytes, int index, int count)
217         {
218                 if (bytes == null) {
219                         throw new ArgumentNullException ("bytes");
220                 }
221                 if (index < 0 || index > bytes.Length) {
222                         throw new ArgumentOutOfRangeException ("index", _("ArgRange_Array"));
223                 }
224                 if (count < 0 || count > (bytes.Length - index)) {
225                         throw new ArgumentOutOfRangeException ("count", _("ArgRange_Array"));
226                 }
227                 return count;
228         }
229
230         // Get the characters that result from decoding a byte buffer.
231         public override int GetChars (byte[] bytes, int byteIndex, int byteCount,
232                                                                  char[] chars, int charIndex)
233         {
234                 if (bytes == null) {
235                         throw new ArgumentNullException ("bytes");
236                 }
237                 if (chars == null) {
238                         throw new ArgumentNullException ("chars");
239                 }
240                 if (byteIndex < 0 || byteIndex > bytes.Length) {
241                         throw new ArgumentOutOfRangeException ("byteIndex", _("ArgRange_Array"));
242                 }
243                 if (byteCount < 0 || byteCount > (bytes.Length - byteIndex)) {
244                         throw new ArgumentOutOfRangeException ("byteCount", _("ArgRange_Array"));
245                 }
246                 if (charIndex < 0 || charIndex > chars.Length) {
247                         throw new ArgumentOutOfRangeException ("charIndex", _("ArgRange_Array"));
248                 }
249                 if ((chars.Length - charIndex) < byteCount) {
250                         throw new ArgumentException (_("Arg_InsufficientSpace"));
251                 }
252                 int count = byteCount;
253                 while (count-- > 0) {
254                         chars [charIndex++] = (char)(bytes [byteIndex++]);
255                 }
256                 return byteCount;
257         }
258
259         // Get the maximum number of bytes needed to encode a
260         // specified number of characters.
261         public override int GetMaxByteCount (int charCount)
262         {
263                 if (charCount < 0) {
264                         throw new ArgumentOutOfRangeException ("charCount", _("ArgRange_NonNegative"));
265                 }
266                 return charCount;
267         }
268
269         // Get the maximum number of characters needed to decode a
270         // specified number of bytes.
271         public override int GetMaxCharCount (int byteCount)
272         {
273                 if (byteCount < 0) {
274                         throw new ArgumentOutOfRangeException ("byteCount", _("ArgRange_NonNegative"));
275                 }
276                 return byteCount;
277         }
278
279         // Decode a buffer of bytes into a string.
280         public override String GetString (byte[] bytes, int index, int count)
281         {
282                 if (bytes == null) {
283                         throw new ArgumentNullException ("bytes");
284                 }
285                 if (index < 0 || index > bytes.Length) {
286                         throw new ArgumentOutOfRangeException ("index", _("ArgRange_Array"));
287                 }
288                 if (count < 0 || count > (bytes.Length - index)) {
289                         throw new ArgumentOutOfRangeException ("count", _("ArgRange_Array"));
290                 }
291                 if (count == 0)
292                     return String.Empty;
293                 unsafe {
294                         fixed (byte* bytePtr = bytes) {
295                                 string s = string.InternalAllocateStr (count);
296
297                                 fixed (char* charPtr = s) {
298                                         byte* currByte = bytePtr + index;
299                                         byte* lastByte = currByte + count;
300                                         char* currChar = charPtr;
301
302                                         while (currByte < lastByte)
303                                                 currChar++ [0] = (char) currByte++ [0];
304                                 }
305
306                                 return s;
307                         }
308                 }
309         }
310         public override String GetString (byte[] bytes)
311         {
312                 if (bytes == null) {
313                         throw new ArgumentNullException ("bytes");
314                 }
315
316                 return GetString (bytes, 0, bytes.Length);
317         }
318
319 #if !ECMA_COMPAT
320
321         // Get the mail body name for this encoding.
322         public override String BodyName
323         {
324                 get {
325                         return "iso-8859-1";
326                 }
327         }
328
329         // Get the human-readable name for this encoding.
330         public override String EncodingName
331         {
332                 get {
333                         return "Western European (ISO)";
334                 }
335         }
336
337         // Get the mail agent header name for this encoding.
338         public override String HeaderName
339         {
340                 get {
341                         return "iso-8859-1";
342                 }
343         }
344
345         // Determine if this encoding can be displayed in a Web browser.
346         public override bool IsBrowserDisplay
347         {
348                 get {
349                         return true;
350                 }
351         }
352
353         // Determine if this encoding can be saved from a Web browser.
354         public override bool IsBrowserSave
355         {
356                 get {
357                         return true;
358                 }
359         }
360
361         // Determine if this encoding can be displayed in a mail/news agent.
362         public override bool IsMailNewsDisplay
363         {
364                 get {
365                         return true;
366                 }
367         }
368
369         // Determine if this encoding can be saved from a mail/news agent.
370         public override bool IsMailNewsSave
371         {
372                 get {
373                         return true;
374                 }
375         }
376
377         // Get the IANA-preferred Web name for this encoding.
378         public override String WebName
379         {
380                 get {
381                         return "iso-8859-1";
382                 }
383         }
384
385 #endif // !ECMA_COMPAT
386
387 }; // class Latin1Encoding
388
389 }; // namespace System.Text