Merge pull request #2174 from stukselbax/master
[mono.git] / mcs / class / I18N / Common / MonoEncoding.cs
1 //
2 // MonoEncoding.cs
3 //
4 // Author:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // Copyright (C) 2005 Novell, Inc.  http://www.novell.com
8 //
9 using System;
10 using System.Runtime.InteropServices;
11 using System.Text;
12
13 namespace I18N.Common
14 {
15         [Serializable]
16         public abstract class MonoEncoding : Encoding
17         {
18                 readonly int win_code_page;
19
20                 public MonoEncoding (int codePage)
21                         : this (codePage, 0)
22                 {
23                 }
24
25                 public MonoEncoding (int codePage, int windowsCodePage)
26                         : base (codePage)
27                 {
28                         win_code_page = windowsCodePage;
29                 }
30
31                 public override int WindowsCodePage {
32                         get { return win_code_page != 0 ? win_code_page : base.WindowsCodePage; }
33                 }
34
35                 /// <summary>
36                 /// GetBytes method used internally by state-full encoders/encodings.
37                 /// </summary>
38                 /// <param name="chars">The chars.</param>
39                 /// <param name="charIndex">Index of the char.</param>
40                 /// <param name="charCount">The char count.</param>
41                 /// <param name="bytes">The bytes.</param>
42                 /// <param name="byteIndex">Index of the byte.</param>
43                 /// <param name="flush">if set to <c>true</c> [flush].</param>
44                 /// <param name="encoding">The encoding class to use (or null if state-less).</param>
45                 /// <returns></returns>
46                 /// <remarks>
47                 /// Only state-full encoders need to implement this method (ie. ISO-2022-JP)
48                 /// </remarks>
49                 protected unsafe virtual int GetBytesInternal(char *chars, int charCount,
50                                 byte *bytes, int byteCount, bool flush, object state)
51                 {
52                         throw new NotImplementedException("Statefull encoding is not implemented (yet?) by this encoding class.");
53                 }
54
55                 public unsafe void HandleFallback (ref EncoderFallbackBuffer buffer,
56                         char* chars, ref int charIndex, ref int charCount,
57                         byte* bytes, ref int byteIndex, ref int byteCount, object state)
58                 {
59                         if (buffer == null)
60                                 buffer = EncoderFallback.CreateFallbackBuffer ();
61
62                         if (charCount > 1 && (Char.IsSurrogate (chars [charIndex]) && Char.IsSurrogate (chars [charIndex + 1]))) {
63                                 buffer.Fallback (chars [charIndex], chars [charIndex + 1], charIndex);
64                                 charIndex++;
65                                 charCount--;
66                         }
67                         else
68                                 buffer.Fallback (chars [charIndex], charIndex);
69                         char [] tmp = new char [buffer.Remaining];
70                         int idx = 0;
71                         while (buffer.Remaining > 0)
72                                 tmp [idx++] = buffer.GetNextChar ();
73
74                         fixed (char* tmparr = tmp) {
75                                 var outbytes = bytes == null ? null : bytes + byteIndex;
76                                 var len = state == null ?
77                                         GetBytes(tmparr, tmp.Length, outbytes, byteCount)
78                                         : GetBytesInternal(tmparr, tmp.Length, outbytes, byteCount, true, state);
79
80                                 byteIndex += len;
81                                 byteCount -= len;
82                         }
83                 }
84
85                 public unsafe void HandleFallback (ref EncoderFallbackBuffer buffer,
86                         char* chars, ref int charIndex, ref int charCount,
87                         byte* bytes, ref int byteIndex, ref int byteCount)
88                 {
89                         HandleFallback(ref buffer, chars, ref charIndex, ref charCount,
90                                 bytes, ref byteIndex, ref byteCount, null);
91                 }
92
93                 // Get the bytes that result from encoding a character buffer.
94                 public override int GetByteCount (
95                         char [] chars, int index, int count)
96                 {
97                         if (chars == null)
98                                 throw new ArgumentNullException ("chars");
99                         if (index < 0 || index > chars.Length)
100                                 throw new ArgumentOutOfRangeException
101                                         ("index", Strings.GetString ("ArgRange_Array"));
102                         if (count < 0 || count > (chars.Length - index))
103                                 throw new ArgumentOutOfRangeException
104                                         ("count", Strings.GetString ("ArgRange_Array"));
105
106                         if (count == 0)
107                                 return 0;
108
109                         unsafe {
110                                 fixed (char* cptr = chars) {
111                                         return GetByteCountImpl (
112                                                 cptr + index, count);
113                                 }
114                         }
115                 }
116
117                 // Get the bytes that result from encoding a character buffer.
118                 public override int GetBytes (
119                         char [] chars, int charIndex, int charCount,
120                         byte [] bytes, int byteIndex)
121                 {
122                         if (chars == null)
123                                 throw new ArgumentNullException ("chars");
124                         if (bytes == null)
125                                 throw new ArgumentNullException ("bytes");
126                         if (charIndex < 0 || charIndex > chars.Length)
127                                 throw new ArgumentOutOfRangeException
128                                         ("charIndex", Strings.GetString ("ArgRange_Array"));
129                         if (charCount < 0 || charCount > (chars.Length - charIndex))
130                                 throw new ArgumentOutOfRangeException
131                                         ("charCount", Strings.GetString ("ArgRange_Array"));
132                         if (byteIndex < 0 || byteIndex > bytes.Length)
133                                 throw new ArgumentOutOfRangeException
134                                         ("byteIndex", Strings.GetString ("ArgRange_Array"));
135                         if (bytes.Length - byteIndex < charCount)
136                                 throw new ArgumentException (Strings.GetString ("Arg_InsufficientSpace"), "bytes");
137
138                         if (charCount == 0)
139                                 return 0;
140
141                         unsafe {
142                                 fixed (char* cptr = chars) {
143                                         fixed (byte* bptr = bytes) {
144                                                 return GetBytesImpl (
145                                                         cptr + charIndex,
146                                                         charCount,
147                                                         bptr + byteIndex,
148                                                         bytes.Length - byteIndex);
149                                         }
150                                 }
151                         }
152                 }
153
154                 // Convenience wrappers for "GetBytes".
155                 public override int GetBytes (string s, int charIndex, int charCount,
156                         byte [] bytes, int byteIndex)
157                 {
158                         // Validate the parameters.
159                         if(s == null)
160                                 throw new ArgumentNullException("s");
161                         if(bytes == null)
162                                 throw new ArgumentNullException("bytes");
163                         if(charIndex < 0 || charIndex > s.Length)
164                                 throw new ArgumentOutOfRangeException
165                                         ("charIndex",
166                                          Strings.GetString("ArgRange_StringIndex"));
167                         if(charCount < 0 || charCount > (s.Length - charIndex))
168                                 throw new ArgumentOutOfRangeException
169                                         ("charCount",
170                                          Strings.GetString("ArgRange_StringRange"));
171                         if(byteIndex < 0 || byteIndex > bytes.Length)
172                                 throw new ArgumentOutOfRangeException
173                                         ("byteIndex",
174                                          Strings.GetString("ArgRange_Array"));
175                         if((bytes.Length - byteIndex) < charCount)
176                                 throw new ArgumentException
177                                         (Strings.GetString("Arg_InsufficientSpace"), "bytes");
178
179                         if (charCount == 0 || bytes.Length == byteIndex)
180                                 return 0;
181                         unsafe {
182                                 fixed (char* cptr = s) {
183                                         fixed (byte* bptr = bytes) {
184                                                 return GetBytesImpl (
185                                                         cptr + charIndex,
186                                                         charCount,
187                                                         bptr + byteIndex,
188                                                         bytes.Length - byteIndex);
189                                         }
190                                 }
191                         }
192                 }
193
194                 public unsafe override int GetByteCount (char* chars, int count)
195
196                 {
197                         return GetByteCountImpl (chars, count);
198                 }
199
200                 public unsafe override int GetBytes (char* chars, int charCount,
201                         byte* bytes, int byteCount)
202
203                 {
204                         return GetBytesImpl (chars, charCount, bytes, byteCount);
205                 }
206
207                 //[CLSCompliant (false)]
208                 public unsafe abstract int GetByteCountImpl (char* chars, int charCount);
209
210                 //[CLSCompliant (false)]
211                 public unsafe abstract int GetBytesImpl (char* chars, int charCount,
212                         byte* bytes, int byteCount);
213                 
214                 public override Encoder GetEncoder ()
215                 {
216                         return new MonoEncodingDefaultEncoder (this);
217                 }
218         }
219
220                 public abstract class MonoEncoder : Encoder
221                 {
222                         MonoEncoding encoding;
223
224                         public MonoEncoder (MonoEncoding encoding)
225                         {
226                                 this.encoding = encoding;
227                         }
228
229                         public override int GetByteCount (
230                                 char [] chars, int index, int count, bool refresh)
231                         {
232                                 if (chars == null)
233                                         throw new ArgumentNullException ("chars");
234                                 if (index < 0 || index > chars.Length)
235                                         throw new ArgumentOutOfRangeException
236                                                 ("index", Strings.GetString ("ArgRange_Array"));
237                                 if (count < 0 || count > (chars.Length - index))
238                                         throw new ArgumentOutOfRangeException
239                                                 ("count", Strings.GetString ("ArgRange_Array"));
240
241                                 if (count == 0)
242                                         return 0;
243
244                                 unsafe {
245                                         fixed (char* cptr = chars) {
246                                                 return GetByteCountImpl (
247                                                         cptr + index, count, refresh);
248                                         }
249                                 }
250                         }
251
252                         public override int GetBytes (char [] chars, int charIndex, int charCount, byte [] bytes, int byteIndex, bool flush)
253                         {
254                                 if (chars == null)
255                                         throw new ArgumentNullException ("chars");
256                                 if (bytes == null)
257                                         throw new ArgumentNullException ("bytes");
258                                 if (charIndex < 0 || charIndex > chars.Length)
259                                         throw new ArgumentOutOfRangeException
260                                                 ("charIndex", Strings.GetString ("ArgRange_Array"));
261                                 if (charCount < 0 || charCount > (chars.Length - charIndex))
262                                         throw new ArgumentOutOfRangeException
263                                                 ("charCount", Strings.GetString ("ArgRange_Array"));
264                                 if (byteIndex < 0 || byteIndex > bytes.Length)
265                                         throw new ArgumentOutOfRangeException
266                                                 ("byteIndex", Strings.GetString ("ArgRange_Array"));
267                                 if (bytes.Length - byteIndex < charCount)
268                                         throw new ArgumentException (Strings.GetString ("Arg_InsufficientSpace"), "bytes");
269
270                                 if (charCount == 0)
271                                         return 0;
272                                 unsafe {
273                                         fixed (char* cptr = chars) {
274                                                 fixed (byte* bptr = bytes) {
275                                                         return GetBytesImpl (cptr + charIndex, 
276                                                                 charCount,
277                                                                 bptr + byteIndex,
278                                                                 bytes.Length - byteIndex,
279                                                                 flush);
280                                                 }
281                                         }
282                                 }
283                         }
284
285                         public unsafe abstract int GetByteCountImpl (char* chars, int charCount, bool refresh);
286
287                         public unsafe abstract int GetBytesImpl (char* chars, int charCount, byte* bytes, int byteCount, bool refresh);
288
289                         public unsafe override int GetBytes (char* chars, int charCount, byte* bytes, int byteCount, bool flush)
290                         {
291                                 return GetBytesImpl (chars, charCount, bytes, byteCount, flush);
292                         }
293
294                         public unsafe void HandleFallback (
295                                 char* chars, ref int charIndex, ref int charCount,
296                                 byte* bytes, ref int byteIndex, ref int byteCount, object state)
297                         {
298                                 EncoderFallbackBuffer buffer = FallbackBuffer;
299                                 encoding.HandleFallback (ref buffer,
300                                         chars, ref charIndex, ref charCount,
301                                         bytes, ref byteIndex, ref byteCount, state);
302                         }
303
304 /*                      public unsafe void HandleFallback(
305                                 char* chars, ref int charIndex, ref int charCount,
306                                 byte* bytes, ref int byteIndex, ref int byteCount)
307                         {
308                                 HandleFallback(chars, ref charIndex, ref charCount,
309                                         bytes, ref byteIndex, ref byteCount, null);
310                         }*/
311                 }
312
313         public class MonoEncodingDefaultEncoder : ReferenceSourceDefaultEncoder
314         {
315                 public MonoEncodingDefaultEncoder (Encoding encoding)
316                         : base (encoding)
317                 {
318                 }
319
320                 [CLSCompliant (false)]
321                 [ComVisible (false)]
322                 public unsafe override void Convert (
323                         char* chars, int charCount,
324                         byte* bytes, int byteCount, bool flush,
325                         out int charsUsed, out int bytesUsed, out bool completed)
326                 {
327                         CheckArguments (chars, charCount, bytes, byteCount);
328
329                         charsUsed = charCount;
330                         while (true) {
331                                 bytesUsed = GetByteCount (chars, charsUsed, flush);
332                                 if (bytesUsed <= byteCount)
333                                         break;
334                                 flush = false;
335                                 charsUsed >>= 1;
336                         }
337                         completed = charsUsed == charCount;
338                         bytesUsed = GetBytes (chars, charsUsed, bytes, byteCount, flush);
339                 }
340
341                 [ComVisible (false)]
342                 public override void Convert (
343                         char [] chars, int charIndex, int charCount,
344                         byte [] bytes, int byteIndex, int byteCount, bool flush,
345                         out int charsUsed, out int bytesUsed, out bool completed)
346                 {
347                         if (chars == null)
348                                 throw new ArgumentNullException ("chars");
349                         if (bytes == null)
350                                 throw new ArgumentNullException ("bytes");
351                         if (charIndex < 0)
352                                 throw new ArgumentOutOfRangeException ("charIndex");
353                         if (charCount < 0 || chars.Length < charIndex + charCount)
354                                 throw new ArgumentOutOfRangeException ("charCount");
355                         if (byteIndex < 0)
356                                 throw new ArgumentOutOfRangeException ("byteIndex");
357                         if (byteCount < 0 || bytes.Length < byteIndex + byteCount)
358                                 throw new ArgumentOutOfRangeException ("byteCount");
359
360                         charsUsed = charCount;
361                         while (true) {
362                                 bytesUsed = GetByteCount (chars, charIndex, charsUsed, flush);
363                                 if (bytesUsed <= byteCount)
364                                         break;
365                                 flush = false;
366                                 charsUsed >>= 1;
367                         }
368                         completed = charsUsed == charCount;
369                         bytesUsed = GetBytes (chars, charIndex, charsUsed, bytes, byteIndex, flush);
370                 }
371
372                 unsafe void CheckArguments (char* chars, int charCount, byte* bytes, int byteCount)
373                 {
374                         if (chars == null)
375                                 throw new ArgumentNullException ("chars");
376                         if (bytes == null)
377                                 throw new ArgumentNullException ("bytes");
378                         if (charCount < 0)
379                                 throw new ArgumentOutOfRangeException ("charCount");
380                         if (byteCount < 0)
381                                 throw new ArgumentOutOfRangeException ("byteCount");
382                 }
383         }
384 }