Merge pull request #5714 from alexischr/update_bockbuild
[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         static byte [] isNormalized;
52         static byte [] isNormalizedComputed;
53         static byte [] normalization_bytes;
54
55         // Constructor.
56         protected ByteEncoding(int codePage, char[] toChars,
57                                                    String encodingName, String bodyName,
58                                                    String headerName, String webName,
59                                                    bool isBrowserDisplay, bool isBrowserSave,
60                                                    bool isMailNewsDisplay, bool isMailNewsSave,
61                                                    int windowsCodePage)
62                         : base(codePage)
63                         {
64                                 if (toChars.Length != byte.MaxValue + 1)
65                                         throw new ArgumentException("toChars");
66
67                                 this.toChars = toChars;
68                                 this.encodingName = encodingName;
69                                 this.bodyName = bodyName;
70                                 this.headerName = headerName;
71                                 this.webName = webName;
72                                 this.isBrowserDisplay = isBrowserDisplay;
73                                 this.isBrowserSave = isBrowserSave;
74                                 this.isMailNewsDisplay = isMailNewsDisplay;
75                                 this.isMailNewsSave = isMailNewsSave;
76                                 this.windowsCodePage = windowsCodePage;
77                         }
78
79         public override bool IsAlwaysNormalized (NormalizationForm form)
80         {
81                 if (form != NormalizationForm.FormC)
82                         return false;
83
84                 if (isNormalized == null)
85                         isNormalized = new byte [0x10000 / 8];
86                 if (isNormalizedComputed == null)
87                         isNormalizedComputed = new byte [0x10000 / 8];
88
89                 if (normalization_bytes == null) {
90                         normalization_bytes = new byte [0x100];
91                         lock (normalization_bytes) {
92                                 for (int i = 0; i < 0x100; i++)
93                                         normalization_bytes [i] = (byte) i;
94                         }
95                 }
96
97                 byte offset = (byte) (1 << (CodePage % 8));
98                 if ((isNormalizedComputed [CodePage / 8] & offset) == 0) {
99                         Encoding e = Clone () as Encoding;
100                         e.DecoderFallback = new DecoderReplacementFallback ("");
101                         string s = e.GetString (normalization_bytes);
102                         // note that the flag only stores FormC information.
103                         if (s != s.Normalize (form))
104                                 isNormalized [CodePage / 8] |= offset;
105                         isNormalizedComputed [CodePage / 8] |= offset;
106                 }
107
108                 return (isNormalized [CodePage / 8] & offset) == 0;
109         }
110
111         public override bool IsSingleByte {
112                 get { return true; }
113         }
114
115         public override int GetByteCount(String s)
116                         {
117                                 if(s == null)
118                                 {
119                                         throw new ArgumentNullException("s");
120                                 }
121                                 return s.Length;
122                         }
123
124         // Get the number of bytes needed to encode a character buffer.
125         public unsafe override int GetByteCountImpl (char* chars, int count)
126                         {
127                                 return count;
128                         }
129
130         // Convert an array of characters into a byte buffer,
131         // once the parameters have been validated.
132         protected unsafe abstract void ToBytes (
133                 char* chars, int charCount, byte* bytes, int byteCount);
134         /*
135         protected unsafe virtual void ToBytes (
136                 char* chars, int charCount, byte* bytes, int byteCount)
137         {
138                 // When it is not overriden, use ToBytes() with arrays.
139                 char [] carr = new char [charCount];
140                 Marshal.Copy ((IntPtr) chars, carr, 0, charCount);
141                 byte [] barr = new byte [byteCount];
142                 Marshal.Copy ((IntPtr) bytes, barr, 0, byteCount);
143                 ToBytes (carr, 0, charCount, barr, 0);
144         }
145         */
146
147         // Convert an array of characters into a byte buffer,
148         // once the parameters have been validated.
149         protected unsafe virtual void ToBytes(char[] chars, int charIndex, int charCount,
150                                                                         byte[] bytes, int byteIndex)
151         {
152                 // When it is not overriden, use ToBytes() with pointers
153                 // (this is the ideal solution)
154                 if (charCount == 0 || bytes.Length == byteIndex)
155                         return;
156                 if (charIndex < 0 || charIndex > chars.Length) {
157                         throw new ArgumentOutOfRangeException
158                                 ("charIndex", Strings.GetString("ArgRange_Array"));
159                 }
160                 if (byteIndex < 0 || byteIndex > bytes.Length) {
161                         throw new ArgumentOutOfRangeException
162                                 ("byteIndex", Strings.GetString("ArgRange_Array"));
163                 }
164                 if (charCount < 0 || charIndex + charCount > chars.Length || byteIndex + charCount > bytes.Length) {
165                         throw new ArgumentOutOfRangeException
166                                 ("charCount", Strings.GetString("ArgRange_Array"));
167                 }
168                 fixed (char* cptr = chars) {
169                         fixed (byte* bptr = bytes) {
170                                 ToBytes (cptr + charIndex, charCount,
171                                         bptr + byteIndex, bytes.Length - byteIndex);
172                         }
173                 }
174         }
175
176 /*
177         // Convert a string into a byte buffer, once the parameters
178         // have been validated.
179         protected unsafe virtual void ToBytes(String s, int charIndex, int charCount,
180                                                                         byte[] bytes, int byteIndex)
181         {
182                 // When it is not overriden, use ToBytes() with pointers
183                 // (Ideal solution)
184                 if (s.Length == 0 || bytes.Length == byteIndex)
185                         return;
186                 fixed (char* cptr = s) {
187                         fixed (byte* bptr = bytes) {
188                                 ToBytes (cptr + charIndex, charCount,
189                                         bptr + byteIndex, bytes.Length - byteIndex);
190                         }
191                 }
192         }
193 */
194
195         //[CLSCompliant (false)]
196         public unsafe override int GetBytesImpl (char* chars, int charCount, byte* bytes, int byteCount)
197         {
198                 ToBytes (chars, charCount, bytes, byteCount);
199                 return charCount;
200         }
201 /*
202         // Get the bytes that result from encoding a character buffer.
203         public override int GetBytes(char[] chars, int charIndex, int charCount,
204                                                                  byte[] bytes, int byteIndex)
205                         {
206                                 if(chars == null)
207                                 {
208                                         throw new ArgumentNullException("chars");
209                                 }
210                                 if(bytes == null)
211                                 {
212                                         throw new ArgumentNullException("bytes");
213                                 }
214                                 if(charIndex < 0 || charIndex > chars.Length)
215                                 {
216                                         throw new ArgumentOutOfRangeException
217                                                 ("charIndex", Strings.GetString("ArgRange_Array"));
218                                 }
219                                 if(charCount < 0 || charCount > (chars.Length - charIndex))
220                                 {
221                                         throw new ArgumentOutOfRangeException
222                                                 ("charCount", Strings.GetString("ArgRange_Array"));
223                                 }
224                                 if(byteIndex < 0 || byteIndex > bytes.Length)
225                                 {
226                                         throw new ArgumentOutOfRangeException
227                                                 ("byteIndex", Strings.GetString("ArgRange_Array"));
228                                 }
229                                 if((bytes.Length - byteIndex) < charCount)
230                                 {
231                                         throw new ArgumentException
232                                                 (Strings.GetString("Arg_InsufficientSpace"));
233                                 }
234                                 ToBytes(chars, charIndex, charCount, bytes, byteIndex);
235                                 return charCount;
236                         }
237
238         // Convenience wrappers for "GetBytes".
239         public override int GetBytes(String s, int charIndex, int charCount,
240                                                                  byte[] bytes, int byteIndex)
241                         {
242                                 if(s == null)
243                                 {
244                                         throw new ArgumentNullException("s");
245                                 }
246                                 if(bytes == null)
247                                 {
248                                         throw new ArgumentNullException("bytes");
249                                 }
250                                 if(charIndex < 0 || charIndex > s.Length)
251                                 {
252                                         throw new ArgumentOutOfRangeException
253                                                 ("charIndex",
254                                                  Strings.GetString("ArgRange_StringIndex"));
255                                 }
256                                 if(charCount < 0 || charCount > (s.Length - charIndex))
257                                 {
258                                         throw new ArgumentOutOfRangeException
259                                                 ("charCount",
260                                                  Strings.GetString("ArgRange_StringRange"));
261                                 }
262                                 if(byteIndex < 0 || byteIndex > bytes.Length)
263                                 {
264                                         throw new ArgumentOutOfRangeException
265                                                 ("byteIndex", Strings.GetString("ArgRange_Array"));
266                                 }
267                                 if((bytes.Length - byteIndex) < charCount)
268                                 {
269                                         throw new ArgumentException
270                                                 (Strings.GetString("Arg_InsufficientSpace"));
271                                 }
272                                 ToBytes(s, charIndex, charCount, bytes, byteIndex);
273                                 return charCount;
274                         }
275 */
276
277         // Get the number of characters needed to decode a byte buffer.
278         public override int GetCharCount(byte[] bytes, int index, int count)
279                         {
280                                 if(bytes == null)
281                                 {
282                                         throw new ArgumentNullException("bytes");
283                                 }
284                                 if(index < 0 || index > bytes.Length)
285                                 {
286                                         throw new ArgumentOutOfRangeException
287                                                 ("index", Strings.GetString("ArgRange_Array"));
288                                 }
289                                 if(count < 0 || count > (bytes.Length - index))
290                                 {
291                                         throw new ArgumentOutOfRangeException
292                                                 ("count", Strings.GetString("ArgRange_Array"));
293                                 }
294                                 return count;
295                         }
296
297         // Get the characters that result from decoding a byte buffer.
298         public override int GetChars(byte[] bytes, int byteIndex, int byteCount,
299                                                                  char[] chars, int charIndex)
300                         {
301                                 if(bytes == null)
302                                 {
303                                         throw new ArgumentNullException("bytes");
304                                 }
305                                 if(chars == null)
306                                 {
307                                         throw new ArgumentNullException("chars");
308                                 }
309                                 if(byteIndex < 0 || byteIndex > bytes.Length)
310                                 {
311                                         throw new ArgumentOutOfRangeException
312                                                 ("byteIndex", Strings.GetString("ArgRange_Array"));
313                                 }
314                                 if(byteCount < 0 || byteCount > (bytes.Length - byteIndex))
315                                 {
316                                         throw new ArgumentOutOfRangeException
317                                                 ("byteCount", Strings.GetString("ArgRange_Array"));
318                                 }
319                                 if(charIndex < 0 || charIndex > chars.Length)
320                                 {
321                                         throw new ArgumentOutOfRangeException
322                                                 ("charIndex", Strings.GetString("ArgRange_Array"));
323                                 }
324                                 if((chars.Length - charIndex) < byteCount)
325                                 {
326                                         throw new ArgumentException
327                                                 (Strings.GetString("Arg_InsufficientSpace"));
328                                 }
329                                 int count = byteCount;
330                                 char[] cvt = toChars;
331                                 while(count-- > 0)
332                                 {
333                                         chars[charIndex++] = cvt[(int)(bytes[byteIndex++])];
334                                 }
335                                 return byteCount;
336                         }
337
338         // Get the maximum number of bytes needed to encode a
339         // specified number of characters.
340         public override int GetMaxByteCount(int charCount)
341                         {
342                                 if(charCount < 0)
343                                 {
344                                         throw new ArgumentOutOfRangeException
345                                                 ("charCount",
346                                                  Strings.GetString("ArgRange_NonNegative"));
347                                 }
348                                 return charCount;
349                         }
350
351         // Get the maximum number of characters needed to decode a
352         // specified number of bytes.
353         public override int GetMaxCharCount(int byteCount)
354                         {
355                                 if(byteCount < 0)
356                                 {
357                                         throw new ArgumentOutOfRangeException
358                                                 ("byteCount",
359                                                  Strings.GetString("ArgRange_NonNegative"));
360                                 }
361                                 return byteCount;
362                         }
363
364         // Decode a buffer of bytes into a string.
365         public unsafe override String GetString(byte[] bytes, int index, int count)
366                         {
367                                 if(bytes == null)
368                                 {
369                                         throw new ArgumentNullException("bytes");
370                                 }
371                                 if(index < 0 || index > bytes.Length)
372                                 {
373                                         throw new ArgumentOutOfRangeException
374                                                 ("index", Strings.GetString("ArgRange_Array"));
375                                 }
376                                 if(count < 0 || count > (bytes.Length - index))
377                                 {
378                                         throw new ArgumentOutOfRangeException
379                                                 ("count", Strings.GetString("ArgRange_Array"));
380                                 }
381
382                                 if (count == 0)
383                                         return string.Empty;
384
385                                 string s = new string ((char) 0, count);
386
387                                 fixed (byte* bytePtr = bytes)
388                                         fixed (char* charPtr = s)
389                                                 fixed (char* cvt = toChars) {
390                                                         byte* b = bytePtr + index;
391                                                         char* c = charPtr;
392                                                         while(count-- != 0)
393                                                                 *(c++) = cvt[*(b++)];
394                                                 }
395
396                                 return s;
397                         }
398         public override String GetString(byte[] bytes)
399                         {
400                                 if(bytes == null)
401                                 {
402                                         throw new ArgumentNullException("bytes");
403                                 }
404
405                                 return GetString (bytes, 0, bytes.Length);
406                         }
407
408 #if !ECMA_COMPAT
409
410         // Get the mail body name for this encoding.
411         public override String BodyName
412                         {
413                                 get
414                                 {
415                                         return bodyName;
416                                 }
417                         }
418
419         // Get the human-readable name for this encoding.
420         public override String EncodingName
421                         {
422                                 get
423                                 {
424                                         return encodingName;
425                                 }
426                         }
427
428         // Get the mail agent header name for this encoding.
429         public override String HeaderName
430                         {
431                                 get
432                                 {
433                                         return headerName;
434                                 }
435                         }
436
437         // Determine if this encoding can be displayed in a Web browser.
438         public override bool IsBrowserDisplay
439                         {
440                                 get
441                                 {
442                                         return isBrowserDisplay;
443                                 }
444                         }
445
446         // Determine if this encoding can be saved from a Web browser.
447         public override bool IsBrowserSave
448                         {
449                                 get
450                                 {
451                                         return isBrowserSave;
452                                 }
453                         }
454
455         // Determine if this encoding can be displayed in a mail/news agent.
456         public override bool IsMailNewsDisplay
457                         {
458                                 get
459                                 {
460                                         return isMailNewsDisplay;
461                                 }
462                         }
463
464         // Determine if this encoding can be saved from a mail/news agent.
465         public override bool IsMailNewsSave
466                         {
467                                 get
468                                 {
469                                         return isMailNewsSave;
470                                 }
471                         }
472
473         // Get the IANA-preferred Web name for this encoding.
474         public override String WebName
475                         {
476                                 get
477                                 {
478                                         return webName;
479                                 }
480                         }
481
482         // Get the Windows code page represented by this object.
483         public override int WindowsCodePage
484                         {
485                                 get
486                                 {
487                                         return windowsCodePage;
488                                 }
489                         }
490
491 #endif // !ECMA_COMPAT
492
493 }; // class ByteEncoding
494
495 }; // namespace I18N.Encoding