source: trunk/ab5.0/ablib/src/Classes/System/Text/Encoding.ab@ 682

Last change on this file since 682 was 682, checked in by イグトランス (egtra), 15 years ago

UTF8Encodingクラスをとりあえず使える状態に。ただし、BOM出力はまだ不可能。
(#231)

File size: 14.5 KB
RevLine 
[411]1/*!
2@file Classes/System/Text/Encoding.ab
3@brief Encodingクラスとそれに関係するクラスなどの宣言・定義
4*/
5
6Namespace System
7Namespace Text
8
9/*!
10@brief 各種の文字符号化(エンコーディング)を行うためのクラス
11@date 2007/12/07
12@auther Egtra
13
14なお、このクラスで、文字列の長さやバッファの大きさを指定するときには、
[653]151 WCHAR = 2バイト(UTF-16符号単位)、1 Byte = 1バイトの単位で指定する。
[411]16
17*/
18Class Encoding
19 Implements ICloneable
20Public
21 /*!
22 @brief 簡易的複製を作成する。
23 */
[653]24 Virtual Function Clone() As Object
25 Clone = This
26 End Function
[411]27
28' Override Function Equals(y As Object) As Boolean
29' End Function
30
31' Override Function GetHashCode() As Long
32' End Function
33
34Public
35 Sub Encoding()
36 End Sub
37
38 /*!
39 @brief 符号化して得られる文字列の長さを計算する。
[653]40 @param[in] src 対象文字列
[676]41 @param[in] srcCount srcの長さ(要素数単位)
42 @return 符号化して得られる文字列の長さ(要素数単位)
[411]43 @date 2007/12/08
44 */
[653]45 Function GetBytesCount(src As *WCHAR, srcCount As Long) As Long
46 If src = 0 Then
47 Throw New ArgumentNullException("src")
48 ElseIf srcCount < 0 Then
49 Throw New ArgumentOutOfRangeException("srcCount")
[411]50 End If
[653]51 Return GetBytesCountCore(src, srcCount)
[411]52 End Function
[497]53#ifdef UNICODE
[411]54 /*!
55 @brief 符号化して得られる文字列の長さを計算する。
[653]56 @param[in] src 対象文字列
[676]57 @return 符号化して得られる文字列の長さ(要素数単位)
[411]58 @date 2007/12/08
59 */
[653]60 Function GetBytesCount(src As String) As Long
61 If ActiveBasic.IsNothing(src) Then
62 Throw New ArgumentNullException("src")
[411]63 End If
[653]64 Return GetBytesCountCore(StrPtr(src), src.Length)
[411]65 End Function
66#endif
[653]67
[676]68Protected
[411]69 /*!
[653]70 @brief GetBytesCountの実装を行う。
71 @param[in] src 対象文字列
[676]72 @param[in] srcCount srcの長さ(要素数単位)
73 @return 符号化して得られる文字列の長さ(要素数単位)
[411]74 @date 2007/12/08
75 */
[682]76 Virtual Function GetBytesCountCore(src As *WCHAR, srcCount As Long) As Long
77 Dim s = New IO.Detail.WriteCountingNullStream
78 GetEncoder().Encode(src, srcCount, s, True)
79 GetBytesCountCore = s.WriteCount
80 If GetBytesCountCore < 0 Then
81 Throw New OverflowException
82 End If
83 End Function
[411]84Public
85 /*!
86 @brief 符号化する。
[653]87 @param[in] src 入力
[676]88 @param[in] srcCount srcの長さ(要素数単位)
[653]89 @param[out] dst 出力
[676]90 @param[in] dstCount dstのバッファの大きさ(要素数単位)
91 @return dstに書き込まれた要素数
[411]92 @date 2007/12/08
93 */
[653]94 Function GetBytes(src As *WCHAR, srcCount As Long, dst As *Byte, dstCount As Long) As Long
95 If src = 0 Then
96 Throw New ArgumentNullException("src")
97 ElseIf dst = 0 Then
98 Throw New ArgumentNullException("dst")
99 ElseIf srcCount < 0 Then
100 Throw New ArgumentOutOfRangeException("srcCount")
101 ElseIf dstCount < 0 Then
102 Throw New ArgumentOutOfRangeException("dstCount")
[411]103 End If
104
[653]105 Return GetBytesCore(src, srcCount, dst, dstCount)
[411]106 End Function
107
[676]108Protected
[411]109 /*!
110 @brief GetBytesの処理を行う。
[653]111 @param[in] src 入力
[676]112 @param[in] srcCount srcの長さ(要素数単位)
[653]113 @param[out] dst 出力
[676]114 @param[in] dstCount dstのバッファの大きさ(要素数単位)
115 @return dstに書き込まれた要素数
[411]116 @exception ArgumentException バッファの大きさが足りない
117 @date 2007/12/08
118 */
[682]119 Virtual Function GetBytesCore(src As *WCHAR, srcCount As Long, dst As *Byte, dstCount As Long) As Long
120 Dim s = New IO.MemoryStream
121 GetEncoder().Encode(src, srcCount, s, True)
122 Dim size = s.Position()
123 If size > (dstCount As QWord) Then
124 Throw New ArgumentException("dstCount")
125 End If
126 GetBytesCore = size As Long
127 memcpy(dst, s.ToPointer(), size As SIZE_T)
128 End Function
[411]129Public
130 /*!
131 @brief 復号して得られる文字列の長さを計算する。
[653]132 @param[in] src 対象文字列
[676]133 @param[in] srcCount srcの長さ(要素数単位)
134 @return 復号して得られる文字列の長さ(要素数単位)
[411]135 @date 2007/12/08
136 */
[653]137 Function GetCharsCount(src As *Byte, srcCount As Long) As Long
138 If src = 0 Then
139 Throw New ArgumentNullException("src")
140 ElseIf srcCount < 0 Then
141 Throw New ArgumentOutOfRangeException("srcCount")
[411]142 End If
[653]143 Return GetCharsCountCore(src, srcCount)
[411]144 End Function
[653]145
[676]146Protected
[411]147 /*!
[653]148 @brief GetCharsCountの処理を行う。
149 @param[in] src 対象文字列
[676]150 @param[in] srcCount srcの長さ(要素数単位)
151 @return 符号化して得られる文字列の長さ(要素数単位)
[411]152 @date 2007/12/08
153 */
[682]154 Virtual Function GetCharsCountCore(src As *Byte, srcCount As Long) As Long
155 Dim s = New IO.MemoryStream(src, srcCount)
156 Dim l = New Collections.Generic.List<WCHAR>
157 GetDecoder().Decode(l, s)
158 GetCharsCountCore = l.Count
159 End Function
[411]160Public
161 /*!
162 @brief 復号する。
[653]163 @param[in] src 入力
[676]164 @param[in] srcCount srcの長さ(要素数単位)
[653]165 @param[out] dst 出力
[676]166 @param[in] dstCount srcのバッファの大きさ(要素数単位)
167 @return dstに書き込まれた要素数
[411]168 @date 2007/12/08
169 */
[653]170 Function GetChars(src As *Byte, srcCount As Long, dst As *WCHAR, dstCount As Long) As Long
171 If dst = 0 Then
172 Throw New ArgumentNullException("dst")
173 ElseIf src = 0 Then
174 Throw New ArgumentNullException("src")
175 ElseIf dstCount < 0 Then
176 Throw New ArgumentOutOfRangeException("dstCount")
177 ElseIf srcCount < 0 Then
178 Throw New ArgumentOutOfRangeException("srcCount")
[411]179 End If
180
[653]181 Return GetCharsCore(src, srcCount, dst, dstCount)
[411]182 End Function
183
[676]184Protected
[411]185 /*!
186 @brief GetCharsの処理を行う。
[653]187 @param[in] src 入力
[676]188 @param[in] srcCount srcの長さ(要素数単位)
[653]189 @param[out] dst 出力
[676]190 @param[in] dstCount dstのバッファの大きさ(要素数単位)
191 @return dstに書き込まれた要素数
[411]192 @exception ArgumentException バッファの大きさが足りない
193 @date 2007/12/08
194 */
[682]195 Virtual Function GetCharsCore(src As *Byte, srcCount As Long, dst As *WCHAR, dstCount As Long) As Long
196 Dim s = New IO.MemoryStream(src, srcCount)
197 Dim l = New Collections.Generic.List<WCHAR>
198 GetDecoder().Decode(l, s)
199 If l.Count > dstCount Then
200 Throw New ArgumentException("dstCount")
201 End If
202 Dim p As *WCHAR
203 p = l
204 memcpy(dst, p, (l.Count As SIZE_T) * 2)
205 End Function
[411]206Public
[497]207#ifdef UNICODE
[411]208 /*!
209 @brief 復号し、Stringで結果を返す。
[653]210 @param[in] src 入力
[676]211 @param[in] srcCount srcの長さ(要素数単位)
[411]212 @return 変換結果の文字列
213 @date 2007/12/08
214 */
[653]215 Function GetString(src As *Byte, srcCount As Long) As String
216 If src = 0 Then
217 Throw New ArgumentNullException("src")
218 ElseIf srcCount < 0 Then
219 Throw New ArgumentOutOfRangeException("srcCount")
[411]220 End If
[653]221 GetString = getStringCore(src, srcCount)
[411]222 End Function
[653]223
[411]224Private
[653]225 Function getStringCore(src As *Byte, srcCount As Long) As String
[411]226 Dim sb = New StringBuilder
[653]227 Dim bufCount = GetMaxCharCount(srcCount)
228 sb.Length = bufCount
229 Dim len = GetCharsCore(src, srcCount, StrPtr(sb), bufCount)
[411]230 sb.Length = len
[653]231 getStringCore = sb.ToString()
[411]232 End Function
233#endif
234
235Public
236 /*!
[676]237 @brief 復号器を取得する。
[411]238 */
239 Abstract Function GetDecoder() As Decoder
240
241 /*!
[676]242 @brief 符号器を取得する。
[411]243 */
244 Abstract Function GetEncoder() As Encoder
245
246 /*!
247 @brief ある長さの文字列を符号化して得られるバイト列の最大の長さを返す。
248 */
[653]249 Abstract Function GetMaxByteCount(srcCount As Long) As Long
[411]250
251 /*!
252 @brief ある長さのバイト列を復号して得られる文字列の最大の長さを返す。
253 */
[653]254 Abstract Function GetMaxCharCount(srcCount As Long) As Long
[411]255
256 /*!
257 @brief 符号化された文字列の先頭につける識別文字列の取得
[653]258 ようするにUTFのBOM。
[411]259 */
260 Virtual Function GetPreamble() As *Byte
261 Return 0
262 End Function
263
264 /*!
[676]265 @brief GetPreambleの配列の要素数。
[411]266 */
267 Virtual Function GetPreambleLength() As Long
268 Return 0
269 End Function
270
[676]271Public
[653]272' Abstract Function BodyName() As String
273' Abstract Function HeaderName() As String
[411]274
275 /*!
276 @brief コードページの取得。
277 */
278' Abstract Function CodePage() As Long
279 /*!
280 @brief 最も厳密に対応するWindowsコードページの取得。
281 */
282' Abstract Function WindowsCodePage() As Long
283
284Public
285 /*!
286 @brief この符号化形式の名前の取得。
287 */
[653]288' Abstract Function EncodingName() As String
[411]289
290 /*!
291 @brief この符号化形式のIANA登録名の取得。
292 */
[653]293' Abstract Function WebName() As String
[411]294
295' Abstract Function IsBrowserDisplay() As Boolean
296' Abstract Function IsBrowserSave() As Boolean
297' Abstract Function IsMailNewsDisplay() As Boolean
298' Abstract Function IsMailNewsSave() As Boolean
299
300 /*!
301 @brief この符号化形式が、1バイト文字だけを使う(複数バイト文字を使わない)かどうか。
302 */
[653]303' Abstract Function IsSingleByte() As Boolean
[411]304
305 'GetPreamble
306
307 /*!
308 @brief ある符号化文字列から別の符号化文字列へ変換する。
309 @param[in] srcEncoding 入力の符号化方式
310 @param[in] dstEncoding 出力の符号化方式
311 @param[in] bytes 入力文字列
312 @param[in] size バイト単位での文字列の長さ
313 @return 出力文字列
314 @exception ArgumentNullException srcEncoding, dstEncoding, bytesの少なくとも1つ以上がNothing/NULLのとき。
315 @exception ArgumentOutOfRangeException sizeが明らかに範囲外(負の値など)のとき。
316 */
[653]317' Static Function Convert(srcEncoding As Encoding, dstEncoding As Encoding, bytes As *Byte, size As Long) As *Byte
318' End Function
[411]319
[653]320' Static Function Convert(srcEncoding As Encoding, dstEncoding As Encoding, bytes As *Byte, index As Long, count As Long) As *Byte
321' End Function
[411]322
323 /*!
324 @brief 指定したコードページ用のEncodingインスタンスの取得。
325 */
[653]326' Static Function GetEncoding(codepage As Long) As Encoding
[411]327' End Function
328 /*!
329 @brief 指定した符号化形式名用のEncodingインスタンスの取得。
330 */
[653]331' Static Function GetEncoding(name As String) As Encoding
[411]332' End Function
333 /*!
[653]334 @brief システムで標準のANSIコードページ用のEncodingインスタンスの取得。
[411]335 */
336 Static Function Default() As Encoding
337 End Function
338 /*!
339 @brief UTF-8用のEncodingインスタンスの取得。
340 */
341 Static Function UTF8() As Encoding
342 End Function
343 /*!
344 @brief UTF-16LE用のEncodingインスタンスの取得。
345 */
346 Static Function UTF16() As Encoding
347 End Function
348 /*!
349 @brief UTF-16BE用のEncodingインスタンスの取得。
350 */
351 Static Function UTF16BE() As Encoding
352 End Function
353End Class
354
355/*!
356@brief 復号を行うクラス
[676]357@date 2009/01/12
[411]358@auther Egtra
[676]359内部処理用
[411]360*/
361Class Decoder
362Public
[676]363 Function Decode(dst As Collections.Generic.List<WCHAR>, st As IO.Stream) As Boolean
364 Decode = DecodeImpl(dst, st)
[411]365 End Function
366
367Protected
[676]368 Abstract Function DecodeImpl(dst As Collections.Generic.List<WCHAR>, s As IO.Stream) As Boolean
[411]369End Class
370
371/*!
372@brief 符号化を行うクラス
[676]373@date 2009/01/12
[411]374@auther Egtra
[676]375内部処理用
[411]376*/
377Class Encoder
378Public
[676]379 Sub Encode(src As *WCHAR, size As SIZE_T, s As IO.Stream, last As Boolean)
380 EncodeImpl(src, size, s, last)
[411]381 End Sub
382
[653]383Protected
[676]384 Abstract Sub EncodeImpl(src As *WCHAR, size As SIZE_T, s As IO.Stream, last As Boolean)
[653]385End Class
386
387Enum NormalizationForm
388 FormC
389 FormD
390 FormKC
391 FormKD
392End Enum
393
394Namespace Detail
395
396/*!
397@brief WideCharToMultiByte/MultiByteToWideCharで変換を行うエンコーディング。
398DBCS/SBCS限定。UTF-8やUTF-7は非対応。
399*/
400Class WindowsCodePageEncoding
401 Inherits Encoding
402Public
403 Sub WindowsCodePageEncoding(codepage As DWord)
404 cp = codepage
405 End Sub
406
407 Override Function GetHashCode() As Long
408 GetHashCode = cp As Long
409 End Function
410
411 Override Function Equals(x As Object) As Boolean
412 If GetType().Equals(x.GetType()) Then
413 Dim xe = x As WindowsCodePageEncoding
414 Equals = cp = xe.cp
415 Else
416 Equals = False
417 End If
418 End Function
419
[676]420 Override Function GetDecoder() As Decoder
421 GetDecoder = New WindowsCodePageDecoder(cp)
422 End Function
423
424 Override Function GetEncoder() As Encoder
425 GetEncoder = New WindowsCodePageEncoder(cp)
426 End Function
427
[411]428 /*!
[653]429 @brief ある長さの文字列を符号化して得られるバイト列の最大の長さを返す。
[411]430 */
[653]431 Override Function GetMaxByteCount(srcCount As Long) As Long
432 GetMaxByteCount = srcCount * 2
[411]433 End Function
434
435 /*!
[653]436 @brief ある長さのバイト列を復号して得られる文字列の最大の長さを返す。
[411]437 */
[653]438 Override Function GetMaxCharCount(srcCount As Long) As Long
439 GetMaxCharCount = srcCount
440 End Function
441
[676]442Protected
443 Override Function GetBytesCountCore(src As *WCHAR, srcCount As Long) As Long
444 GetBytesCountCore = WideCharToMultiByte(cp, 0, src, srcCount, 0, 0, 0, 0)
445 If srcCount <> 0 And GetBytesCountCore = 0 Then
446 ActiveBasic.Windows.ThrowWithLastError()
447 End If
448 End Function
449
450 Override Function GetBytesCore(src As *WCHAR, srcCount As Long, dst As *Byte, dstCount As Long) As Long
451 GetBytesCore = WideCharToMultiByte(cp, 0, src, srcCount, dst As PCSTR, dstCount, 0, 0)
452 If srcCount <> 0 And GetBytesCore = 0 Then
453 ActiveBasic.Windows.ThrowWithLastError()
454 End If
455 End Function
456
457 Override Function GetCharsCountCore(src As *Byte, srcCount As Long) As Long
458 GetCharsCountCore = MultiByteToWideChar(cp, 0, src As PCSTR, srcCount, 0, 0)
459 If srcCount <> 0 And GetCharsCountCore = 0 Then
460 ActiveBasic.Windows.ThrowWithLastError()
461 End If
462 End Function
463
464 Override Function GetCharsCore(src As *Byte, srcCount As Long, dst As *WCHAR, dstCount As Long) As Long
465 GetCharsCore = MultiByteToWideChar(cp, 0, src As PCSTR, srcCount, dst, dstCount)
466 If srcCount <> 0 And GetCharsCore = 0 Then
467 ActiveBasic.Windows.ThrowWithLastError()
468 End If
469 End Function
470
[653]471Private
472 cp As DWord
473End Class
474
[676]475/*!
476@brief WideCharToMultiByteで復号化を行うクラス
477@date 2009/01/12
478@auther Egtra
479内部処理用
480*/
[653]481Class WindowsCodePageEncoder
482 Inherits Encoder
483Public
484 Sub WindowsCodePageEncoder(codepage As DWord)
485 cp = codepage
[411]486 End Sub
[653]487
[411]488Protected
[676]489 Override Sub EncodeImpl(src As *WCHAR, size As SIZE_T, s As IO.Stream, last As Boolean)
490 ' サロゲートペアや結合文字列 (Combining Character Sequence)の途中でバッファが途切れている場合に対応する
491 ' ToDo: エラー処理
492 Dim mbLen = WideCharToMultiByte(cp, 0, src, size, 0, 0, 0, 0)
493 Dim mbBuf = GC_malloc_atomic(mbLen)
494 WideCharToMultiByte(cp, 0, src, size, mbBuf, mbLen, 0, 0)
495 s.Write(mbBuf, 0, mbLen)
[653]496 End Sub
497
[411]498Private
[653]499 cp As DWord
[411]500End Class
501
[676]502/*!
503@brief MultiByteToWideCharで復号化を行うクラス
504@date 2009/01/12
505@auther Egtra
506内部処理用
507*/
[653]508Class WindowsCodePageDecoder
509 Inherits Decoder
510Public
511 Sub WindowsCodePageDecoder(codepage As DWord)
512 cp = codepage
513 End Sub
[411]514
[653]515Protected
[676]516 Override Function DecodeImpl(dst As Collections.Generic.List<WCHAR>, s As IO.Stream) As Boolean
517 Dim i As Long
518 For i = 0 To DefalultDecodingBufferSize - 1 'ELM
519 Dim len As Long
[655]520 Dim buf[1] As CHAR
[676]521 Dim t = s.ReadByte()
522 If t = -1 Then
523 DecodeImpl = False
524 Exit Function
[655]525 End If
[676]526 buf[0] = t As CHAR
527 If IsDBCSLeadByteEx(cp, buf[0]) Then
528 t = s.ReadByte()
529 If t = -1 Then
530 dst.Add(&hfffd As WCHAR)
531 DecodeImpl = False
532 Exit For
[655]533 End If
[676]534 buf[1] = t As CHAR
535 len = 2
536 Else
537 len = 1
[655]538 End If
[676]539 Dim wc As WCHAR
540 If MultiByteToWideChar(cp, 0, buf, len, VarPtr(wc), 1) = 0 Then
541 dst.Add(&hFFFD As WCHAR)
542 Else
543 dst.Add(wc)
[655]544 End If
[676]545 Next
546 DecodeImpl = True
[653]547 End Function
548
549Private
550 cp As DWord
[411]551End Class
552
[676]553Const DefalultDecodingBufferSize = 16384
554
[653]555End Namespace
556
[411]557End Namespace 'Text
558End Namespace 'System
Note: See TracBrowser for help on using the repository browser.