New test.
[mono.git] / mcs / class / I18N / Common / ByteEncoding.cs
1 /*
2  * ByteEncoding.cs - Implementation of the "I18N.Common.ByteEncoding" class.
3  *
4  * Copyright (c) 2002  Southern Storm Software, Pty Ltd
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * OTHER DEALINGS IN THE SOFTWARE.
23  */
24
25 namespace I18N.Common
26 {
27
28 using System;
29 using System.Runtime.InteropServices;
30 using System.Text;
31
32 // This class provides an abstract base for encodings that use a single
33 // byte per character.  The bulk of the work is done in this class, with
34 // subclasses providing implementations of the "ToBytes" methods to perform
35 // the char->byte conversion.
36
37 [Serializable]
38 public abstract class ByteEncoding : MonoEncoding
39 {
40         // Internal state.
41         protected char[] toChars;
42         protected String encodingName;
43         protected String bodyName;
44         protected String headerName;
45         protected String webName;
46         protected bool isBrowserDisplay;
47         protected bool isBrowserSave;
48         protected bool isMailNewsDisplay;
49         protected bool isMailNewsSave;
50         protected int windowsCodePage;
51 #if NET_2_0
52         static byte [] isNormalized;
53         static byte [] isNormalizedComputed;
54         static byte [] normalization_bytes;
55 #endif
56
57         // Constructor.
58         protected ByteEncoding(int codePage, char[] toChars,
59                                                    String encodingName, String bodyName,
60                                                    String headerName, String webName,
61                                                    bool isBrowserDisplay, bool isBrowserSave,
62                                                    bool isMailNewsDisplay, bool isMailNewsSave,
63                                                    int windowsCodePage)
64                         : base(codePage)
65                         {
66                                 if (toChars.Length != byte.MaxValue + 1)
67                                         throw new ArgumentException("toChars");
68
69                                 this.toChars = toChars;
70                                 this.encodingName = encodingName;
71                                 this.bodyName = bodyName;
72                                 this.headerName = headerName;
73                                 this.webName = webName;
74                                 this.isBrowserDisplay = isBrowserDisplay;
75                                 this.isBrowserSave = isBrowserSave;
76                                 this.isMailNewsDisplay = isMailNewsDisplay;
77                                 this.isMailNewsSave = isMailNewsSave;
78                                 this.windowsCodePage = windowsCodePage;
79                         }
80
81 #if NET_2_0
82         public override bool IsAlwaysNormalized (NormalizationForm form)
83         {
84                 if (form != NormalizationForm.FormC)
85                         return false;
86
87                 if (isNormalized == null)
88                         isNormalized = new byte [0x10000 / 8];
89                 if (isNormalizedComputed == null)
90                         isNormalizedComputed = new byte [0x10000 / 8];
91
92                 if (normalization_bytes == null) {
93                         normalization_bytes = new byte [0x100];
94                         lock (normalization_bytes) {
95                                 for (int i = 0; i < 0x100; i++)
96                                         normalization_bytes [i] = (byte) i;
97                         }
98                 }
99
100                 byte offset = (byte) (1 << (CodePage % 8));
101                 if ((isNormalizedComputed [CodePage / 8] & offset) == 0) {
102                         Encoding e = Clone () as Encoding;
103                         e.DecoderFallback = new DecoderReplacementFallback ("");
104                         string s = e.GetString (normalization_bytes);
105                         // note that the flag only stores FormC information.
106                         if (s != s.Normalize (form))
107                                 isNormalized [CodePage / 8] |= offset;
108                         isNormalizedComputed [CodePage / 8] |= offset;
109                 }
110
111                 return (isNormalized [CodePage / 8] & offset) == 0;
112         }
113
114         public override bool IsSingleByte {
115                 get { return true; }
116         }
117 #endif
118
119         public override int GetByteCount(String s)
120                         {
121                                 if(s == null)
122                                 {
123                                         throw new ArgumentNullException("s");
124                                 }
125                                 return s.Length;
126                         }
127
128         // Get the number of bytes needed to encode a character buffer.
129         public unsafe override int GetByteCountImpl (char* chars, int count)
130                         {
131                                 return count;
132                         }
133
134         // Convert an array of characters into a byte buffer,
135         // once the parameters have been validated.
136         protected unsafe abstract void ToBytes (
137                 char* chars, int charCount, byte* bytes, int byteCount);
138         /*
139         protected unsafe virtual void ToBytes (
140                 char* chars, int charCount, byte* bytes, int byteCount)
141         {
142                 // When it is not overriden, use ToBytes() with arrays.
143                 char [] carr = new char [charCount];
144                 Marshal.Copy ((IntPtr) chars, carr, 0, charCount);
145                 byte [] barr = new byte [byteCount];
146                 Marshal.Copy ((IntPtr) bytes, barr, 0, byteCount);
147                 ToBytes (carr, 0, charCount, barr, 0);
148         }
149         */
150
151         // Convert an array of characters into a byte buffer,
152         // once the parameters have been validated.
153         protected unsafe virtual void ToBytes(char[] chars, int charIndex, int charCount,
154                                                                         byte[] bytes, int byteIndex)
155         {
156                 // When it is not overriden, use ToBytes() with pointers
157                 // (this is the ideal solution)
158                 if (charCount == 0 || bytes.Length == byteIndex)
159                         return;
160                 fixed (char* cptr = chars) {
161                         fixed (byte* bptr = bytes) {
162                                 ToBytes (cptr + charIndex, charCount,
163                                         bptr + byteIndex, bytes.Length - byteIndex);
164                         }
165                 }
166         }
167
168 /*
169         // Convert a string into a byte buffer, once the parameters
170         // have been validated.
171         protected unsafe virtual void ToBytes(String s, int charIndex, int charCount,
172                                                                         byte[] bytes, int byteIndex)
173         {
174                 // When it is not overriden, use ToBytes() with pointers
175                 // (Ideal solution)
176                 if (s.Length == 0 || bytes.Length == byteIndex)
177                         return;
178                 fixed (char* cptr = s) {
179                         fixed (byte* bptr = bytes) {
180                                 ToBytes (cptr + charIndex, charCount,
181                                         bptr + byteIndex, bytes.Length - byteIndex);
182                         }
183                 }
184         }
185 */
186
187         //[CLSCompliant (false)]
188         public unsafe override int GetBytesImpl (char* chars, int charCount, byte* bytes, int byteCount)
189         {
190                 ToBytes (chars, charCount, bytes, byteCount);
191                 return charCount;
192         }
193 /*
194         // Get the bytes that result from encoding a character buffer.
195         public override int GetBytes(char[] chars, int charIndex, int charCount,
196                                                                  byte[] bytes, int byteIndex)
197                         {
198                                 if(chars == null)
199                                 {
200                                         throw new ArgumentNullException("chars");
201                                 }
202                                 if(bytes == null)
203                                 {
204                                         throw new ArgumentNullException("bytes");
205                                 }
206                                 if(charIndex < 0 || charIndex > chars.Length)
207                                 {
208                                         throw new ArgumentOutOfRangeException
209                                                 ("charIndex", Strings.GetString("ArgRange_Array"));
210                                 }
211                                 if(charCount < 0 || charCount > (chars.Length - charIndex))
212                                 {
213                                         throw new ArgumentOutOfRangeException
214                                                 ("charCount", Strings.GetString("ArgRange_Array"));
215                                 }
216                                 if(byteIndex < 0 || byteIndex > bytes.Length)
217                                 {
218                                         throw new ArgumentOutOfRangeException
219                                                 ("byteIndex", Strings.GetString("ArgRange_Array"));
220                                 }
221                                 if((bytes.Length - byteIndex) < charCount)
222                                 {
223                                         throw new ArgumentException
224                                                 (Strings.GetString("Arg_InsufficientSpace"));
225                                 }
226                                 ToBytes(chars, charIndex, charCount, bytes, byteIndex);
227                                 return charCount;
228                         }
229
230         // Convenience wrappers for "GetBytes".
231         public override int GetBytes(String s, int charIndex, int charCount,
232                                                                  byte[] bytes, int byteIndex)
233                         {
234                                 if(s == null)
235                                 {
236                                         throw new ArgumentNullException("s");
237                                 }
238                                 if(bytes == null)
239                                 {
240                                         throw new ArgumentNullException("bytes");
241                                 }
242                                 if(charIndex < 0 || charIndex > s.Length)
243                                 {
244                                         throw new ArgumentOutOfRangeException
245                                                 ("charIndex",
246                                                  Strings.GetString("ArgRange_StringIndex"));
247                                 }
248                                 if(charCount < 0 || charCount > (s.Length - charIndex))
249                                 {
250                                         throw new ArgumentOutOfRangeException
251                                                 ("charCount",
252                                                  Strings.GetString("ArgRange_StringRange"));
253                                 }
254                                 if(byteIndex < 0 || byteIndex > bytes.Length)
255                                 {
256                                         throw new ArgumentOutOfRangeException
257                                                 ("byteIndex", Strings.GetString("ArgRange_Array"));
258                                 }
259                                 if((bytes.Length - byteIndex) < charCount)
260                                 {
261                                         throw new ArgumentException
262                                                 (Strings.GetString("Arg_InsufficientSpace"));
263                                 }
264                                 ToBytes(s, charIndex, charCount, bytes, byteIndex);
265                                 return charCount;
266                         }
267 */
268
269         // Get the number of characters needed to decode a byte buffer.
270         public override int GetCharCount(byte[] bytes, int index, int count)
271                         {
272                                 if(bytes == null)
273                                 {
274                                         throw new ArgumentNullException("bytes");
275                                 }
276                                 if(index < 0 || index > bytes.Length)
277                                 {
278                                         throw new ArgumentOutOfRangeException
279                                                 ("index", Strings.GetString("ArgRange_Array"));
280                                 }
281                                 if(count < 0 || count > (bytes.Length - index))
282                                 {
283                                         throw new ArgumentOutOfRangeException
284                                                 ("count", Strings.GetString("ArgRange_Array"));
285                                 }
286                                 return count;
287                         }
288
289         // Get the characters that result from decoding a byte buffer.
290         public override int GetChars(byte[] bytes, int byteIndex, int byteCount,
291                                                                  char[] chars, int charIndex)
292                         {
293                                 if(bytes == null)
294                                 {
295                                         throw new ArgumentNullException("bytes");
296                                 }
297                                 if(chars == null)
298                                 {
299                                         throw new ArgumentNullException("chars");
300                                 }
301                                 if(byteIndex < 0 || byteIndex > bytes.Length)
302                                 {
303                                         throw new ArgumentOutOfRangeException
304                                                 ("byteIndex", Strings.GetString("ArgRange_Array"));
305                                 }
306                                 if(byteCount < 0 || byteCount > (bytes.Length - byteIndex))
307                                 {
308                                         throw new ArgumentOutOfRangeException
309                                                 ("byteCount", Strings.GetString("ArgRange_Array"));
310                                 }
311                                 if(charIndex < 0 || charIndex > chars.Length)
312                                 {
313                                         throw new ArgumentOutOfRangeException
314                                                 ("charIndex", Strings.GetString("ArgRange_Array"));
315                                 }
316                                 if((chars.Length - charIndex) < byteCount)
317                                 {
318                                         throw new ArgumentException
319                                                 (Strings.GetString("Arg_InsufficientSpace"));
320                                 }
321                                 int count = byteCount;
322                                 char[] cvt = toChars;
323                                 while(count-- > 0)
324                                 {
325                                         chars[charIndex++] = cvt[(int)(bytes[byteIndex++])];
326                                 }
327                                 return byteCount;
328                         }
329
330         // Get the maximum number of bytes needed to encode a
331         // specified number of characters.
332         public override int GetMaxByteCount(int charCount)
333                         {
334                                 if(charCount < 0)
335                                 {
336                                         throw new ArgumentOutOfRangeException
337                                                 ("charCount",
338                                                  Strings.GetString("ArgRange_NonNegative"));
339                                 }
340                                 return charCount;
341                         }
342
343         // Get the maximum number of characters needed to decode a
344         // specified number of bytes.
345         public override int GetMaxCharCount(int byteCount)
346                         {
347                                 if(byteCount < 0)
348                                 {
349                                         throw new ArgumentOutOfRangeException
350                                                 ("byteCount",
351                                                  Strings.GetString("ArgRange_NonNegative"));
352                                 }
353                                 return byteCount;
354                         }
355
356         // Decode a buffer of bytes into a string.
357         public unsafe override String GetString(byte[] bytes, int index, int count)
358                         {
359                                 if(bytes == null)
360                                 {
361                                         throw new ArgumentNullException("bytes");
362                                 }
363                                 if(index < 0 || index > bytes.Length)
364                                 {
365                                         throw new ArgumentOutOfRangeException
366                                                 ("index", Strings.GetString("ArgRange_Array"));
367                                 }
368                                 if(count < 0 || count > (bytes.Length - index))
369                                 {
370                                         throw new ArgumentOutOfRangeException
371                                                 ("count", Strings.GetString("ArgRange_Array"));
372                                 }
373
374                                 if (count == 0)\r
375                                         return string.Empty;\r
376 \r
377                                 string s = new string ((char) 0, count);\r
378 \r
379                                 fixed (byte* bytePtr = bytes)\r
380                                         fixed (char* charPtr = s)\r
381                                                 fixed (char* cvt = toChars) {\r
382                                                         byte* b = bytePtr + index;\r
383                                                         char* c = charPtr;\r
384                                                         while(count-- != 0)
385                                                                 *(c++) = cvt[*(b++)];
386                                                 }
387 \r
388                                 return s;\r
389                         }
390         public override String GetString(byte[] bytes)
391                         {
392                                 if(bytes == null)
393                                 {
394                                         throw new ArgumentNullException("bytes");
395                                 }
396
397                                 return GetString (bytes, 0, bytes.Length);
398                         }
399
400 #if !ECMA_COMPAT
401
402         // Get the mail body name for this encoding.
403         public override String BodyName
404                         {
405                                 get
406                                 {
407                                         return bodyName;
408                                 }
409                         }
410
411         // Get the human-readable name for this encoding.
412         public override String EncodingName
413                         {
414                                 get
415                                 {
416                                         return encodingName;
417                                 }
418                         }
419
420         // Get the mail agent header name for this encoding.
421         public override String HeaderName
422                         {
423                                 get
424                                 {
425                                         return headerName;
426                                 }
427                         }
428
429         // Determine if this encoding can be displayed in a Web browser.
430         public override bool IsBrowserDisplay
431                         {
432                                 get
433                                 {
434                                         return isBrowserDisplay;
435                                 }
436                         }
437
438         // Determine if this encoding can be saved from a Web browser.
439         public override bool IsBrowserSave
440                         {
441                                 get
442                                 {
443                                         return isBrowserSave;
444                                 }
445                         }
446
447         // Determine if this encoding can be displayed in a mail/news agent.
448         public override bool IsMailNewsDisplay
449                         {
450                                 get
451                                 {
452                                         return isMailNewsDisplay;
453                                 }
454                         }
455
456         // Determine if this encoding can be saved from a mail/news agent.
457         public override bool IsMailNewsSave
458                         {
459                                 get
460                                 {
461                                         return isMailNewsSave;
462                                 }
463                         }
464
465         // Get the IANA-preferred Web name for this encoding.
466         public override String WebName
467                         {
468                                 get
469                                 {
470                                         return webName;
471                                 }
472                         }
473
474         // Get the Windows code page represented by this object.
475         public override int WindowsCodePage
476                         {
477                                 get
478                                 {
479                                         return windowsCodePage;
480                                 }
481                         }
482
483 #endif // !ECMA_COMPAT
484
485 }; // class ByteEncoding
486
487 }; // namespace I18N.Encoding