/*! @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 Private /*! @brief GetBytesCountの実装を行う。 @param[in] src 対象文字列 @param[in] srcCount srcの長さ @return 符号化して得られる文字列の長さ @date 2007/12/08 */ Function GetBytesCountCore(src As *WCHAR, srcCount As Long) As Long Dim enc = GetEncoder() GetBytesCountCore = enc.GetBytesCount(src, srcCount, True) 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 Private /*! @brief GetBytesの処理を行う。 @param[in] src 入力 @param[in] srcCount srcの長さ @param[out] dst 出力 @param[in] dstCount dstのバッファの大きさ @return dstに書き込まれたバイト数 @exception ArgumentException バッファの大きさが足りない @date 2007/12/08 */ Function GetBytesCore(src As *WCHAR, srcCount As Long, dst As *Byte, dstCount As Long) As Long GetBytesCore = GetEncoder().GetBytes(src, srcCount, dst, dstCount, True) 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 Private /*! @brief GetCharsCountの処理を行う。 @param[in] src 対象文字列 @param[in] srcCount srcの長さ @return 符号化して得られる文字列の長さ @date 2007/12/08 */ Function GetCharsCountCore(src As *Byte, srcCount As Long) As Long Dim dec = GetDecoder() GetCharsCountCore = dec.GetCharsCount(src, srcCount, True) 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 Private /*! @brief GetCharsの処理を行う。 @param[in] src 入力 @param[in] srcCount srcの長さ @param[out] dst 出力 @param[in] dstCount dstのバッファの大きさ @return dstに書き込まれたバイト数 @exception ArgumentException バッファの大きさが足りない @date 2007/12/08 */ Function GetCharsCore(src As *Byte, srcCount As Long, dst As *WCHAR, dstCount As Long) As Long GetCharsCore = GetDecoder().GetChars(src, srcCount, dst, dstCount, True) 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 ' 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 2007/12/19 @auther Egtra */ Class Decoder Public /*! @brief 変換する @param[in] src 入力 @param[in] srcCount 入力要素数 @param[out] dst 出力 @param[in] dstCount 出力要素数 @param[in] flush 終了後に内部状態を初期化するかどうか @param[out] srcUsed 使用された入力の要素数 @param[out] dstUsed 出力の内、実際に書き込まれた要素数 @param[out] completed 入力の全ての文字が変換に使われたかどうか */ Sub Convert(src As *Byte, srcCount As Long, dst As *WCHAR, dstCount As Long, flush As Boolean, ByRef srcUsed As Long, ByRef dstUsed As Long, ByRef completed As Boolean) If src = 0 Then Throw New ArgumentNullException("src") ElseIf srcCount < 0 Then Throw New ArgumentOutOfRangeException("srcCount") ElseIf dst = 0 Then Throw New ArgumentNullException("dst") ElseIf dstCount < 0 Then Throw New ArgumentOutOfRangeException("dstCount") End If ConvertCore(src, srcCount, dst, dstCount, flush, srcUsed, dstUsed, completed) End Sub /*! @brief 変換する @param[in] src 入力 @param[in] srcCount 入力要素数 @param[out] dst 出力 @param[in] dstCount 出力要素数 @param[in] flush 終了後に内部状態を初期化するかどうか @return 出力の内、実際に書き込まれた要素数 */ Function GetChars(src As *Byte, srcCount As Long, dst As *WCHAR, dstCount As Long, flush As Boolean) As Long Dim srcUsed As Long Dim completed As Boolean Convert(src, srcCount, dst, dstCount, flush, srcUsed, GetChars, completed) If srcUsed < srcCount Then Throw New ArgumentException("src", "buffer is too small") End If End Function /*! @brief 変換すると何文字になるか数える @param[in] src 入力 @param[in] srcCount 入力要素数 @param[in] flush 終了後に内部状態を初期化するとして計算するかどうか @return 必要な文字数 */ Function GetCharsCount(src As *Byte, srcCount As Long, flush As Boolean) As Long If src = 0 Then Throw New ArgumentNullException("src") ElseIf srcCount < 0 Then Throw New ArgumentOutOfRangeException("srcCount") End If GetCharsCountCore(src, srcCount, flush) End Function /*! @brief 内部状態を初期状態に戻す */ Virtual Sub Reset() End Sub Protected /*! @brief 実際に変換する @param[in] src 入力 @param[in] srcCount 入力要素数 @param[out] dst 出力 @param[in] dstCount 出力要素数 @param[in] flush 終了後に内部状態を初期化するかどうか @param[out] dstUsed 使用された入力の要素数 @param[out] srcUsed 出力の内、実際に書き込まれた要素数 @param[out] completed 入力の全ての文字が変換に使われたかどうか */ Abstract Sub ConvertCore(src As *Byte, srcCount As Long, dst As *WCHAR, dstCount As Long, flush As Boolean, ByRef srcUsed As Long, ByRef dstUsed As Long, ByRef completed As Boolean) /*! @brief 変換すると何文字になるか数える @param[in] src 入力 @param[in] srcCount 入力要素数 @param[in] flush 終了後に内部状態を初期化するとして計算するかどうか @return 必要な文字数 */ Abstract Function GetCharsCountCore(src As *Byte, srcCount As Long, flush As Boolean) As Long End Class /*! @brief 符号化を行うクラス @date 2007/12/19 @auther Egtra */ Class Encoder Public /*! @brief 変換する @param[in] src 入力 @param[in] srcCount 入力要素数 @param[out] dst 出力 @param[in] dstCount 出力要素数 @param[in] flush 終了後に内部状態を初期化するかどうか @param[out] srcUsed 使用された入力の要素数 @param[out] dstUsed 出力の内、実際に書き込まれた要素数 @param[out] completed 入力の全ての文字が変換に使われたかどうか */ Sub Convert(src As *WCHAR, srcCount As Long, dst As *Byte, dstCount As Long, flush As Boolean, ByRef srcUsed As Long, ByRef dstUsed As Long, ByRef completed As Boolean) If src = 0 Then Throw New ArgumentNullException("src") ElseIf srcCount < 0 Then Throw New ArgumentOutOfRangeException("srcCount") ElseIf dst = 0 Then Throw New ArgumentNullException("dst") ElseIf dstCount < 0 Then Throw New ArgumentOutOfRangeException("dstCount") End If ConvertCore(src, srcCount, dst, dstCount, flush, srcUsed, dstUsed, completed) End Sub /*! @brief 変換する @param[in] src 入力 @param[in] srcCount 入力要素数 @param[out] dst 出力 @param[in] dstCount 出力要素数 @param[in] flush 終了後に内部状態を初期化するかどうか @return 出力の内、実際に書き込まれた要素数 */ Function GetBytes(src As *WCHAR, srcCount As Long, dst As *Byte, dstCount As Long, flush As Boolean) As Long Dim srcUsed As Long Dim completed As Boolean Convert(src, srcCount, dst, dstCount, flush, srcUsed, GetBytes, completed) If srcUsed < srcCount Then Throw New ArgumentException("src", "buffer is too small") End If End Function /*! @brief 変換すると何文字になるか数える @param[in] src 入力 @param[in] srcCount 入力要素数 @param[in] flush 終了後に内部状態を初期化するとして計算するかどうか @return 必要な文字数 */ Function GetBytesCount(src As *WCHAR, srcCount As Long, flush As Boolean) As Long If src = 0 Then Throw New ArgumentNullException("src") ElseIf srcCount < 0 Then Throw New ArgumentOutOfRangeException("srcCount") End If GetBytesCountCore(src, srcCount, flush) End Function /*! @brief 内部状態を初期状態に戻す */ Virtual Sub Reset() End Sub Protected /*! @brief 実際に変換する @param[in] src 入力 @param[in] srcCount 入力要素数 @param[out] dst 出力 @param[in] dstCount 出力要素数 @param[in] flush 終了後に内部状態を初期化するかどうか @param[out] dstUsed 使用された入力の要素数 @param[out] srcUsed 出力の内、実際に書き込まれた要素数 @param[out] completed 入力の全ての文字が変換に使われたかどうか */ Abstract Sub ConvertCore(src As *WCHAR, srcCount As Long, dst As *Byte, dstCount As Long, flush As Boolean, ByRef dstUsed As Long, ByRef srcUsed As Long, ByRef completed As Boolean) /*! @brief 変換すると何文字になるか数える @param[in] src 入力 @param[in] srcCount 入力要素数 @param[in] flush 終了後に内部状態を初期化するとして計算するかどうか @return 必要な文字数 */ Abstract Function GetBytesCountCore(src As *WCHAR, srcCount As Long, flush As Boolean) As Long 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 /*! @brief 符号器を取得する。 */ Override Function GetDecoder() As Decoder GetDecoder = New WindowsCodePageDecoder(cp) End Function /*! @brief 復号器を取得する。 */ Override Function GetEncoder() As Encoder GetEncoder = New WindowsCodePageEncoder(cp) End Function 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 /*! @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 Private cp As DWord End Class Class WindowsCodePageEncoder Inherits Encoder Public Sub WindowsCodePageEncoder(codepage As DWord) cp = codepage End Sub Override Sub Reset() nextByte = 0 End Sub Protected Override Sub ConvertCore(src As *WCHAR, srcCount As Long, dst As *Byte, dstCount As Long, flush As Boolean, ByRef srcUsed As Long, ByRef dstUsed As Long, ByRef completed As Boolean) Dim srcPos = 0 As Long Dim dstPos = 0 As Long If dstCount > 0 And nextByte <> 0 Then dst[0] = nextByte nextByte = 0 dstPos++ End If While srcPos < srcCount And dstPos < srcCount Dim buf[1] As CHAR Dim len = WideCharToMultiByte(cp, WC_COMPOSITECHECK Or WC_DEFAULTCHAR, VarPtr(src[srcPos]), 1, buf, Len(buf), 0, 0) If len = 0 Then ActiveBasic.Windows.ThrowWithLastError() End If dst[dstPos] = buf[0] As Byte If len = 2 Then If dstCount = 1 Then nextByte = buf[1] As Byte Exit While End If dstPos++ dst[dstPos] = buf[1] As Byte nextByte = 0 End If srcPos++ dstPos++ Wend srcUsed = srcPos dstUsed = dstPos completed = (srcPos = srcCount And dstPos = srcCount And nextByte = 0) End Sub Override Function GetBytesCountCore(src As *WCHAR, srcCount As Long, flush As Boolean) As Long End Function Private cp As DWord nextByte As Byte End Class Class WindowsCodePageDecoder Inherits Decoder Public Sub WindowsCodePageDecoder(codepage As DWord) cp = codepage End Sub Protected Override Sub ConvertCore(src As *Byte, srcCount As Long, dst As *WCHAR, dstCount As Long, flush As Boolean, ByRef srcUsed As Long, ByRef dstUsed As Long, ByRef completed As Boolean) End Sub Override Function GetCharsCountCore(src As *Byte, srcCount As Long, flush As Boolean) As Long End Function Private cp As DWord End Class End Namespace End Namespace 'Text End Namespace 'System