'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

	/*
	@date 2008/02/25
	@auther Egtra
	*/
	Override Function Peek() As Long
		If cur = last Then
			last = s.Read(buf, 0, size)
			cur = 0
			If last = 0 Then
				Peek = -1
				Exit Function
			End If
		End If
		Peek = buf[cur]
	End Function

	/*
	@date 2008/02/25
	@auther Egtra
	*/
	Override Function Read() As Long
		Read = Peek()
		If Read <> -1 Then
			cur++
		End If
	End Function

	/*
	@date 2008/02/26
	@auther Egtra
	*/
	Override Function ReadToEnd() As String
		Dim sb = New Text.StringBuilder(65536)
		sb.Append(buf, cur, last - cur)
		Do
			Dim read = Read(buf, 0, size)
			sb.Append(buf, 0, read)
			If read < size Then
				ReadToEnd = sb.ToString
				Exit Function
			End If
		Loop
	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
		size = 0
		cur = 0
		last = 0
	End Sub

	/*
	@date 2008/02/25
	@auther Egtra
	*/
	Override Function ReadImpl(buffer As *Char, index As Long, count As Long) As Long
		Dim n = last - cur
		If count <= n Then
			ReadImpl = ReadFromBuffer(buffer, index, count)
			Exit Function
		End If
		Dim p = VarPtr(buffer[index])
		ReadImpl = ReadFromBuffer(p, 0, n)
		If ReadImpl = count Then 'バッファの中身で足りた場合
			Exit Function
		End If
		p = VarPtr(p[n])
		count -= n
		If count > size Then
			n = (count \ size) * size 'sizeの倍数分だけは直接bufferへ読み込ませる
			Dim read = s.Read(p, 0, n)
			If read = 0 Then 'EOF
				Exit Function
			End If
			p = VarPtr(p[n])
			ReadImpl += n
			count -= n
		End If
		last = s.Read(buffer, 0, size)
		cur = 0
		If last = 0 Then 'EOF
			Exit Function
		End If
		ReadImpl += ReadFromBuffer(p, 0, Math.Min(last, count))
	End Function

Private
	/*
	@date 2008/02/25
	@auther Egtra
	*/
	Sub init(str As Stream)
		s = str
		size = 4096
		last = 0
		cur = 0
		buf = GC_malloc(size)
	End Sub

	/**
	@brief バッファの中身から読み取る。
	@date 2008/02/25
	@auther Egtra
	文字数が足りなくても、元のストリームまで読みには行かない。
	*/
	Function ReadFromBuffer(p As *Char, index As Long, count As Long) As Long
		memcpy(VarPtr(p[index]), VarPtr(buf[cur]), count * SizeOf (Char))
		cur += count
		ReadFromBuffer = count
	End Function

	s As Stream
	size As Long
	cur As Long
	last As Long '中身の終わり
	buf As *SByte '暫定
End Class

End Namespace
End Namespace
