New test.
[mono.git] / mcs / class / I18N / CJK / CP949.cs
1 //
2 // I18N.CJK.CP949
3 //
4 // Author:
5 //   Hye-Shik Chang (perky@FreeBSD.org)
6 //   Atsushi Enomoto  <atsushi@ximian.com>
7 //
8
9 using System;
10 using System.Text;
11 using I18N.Common;
12
13 namespace I18N.CJK
14 {
15     [Serializable]
16     internal class CP949 : KoreanEncoding
17     {
18         // Magic number used by Windows for the UHC code page.
19         private const int UHC_CODE_PAGE = 949;
20
21         // Constructor.
22         public CP949 () : base (UHC_CODE_PAGE, true)
23         {
24         }
25
26         // Get the mail body name for this encoding.
27         public override String BodyName
28         {
29             get { return "ks_c_5601-1987"; }
30         }
31
32         // Get the human-readable name for this encoding.
33         public override String EncodingName
34         {
35             get { return "Korean (UHC)"; }
36         }
37
38         // Get the mail agent header name for this encoding.
39         public override String HeaderName
40         {
41             get { return "ks_c_5601-1987"; }
42         }
43
44         // Get the IANA-preferred Web name for this encoding.
45         public override String WebName
46         {
47             get { return "ks_c_5601-1987"; }
48         }
49
50         /*
51         // Get the Windows code page represented by this object.
52         public override int WindowsCodePage
53         {
54             get { return UHC_PAGE; }
55         }
56         */
57     }
58
59     [Serializable]
60     internal class CP51949 : KoreanEncoding
61     {
62         // Magic number used by Windows for the euc-kr code page.
63         private const int EUCKR_CODE_PAGE = 51949;
64
65         // Constructor.
66         public CP51949 () : base (EUCKR_CODE_PAGE, false)
67         {
68         }
69
70         // Get the mail body name for this encoding.
71         public override String BodyName
72         {
73             get { return "euc-kr"; }
74         }
75
76         // Get the human-readable name for this encoding.
77         public override String EncodingName
78         {
79             get { return "Korean (EUC)"; }
80         }
81
82         // Get the mail agent header name for this encoding.
83         public override String HeaderName
84         {
85             get { return "euc-kr"; }
86         }
87
88         // Get the IANA-preferred Web name for this encoding.
89         public override String WebName
90         {
91             get { return "euc-kr"; }
92         }
93
94         /*
95         // Get the Windows code page represented by this object.
96         public override int WindowsCodePage
97         {
98             get { return UHC_PAGE; }
99         }
100         */
101
102     }
103
104     [Serializable]
105     internal class KoreanEncoding : DbcsEncoding
106     {
107         // Constructor.
108         public KoreanEncoding (int codepage, bool useUHC)
109             : base (codepage, 949) {
110             this.useUHC = useUHC;
111         }
112
113         internal override DbcsConvert GetConvert ()
114         {
115                 return DbcsConvert.KS;
116         }
117
118         bool useUHC;
119
120         // Get the bytes that result from encoding a character buffer.
121         public unsafe override int GetByteCountImpl (char* chars, int count)
122         {
123             int index = 0;
124             int length = 0;
125             DbcsConvert convert = GetConvert ();
126 #if NET_2_0
127             EncoderFallbackBuffer buffer = null;
128 #endif
129
130             // 00 00 - FF FF
131             while (count-- > 0) {
132                 char c = chars[index++];
133                 if (c <= 0x80 || c == 0xFF) { // ASCII
134                     length++;
135                     continue;
136                 }
137                 byte b1 = convert.u2n[((int)c) * 2];
138                 byte b2 = convert.u2n[((int)c) * 2 + 1];
139                 if (b1 == 0 && b2 == 0) {
140 #if NET_2_0
141                     // FIXME: handle fallback for GetByteCountImpl().
142                     length++;
143 #else
144                     length++;
145 #endif
146                 }
147                 else
148                     length += 2;
149             }
150             return length;
151         }
152
153         // Get the bytes that result from encoding a character buffer.
154         public unsafe override int GetBytesImpl (char* chars, int charCount,
155                          byte* bytes, int byteCount)
156         {
157             int charIndex = 0;
158             int byteIndex = 0;
159             DbcsConvert convert = GetConvert ();
160 #if NET_2_0
161             EncoderFallbackBuffer buffer = null;
162 #endif
163
164             // 00 00 - FF FF
165             int origIndex = byteIndex;
166             while (charCount-- > 0) {
167                 char c = chars[charIndex++];
168                 if (c <= 0x80 || c == 0xFF) { // ASCII
169                     bytes[byteIndex++] = (byte)c;
170                     continue;
171                 }
172                 byte b1 = convert.u2n[((int)c) * 2];
173                 byte b2 = convert.u2n[((int)c) * 2 + 1];
174                 if (b1 == 0 && b2 == 0) {
175 #if NET_2_0
176                     HandleFallback (ref buffer, chars, ref charIndex, ref charCount,
177                         bytes, ref byteIndex, ref byteCount);
178 #else
179                     bytes[byteIndex++] = (byte)'?';
180 #endif
181                 } else {
182                     bytes[byteIndex++] = b1;
183                     bytes[byteIndex++] = b2;
184                 }
185             }
186             return byteIndex - origIndex;
187         }
188
189         // Get the characters that result from decoding a byte buffer.
190         public override int GetCharCount (byte[] bytes, int index, int count)
191         {
192             return GetDecoder ().GetCharCount (bytes, index, count);
193         }
194
195         // Get the characters that result from decoding a byte buffer.
196         public override int GetChars(byte[] bytes, int byteIndex, int byteCount,
197                          char[] chars, int charIndex)
198         {
199             return GetDecoder ().GetChars (bytes, byteIndex, byteCount, chars, charIndex);
200         }
201
202         // Get a decoder that handles a rolling UHC state.
203         public override Decoder GetDecoder()
204         {
205             return new KoreanDecoder (GetConvert (), useUHC);
206         }
207
208         // Decoder that handles a rolling UHC state.
209         private sealed class KoreanDecoder : DbcsDecoder
210         {
211             // Constructor.
212             public KoreanDecoder (DbcsConvert convert, bool useUHC)
213                 : base(convert)
214             {
215                 this.useUHC = useUHC;
216             }
217             bool useUHC;
218             int last_byte_count, last_byte_conv;
219
220             public override int GetCharCount (byte[] bytes, int index, int count)
221             {
222                 return GetCharCount (bytes, index, count, false);
223             }
224
225 #if NET_2_0
226             public override
227 #endif
228             int GetCharCount (byte [] bytes, int index, int count, bool refresh)
229             {
230                 CheckRange (bytes, index, count);
231
232                 int lastByte = last_byte_count;
233                 last_byte_count = 0;
234                 int length = 0;
235                 while (count-- > 0) {
236                     int b = bytes[index++];
237                     if (lastByte == 0) {
238                         if (b <= 0x80 || b == 0xFF) { // ASCII
239                             length++;
240                             continue;
241                         } else {
242                             lastByte = b;
243                             continue;
244                         }
245                     }
246
247                     char c1;
248                     if (useUHC && lastByte < 0xa1) { // UHC Level 1
249                         int ord = 8836 + (lastByte - 0x81) * 178;
250
251                         if (b >= 0x41 && b <= 0x5A)
252                             ord += b - 0x41;
253                         else if (b >= 0x61 && b <= 0x7A)
254                             ord += b - 0x61 + 26;
255                         else if (b >= 0x81 && b <= 0xFE)
256                             ord += b - 0x81 + 52;
257                         else
258                             ord = -1;
259
260                         if (ord >= 0 && ord * 2 <= convert.n2u.Length)
261                             c1 = (char)(convert.n2u[ord*2] +
262                                         convert.n2u[ord*2 + 1] * 256);
263                         else
264                             c1 = (char)0;
265                     } else if (useUHC && lastByte <= 0xC6 && b < 0xA1) { // UHC Level 2
266                         int ord = 14532 + (lastByte - 0xA1) * 84;
267
268                         if (b >= 0x41 && b <= 0x5A)
269                             ord += b - 0x41;
270                         else if (b >= 0x61 && b <= 0x7A)
271                             ord += b - 0x61 + 26;
272                         else if (b >= 0x81 && b <= 0xA0)
273                             ord += b - 0x81 + 52;
274                         else
275                             ord = -1;
276
277                         if (ord >= 0 && ord * 2 <= convert.n2u.Length)
278                             c1 = (char)(convert.n2u[ord*2] +
279                                         convert.n2u[ord*2 + 1] * 256);
280                         else
281                             c1 = (char)0;
282                     } else if (b >= 0xA1 && b <= 0xFE) { // KS X 1001
283                         int ord = ((lastByte - 0xA1) * 94 + b - 0xA1) * 2;
284
285                         c1 = ord < 0 || ord >= convert.n2u.Length ?
286                             '\0' : (char)(convert.n2u[ord] +
287                                     convert.n2u[ord + 1] * 256);
288                     } else
289                         c1 = (char)0;
290
291                     if (c1 == 0)
292                         // FIXME: fallback
293                         length++;
294                     else
295                         length++;
296                     lastByte = 0;
297                 }
298
299                 if (lastByte != 0) {
300                     if (refresh) {
301                         // FIXME: fallback
302                         length++;
303                         last_byte_count = 0;
304                     }
305                     else
306                         last_byte_count = lastByte;
307                 }
308                 return length;
309             }
310
311             public override int GetChars(byte[] bytes, int byteIndex,
312                                 int byteCount, char[] chars, int charIndex)
313             {
314                 return GetChars (bytes, byteIndex, byteCount, chars, charIndex, false);
315             }
316
317 #if NET_2_0
318             public override
319 #endif
320             int GetChars(byte[] bytes, int byteIndex,
321                                 int byteCount, char[] chars, int charIndex, bool refresh)
322             {
323                 CheckRange (bytes, byteIndex, byteCount, chars, charIndex);
324                 int origIndex = charIndex;
325                 int lastByte = last_byte_conv;
326                 last_byte_conv = 0;
327                 while (byteCount-- > 0) {
328                     int b = bytes[byteIndex++];
329                     if (lastByte == 0) {
330                         if (b <= 0x80 || b == 0xFF) { // ASCII
331                             chars[charIndex++] = (char)b;
332                             continue;
333                         } else {
334                             lastByte = b;
335                             continue;
336                         }
337                     }
338
339                     char c1;
340                     if (useUHC && lastByte < 0xa1) { // UHC Level 1
341                         int ord = 8836 + (lastByte - 0x81) * 178;
342
343                         if (b >= 0x41 && b <= 0x5A)
344                             ord += b - 0x41;
345                         else if (b >= 0x61 && b <= 0x7A)
346                             ord += b - 0x61 + 26;
347                         else if (b >= 0x81 && b <= 0xFE)
348                             ord += b - 0x81 + 52;
349                         else
350                             ord = -1;
351
352                         if (ord >= 0 && ord * 2 <= convert.n2u.Length)
353                             c1 = (char)(convert.n2u[ord*2] +
354                                         convert.n2u[ord*2 + 1] * 256);
355                         else
356                             c1 = (char)0;
357                     } else if (useUHC && lastByte <= 0xC6 && b < 0xA1) { // UHC Level 2
358                         int ord = 14532 + (lastByte - 0xA1) * 84;
359
360                         if (b >= 0x41 && b <= 0x5A)
361                             ord += b - 0x41;
362                         else if (b >= 0x61 && b <= 0x7A)
363                             ord += b - 0x61 + 26;
364                         else if (b >= 0x81 && b <= 0xA0)
365                             ord += b - 0x81 + 52;
366                         else
367                             ord = -1;
368
369                         if (ord >= 0 && ord * 2 <= convert.n2u.Length)
370                             c1 = (char)(convert.n2u[ord*2] +
371                                         convert.n2u[ord*2 + 1] * 256);
372                         else
373                             c1 = (char)0;
374                     } else if (b >= 0xA1 && b <= 0xFE) { // KS X 1001
375                         int ord = ((lastByte - 0xA1) * 94 + b - 0xA1) * 2;
376
377                         c1 = ord < 0 || ord >= convert.n2u.Length ?
378                             '\0' : (char)(convert.n2u[ord] +
379                                     convert.n2u[ord + 1] * 256);
380                     } else
381                         c1 = (char)0;
382
383                     if (c1 == 0)
384                         chars[charIndex++] = '?';
385                     else
386                         chars[charIndex++] = c1;
387                     lastByte = 0;
388                 }
389
390                 if (lastByte != 0) {
391                     if (refresh) {
392                         chars[charIndex++] = '?';
393                         last_byte_conv = 0;
394                     }
395                     else
396                         last_byte_conv = lastByte;
397                 }
398                 return charIndex - origIndex;
399             }
400         }
401     }
402
403     [Serializable]
404     internal class ENCuhc : CP949
405     {
406         public ENCuhc() {}
407     }
408
409     [Serializable]
410     internal class ENCeuc_kr: CP51949
411     {
412         public ENCeuc_kr() {}
413     }
414 }
415
416 // ex: ts=8 sts=4 et