'Classes/System/IO/StreamReader.ab Namespace System Namespace IO /* @brief ストリームから読み取りを行うTextReaderの実装。 @date 2008/02/25 @auther Egtra */ Class StreamReader Inherits TextReader Public /* @date 2008/02/25 @auther Egtra */ Sub StreamReader(path As String) init(New FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) End Sub /* @date 2008/02/25 @auther Egtra */ Sub StreamReader(stream As Stream) init(stream) End Sub Public /* @brief 基になるストリームを取得する @date 2008/09/02 @auther NoWest */ Function BaseStream () As Stream Return s End Function /* @date 2008/02/25 @auther Egtra */ Override Function Peek() As Long If charSize = charCur Then fillCharBuf() If charSize = charCur Then Peek = -1 Exit Function End If End If Peek = charBuf[charCur] End Function /* @date 2008/02/25 @auther Egtra */ Override Function Read() As Long Read = Peek() If Read <> -1 Then charCur++ End If End Function Protected /* @date 2008/02/25 @auther Egtra */ Override Sub Dispose(disposing As Boolean) If disposing Then If Not ActiveBasic.IsNothing(s) Then s.Dispose(True) End If End If s = Nothing End Sub /* @date 2008/02/25 @auther Egtra */ Override Function ReadImpl(buffer As *WCHAR, count As Long) As Long Dim n = charSize - charCur '現在のバッファに溜まっている文字数 If count <= n And charEof <> False Then ReadImpl = readFromBuffer(buffer, count) Exit Function End If ReadImpl = readFromBuffer(buffer, n) If ReadImpl = count Then 'バッファの中身で足りた場合 Exit Function End If fillCharBuf() ReadImpl += ReadImpl(VarPtr(buffer[n]), count - n) End Function Private /* @date 2008/02/25 @auther Egtra */ Sub init(str As Stream) s = str '暫定。正式版ではUTF-8を標準とする。 encoding = New Text.Detail.WindowsCodePageEncoding(CP_ACP) decoder = encoding.GetDecoder() charCapacity = 4096 byteCapacity = 4096 charBuf = GC_malloc(charCapacity * SizeOf(WCHAR)) byteBuf = GC_malloc(byteCapacity) charCur = 0 byteCur = 0 charSize = 0 byteSize = 0 charEof = False byteEof = False End Sub /** @brief バッファの中身から読み取る。 @date 2008/02/25 @auther Egtra 文字数が足りなくても、元のストリームまで読みには行かない。 */ Function readFromBuffer(p As *WCHAR, count As Long) As Long memcpy(p, VarPtr(charBuf[charCur]), count * SizeOf (WCHAR)) charCur += count readFromBuffer = count End Function /*! @brief byteBufを基にcharBufを埋める。charBufが空になったときに用いる。 @date 2008/11/08 @auther Egtra */ Sub fillCharBuf() charCur = 0 charSize = 0 If charEof = False Then If byteCur = byteSize Then byteSize = s.Read(byteBuf, 0, byteCapacity) byteCur = 0 If byteSize = 0 Then byteEof = True End If End If Dim charUsed As Long Dim byteUsed As Long Dim completed As Boolean decoder.Convert(VarPtr(byteBuf[byteCur]), byteSize - byteCur, VarPtr(charBuf[charSize]), charCapacity - charSize, byteEof, charUsed, byteUsed, completed) charEof = byteEof And completed And byteCur = byteSize byteCur += byteUsed charSize += charUsed End If End Sub s As Stream encoding As Text.Encoding decoder As Text.Decoder charBuf As *WCHAR byteBuf As *Byte charCur As Long '読み取っていないデータの開始位置 byteCur As Long charSize As Long 'Bufの内、有効なデータの数 byteSize As Long charCapacity As Long '確保済み容量 = GC_mallocしたときの引数の値 byteCapacity As Long charEof As Boolean 'Trueのとき、次にcur = sizeになるまでしかデータがことを示す byteEof As Boolean '常に0 <= cur <= size <= capacity End Class End Namespace End Namespace