/*! @file Classes/System/Text/Encoding.ab @brief Encodingクラスとそれに関係するクラスなどの宣言・定義 */ Namespace System Namespace Text /*! @brief 各種の文字符号化(エンコーディング)を行うためのクラス @date 2007/12/07 @auther Egtra なお、このクラスで、文字列の長さやバッファの大きさを指定するときには、 1 WCHAR = 2バイト(UTF-16符号単位)、1 Byte = 1バイトの単位で指定する。 */ Class Encoding Implements ICloneable Public /*! @brief 簡易的複製を作成する。 */ Virtual Function Clone() As Object Clone = This End Function ' Override Function Equals(y As Object) As Boolean ' End Function ' Override Function GetHashCode() As Long ' End Function Public Sub Encoding() End Sub /*! @brief 符号化して得られる文字列の長さを計算する。 @param[in] src 対象文字列 @param[in] srcCount srcの長さ(要素数単位) @return 符号化して得られる文字列の長さ(要素数単位) @date 2007/12/08 */ Function GetBytesCount(src As *WCHAR, srcCount As Long) As Long If src = 0 Then Throw New ArgumentNullException("src") ElseIf srcCount < 0 Then Throw New ArgumentOutOfRangeException("srcCount") End If Return GetBytesCountCore(src, srcCount) End Function #ifdef UNICODE /*! @brief 符号化して得られる文字列の長さを計算する。 @param[in] src 対象文字列 @return 符号化して得られる文字列の長さ(要素数単位) @date 2007/12/08 */ Function GetBytesCount(src As String) As Long If ActiveBasic.IsNothing(src) Then Throw New ArgumentNullException("src") End If Return GetBytesCountCore(StrPtr(src), src.Length) End Function #endif Protected /*! @brief GetBytesCountの実装を行う。 @param[in] src 対象文字列 @param[in] srcCount srcの長さ(要素数単位) @return 符号化して得られる文字列の長さ(要素数単位) @date 2007/12/08 */ Virtual Function GetBytesCountCore(src As *WCHAR, srcCount As Long) As Long Dim s = New IO.Detail.WriteCountingNullStream GetEncoder().Encode(src, srcCount, s, True) GetBytesCountCore = s.WriteCount If GetBytesCountCore < 0 Then Throw New OverflowException End If End Function Public /*! @brief 符号化する。 @param[in] src 入力 @param[in] srcCount srcの長さ(要素数単位) @param[out] dst 出力 @param[in] dstCount dstのバッファの大きさ(要素数単位) @return dstに書き込まれた要素数 @date 2007/12/08 */ Function GetBytes(src As *WCHAR, srcCount As Long, dst As *Byte, dstCount As Long) As Long If src = 0 Then Throw New ArgumentNullException("src") ElseIf dst = 0 Then Throw New ArgumentNullException("dst") ElseIf srcCount < 0 Then Throw New ArgumentOutOfRangeException("srcCount") ElseIf dstCount < 0 Then Throw New ArgumentOutOfRangeException("dstCount") End If Return GetBytesCore(src, srcCount, dst, dstCount) End Function Protected /*! @brief GetBytesの処理を行う。 @param[in] src 入力 @param[in] srcCount srcの長さ(要素数単位) @param[out] dst 出力 @param[in] dstCount dstのバッファの大きさ(要素数単位) @return dstに書き込まれた要素数 @exception ArgumentException バッファの大きさが足りない @date 2007/12/08 */ Virtual Function GetBytesCore(src As *WCHAR, srcCount As Long, dst As *Byte, dstCount As Long) As Long Dim s = New IO.MemoryStream GetEncoder().Encode(src, srcCount, s, True) Dim size = s.Position() If size > (dstCount As QWord) Then Throw New ArgumentException("dstCount") End If GetBytesCore = size As Long memcpy(dst, s.ToPointer(), size As SIZE_T) End Function Public /*! @brief 復号して得られる文字列の長さを計算する。 @param[in] src 対象文字列 @param[in] srcCount srcの長さ(要素数単位) @return 復号して得られる文字列の長さ(要素数単位) @date 2007/12/08 */ Function GetCharsCount(src As *Byte, srcCount As Long) As Long If src = 0 Then Throw New ArgumentNullException("src") ElseIf srcCount < 0 Then Throw New ArgumentOutOfRangeException("srcCount") End If Return GetCharsCountCore(src, srcCount) End Function Protected /*! @brief GetCharsCountの処理を行う。 @param[in] src 対象文字列 @param[in] srcCount srcの長さ(要素数単位) @return 符号化して得られる文字列の長さ(要素数単位) @date 2007/12/08 */ Virtual Function GetCharsCountCore(src As *Byte, srcCount As Long) As Long Dim s = New IO.MemoryStream(src, srcCount) Dim l = New Collections.Generic.List GetDecoder().Decode(l, s) GetCharsCountCore = l.Count End Function Public /*! @brief 復号する。 @param[in] src 入力 @param[in] srcCount srcの長さ(要素数単位) @param[out] dst 出力 @param[in] dstCount srcのバッファの大きさ(要素数単位) @return dstに書き込まれた要素数 @date 2007/12/08 */ Function GetChars(src As *Byte, srcCount As Long, dst As *WCHAR, dstCount As Long) As Long If dst = 0 Then Throw New ArgumentNullException("dst") ElseIf src = 0 Then Throw New ArgumentNullException("src") ElseIf dstCount < 0 Then Throw New ArgumentOutOfRangeException("dstCount") ElseIf srcCount < 0 Then Throw New ArgumentOutOfRangeException("srcCount") End If Return GetCharsCore(src, srcCount, dst, dstCount) End Function Protected /*! @brief GetCharsの処理を行う。 @param[in] src 入力 @param[in] srcCount srcの長さ(要素数単位) @param[out] dst 出力 @param[in] dstCount dstのバッファの大きさ(要素数単位) @return dstに書き込まれた要素数 @exception ArgumentException バッファの大きさが足りない @date 2007/12/08 */ Virtual Function GetCharsCore(src As *Byte, srcCount As Long, dst As *WCHAR, dstCount As Long) As Long Dim s = New IO.MemoryStream(src, srcCount) Dim l = New Collections.Generic.List GetDecoder().Decode(l, s) If l.Count > dstCount Then Throw New ArgumentException("dstCount") End If Dim p As *WCHAR p = l memcpy(dst, p, (l.Count As SIZE_T) * 2) End Function Public #ifdef UNICODE /*! @brief 復号し、Stringで結果を返す。 @param[in] src 入力 @param[in] srcCount srcの長さ(要素数単位) @return 変換結果の文字列 @date 2007/12/08 */ Function GetString(src As *Byte, srcCount As Long) As String If src = 0 Then Throw New ArgumentNullException("src") ElseIf srcCount < 0 Then Throw New ArgumentOutOfRangeException("srcCount") End If GetString = getStringCore(src, srcCount) End Function Private Function getStringCore(src As *Byte, srcCount As Long) As String Dim sb = New StringBuilder Dim bufCount = GetMaxCharCount(srcCount) sb.Length = bufCount Dim len = GetCharsCore(src, srcCount, StrPtr(sb), bufCount) sb.Length = len getStringCore = sb.ToString() End Function #endif Public /*! @brief 復号器を取得する。 */ Abstract Function GetDecoder() As Decoder /*! @brief 符号器を取得する。 */ Abstract Function GetEncoder() As Encoder /*! @brief ある長さの文字列を符号化して得られるバイト列の最大の長さを返す。 */ Abstract Function GetMaxByteCount(srcCount As Long) As Long /*! @brief ある長さのバイト列を復号して得られる文字列の最大の長さを返す。 */ Abstract Function GetMaxCharCount(srcCount As Long) As Long /*! @brief 符号化された文字列の先頭につける識別文字列の取得 ようするにUTFのBOM。 */ Virtual Function GetPreamble() As *Byte Return 0 End Function /*! @brief GetPreambleの配列の要素数。 */ Virtual Function GetPreambleLength() As Long Return 0 End Function Public ' Abstract Function BodyName() As String ' Abstract Function HeaderName() As String /*! @brief コードページの取得。 */ ' Abstract Function CodePage() As Long /*! @brief 最も厳密に対応するWindowsコードページの取得。 */ ' Abstract Function WindowsCodePage() As Long Public /*! @brief この符号化形式の名前の取得。 */ ' Abstract Function EncodingName() As String /*! @brief この符号化形式のIANA登録名の取得。 */ ' Abstract Function WebName() As String ' Abstract Function IsBrowserDisplay() As Boolean ' Abstract Function IsBrowserSave() As Boolean ' Abstract Function IsMailNewsDisplay() As Boolean ' Abstract Function IsMailNewsSave() As Boolean /*! @brief この符号化形式が、1バイト文字だけを使う(複数バイト文字を使わない)かどうか。 */ ' Abstract Function IsSingleByte() As Boolean 'GetPreamble /*! @brief ある符号化文字列から別の符号化文字列へ変換する。 @param[in] srcEncoding 入力の符号化方式 @param[in] dstEncoding 出力の符号化方式 @param[in] bytes 入力文字列 @param[in] size バイト単位での文字列の長さ @return 出力文字列 @exception ArgumentNullException srcEncoding, dstEncoding, bytesの少なくとも1つ以上がNothing/NULLのとき。 @exception ArgumentOutOfRangeException sizeが明らかに範囲外(負の値など)のとき。 */ ' Static Function Convert(srcEncoding As Encoding, dstEncoding As Encoding, bytes As *Byte, size As Long) As *Byte ' End Function ' Static Function Convert(srcEncoding As Encoding, dstEncoding As Encoding, bytes As *Byte, index As Long, count As Long) As *Byte ' End Function /*! @brief 指定したコードページ用のEncodingインスタンスの取得。 */ ' Static Function GetEncoding(codepage As Long) As Encoding ' End Function /*! @brief 指定した符号化形式名用のEncodingインスタンスの取得。 */ ' Static Function GetEncoding(name As String) As Encoding ' End Function /*! @brief システムで標準のANSIコードページ用のEncodingインスタンスの取得。 */ Static Function Default() As Encoding End Function /*! @brief UTF-8用のEncodingインスタンスの取得。 */ Static Function UTF8() As Encoding End Function /*! @brief UTF-16LE用のEncodingインスタンスの取得。 */ Static Function UTF16() As Encoding End Function /*! @brief UTF-16BE用のEncodingインスタンスの取得。 */ Static Function UTF16BE() As Encoding End Function End Class /*! @brief 復号を行うクラス @date 2009/01/12 @auther Egtra 内部処理用 */ Class Decoder Public /*! @brief 復号する。 @param[out] dst 出力先 @param[in] s 入力元 @return sを最後 (EOF) まで読んだらFalse、まだあればTrue。 */ Function Decode(dst As Collections.Generic.List, s As IO.Stream) As Boolean Decode = DecodeImpl(dst, s) End Function Protected Abstract Function DecodeImpl(dst As Collections.Generic.List, s As IO.Stream) As Boolean End Class /*! @brief 符号化を行うクラス @date 2009/01/12 @auther Egtra 内部処理用 */ Class Encoder Public Sub Encode(src As *WCHAR, size As SIZE_T, s As IO.Stream, last As Boolean) EncodeImpl(src, size, s, last) End Sub Protected Abstract Sub EncodeImpl(src As *WCHAR, size As SIZE_T, s As IO.Stream, last As Boolean) End Class Enum NormalizationForm FormC FormD FormKC FormKD End Enum Namespace Detail /*! @brief WideCharToMultiByte/MultiByteToWideCharで変換を行うエンコーディング。 DBCS/SBCS限定。UTF-8やUTF-7は非対応。 */ Class WindowsCodePageEncoding Inherits Encoding Public Sub WindowsCodePageEncoding(codepage As DWord) cp = codepage End Sub Override Function GetHashCode() As Long GetHashCode = cp As Long End Function Override Function Equals(x As Object) As Boolean If GetType().Equals(x.GetType()) Then Dim xe = x As WindowsCodePageEncoding Equals = cp = xe.cp Else Equals = False End If End Function Override Function GetDecoder() As Decoder GetDecoder = New WindowsCodePageDecoder(cp) End Function Override Function GetEncoder() As Encoder GetEncoder = New WindowsCodePageEncoder(cp) End Function /*! @brief ある長さの文字列を符号化して得られるバイト列の最大の長さを返す。 */ Override Function GetMaxByteCount(srcCount As Long) As Long GetMaxByteCount = srcCount * 2 End Function /*! @brief ある長さのバイト列を復号して得られる文字列の最大の長さを返す。 */ Override Function GetMaxCharCount(srcCount As Long) As Long GetMaxCharCount = srcCount End Function Protected Override Function GetBytesCountCore(src As *WCHAR, srcCount As Long) As Long GetBytesCountCore = WideCharToMultiByte(cp, 0, src, srcCount, 0, 0, 0, 0) If srcCount <> 0 And GetBytesCountCore = 0 Then ActiveBasic.Windows.ThrowWithLastError() End If End Function Override Function GetBytesCore(src As *WCHAR, srcCount As Long, dst As *Byte, dstCount As Long) As Long GetBytesCore = WideCharToMultiByte(cp, 0, src, srcCount, dst As PCSTR, dstCount, 0, 0) If srcCount <> 0 And GetBytesCore = 0 Then ActiveBasic.Windows.ThrowWithLastError() End If End Function Override Function GetCharsCountCore(src As *Byte, srcCount As Long) As Long GetCharsCountCore = MultiByteToWideChar(cp, 0, src As PCSTR, srcCount, 0, 0) If srcCount <> 0 And GetCharsCountCore = 0 Then ActiveBasic.Windows.ThrowWithLastError() End If End Function Override Function GetCharsCore(src As *Byte, srcCount As Long, dst As *WCHAR, dstCount As Long) As Long GetCharsCore = MultiByteToWideChar(cp, 0, src As PCSTR, srcCount, dst, dstCount) If srcCount <> 0 And GetCharsCore = 0 Then ActiveBasic.Windows.ThrowWithLastError() End If End Function Private cp As DWord End Class /*! @brief WideCharToMultiByteで復号化を行うクラス @date 2009/01/12 @auther Egtra 内部処理用 */ Class WindowsCodePageEncoder Inherits Encoder Public Sub WindowsCodePageEncoder(codepage As DWord) cp = codepage End Sub Protected Override Sub EncodeImpl(src As *WCHAR, size As SIZE_T, s As IO.Stream, last As Boolean) ' サロゲートペアや結合文字列 (Combining Character Sequence)の途中でバッファが途切れている場合に対応する ' ToDo: エラー処理 Dim mbLen = WideCharToMultiByte(cp, 0, src, size As Long, 0, 0, 0, 0) Dim mbBuf = GC_malloc_atomic(mbLen) WideCharToMultiByte(cp, 0, src, size As Long, mbBuf, mbLen, 0, 0) s.Write(mbBuf, 0, mbLen) End Sub Private cp As DWord End Class /*! @brief MultiByteToWideCharで復号化を行うクラス @date 2009/01/12 @auther Egtra 内部処理用 */ Class WindowsCodePageDecoder Inherits Decoder Public Sub WindowsCodePageDecoder(codepage As DWord) cp = codepage End Sub Protected Override Function DecodeImpl(dst As Collections.Generic.List, s As IO.Stream) As Boolean Dim i As Long For i = 0 To DefalultDecodingBufferSize - 1 'ELM Dim len As Long Dim buf[1] As CHAR Dim t = s.ReadByte() If t = -1 Then DecodeImpl = False Exit Function End If buf[0] = t As CHAR If IsDBCSLeadByteEx(cp, buf[0]) Then t = s.ReadByte() If t = -1 Then dst.Add(&hfffd As WCHAR) Exit Function End If buf[1] = t As CHAR len = 2 Else len = 1 End If Dim wc As WCHAR If MultiByteToWideChar(cp, 0, buf, len, VarPtr(wc), 1) = 0 Then dst.Add(&hFFFD As WCHAR) Else dst.Add(wc) End If Next DecodeImpl = True End Function Private cp As DWord End Class Const DefalultDecodingBufferSize = 16384 End Namespace End Namespace 'Text End Namespace 'System