
NameSpace System
NameSpace IO

Class MemoryStream
	Inherits Stream

Public
	/*
	0に初期化される拡張可能な容量を使用して初期化
	*/
	Sub MemoryStream()
		This.writable = True
		This.Resizable = True
		This.visible = False
		This.handle = HeapCreate(0,0,0)
		This.p = HeapAlloc(This.handle,HEAP_ZERO_MEMORY,0)
		This.StreamLength = 0
		This.CurrentPosition = 0
	End Sub
	Sub MemoryStream(capacity As Long)
		This.writable = True
		This.Resizable = True
		This.visible = False
		This.handle = HeapCreate(0,0,0)
		This.p = HeapAlloc(This.handle,HEAP_ZERO_MEMORY,capacity)
		This.StreamLength = capacity
		This.CurrentPosition = 0
	End Sub
	Sub MemoryStream(buffer As *Byte, length As Long)
		This.writable = True
		This.Resizable = False
		This.visible = False
		This.handle = HeapCreate(0,0,0)
		This.p = HeapAlloc(This.handle,HEAP_ZERO_MEMORY,length)
		MoveMemory(This.p,buffer,length)
		This.StreamLength = length
		This.CurrentPosition = 0
	End Sub
	Sub MemoryStream(buffer As *Byte, length As Long, writable As Boolean)
		This.writable = writable
		This.Resizable = False
		This.visible = False
		This.handle = HeapCreate(0,0,0)
		This.p = HeapAlloc(This.handle,HEAP_ZERO_MEMORY,length)
		MoveMemory(This.p,buffer,length)
		This.StreamLength = length
		This.CurrentPosition = 0
	End Sub
	Sub MemoryStream(buffer As *Byte, index As Long, count As Long)
		This.writable = True
		This.Resizable = False
		This.visible = False
		This.handle = HeapCreate(0,0,0)
		This.p = HeapAlloc(This.handle,HEAP_ZERO_MEMORY,count)
		MoveMemory(This.p,VarPtr(buffer[index]),count)
		This.StreamLength = count
		This.CurrentPosition = 0
	End Sub
	Sub MemoryStream(buffer As *Byte, index As Long, count As Long, writable As Boolean)
		This.writable = writable
		This.Resizable = False
		This.visible = False
		This.handle = HeapCreate(0,0,0)
		This.p = HeapAlloc(This.handle,HEAP_ZERO_MEMORY,count)
		MoveMemory(This.p,VarPtr(buffer[index]),count)
		This.StreamLength = count
		This.CurrentPosition = 0
	End Sub
	Sub MemoryStream(buffer As *Byte, index As Long, count As Long, writable As Boolean, visible As Boolean)
		This.writable = writable
		This.Resizable = False
		This.visible = visible
		This.handle = HeapCreate(0,0,0)
		This.p = HeapAlloc(This.handle,HEAP_ZERO_MEMORY,count)
		MoveMemory(This.p,VarPtr(buffer[index]),count)
		This.StreamLength = count
		This.CurrentPosition = 0
	End Sub
	Sub ~MemoryStream()
		This.Close()
	End Sub

Public
	Override Function CanRead() As Boolean
		If This.p Then
			Return True
		Else
			Return False
		End If
	End Function

	Override Function CanSeek() As Boolean
		If This.p Then
			Return True
		Else
			Return False
		End If
	End Function

	Override Function CanWrite() As Boolean
		If This.p Then
			Return This.writable
		Else
			Return False
		End If
	End Function

	/*
	メモリの容量であってストリームの長さではない
	メモリはヒープからブロック単位で確保されるので
	指定したストリーム長より大きくなることがある
	また、配列として扱う場合の配列長となる
	*/
	Virtual Function Capacity() As Long
		If This.p = 0 Then Debug'Throw New ObjectDisposedException
		Return HeapSize(This.handle,0,This.p)
	End Function

	Virtual Sub Capacity(value As Long)
		If This.p = 0 Then Debug'Throw New ObjectDisposedException
		If value < 0 Then Debug'Throw New ArgumentOutOfRangeException
		If value < This.StreamLength Then Debug'Throw New ArgumentOutOfRangeException
		This.p = HeapReAlloc(This.handle,HEAP_ZERO_MEMORY,This.p,value)
	End Sub

	/*
	こちらは容量とは別のストリーム長
	実際のデータの長さはこちら
	*/
	Override Function Length() As Int64
		If This.p = 0 Then Debug'Throw New ObjectDisposedException
		Return This.StreamLength
	End Function

	/*
	ストリームの現在位置を取得または設定
	*/
	Override Sub Position(value As Int64)
		If This.p = 0 Then Debug'Throw New ObjectDisposedException
		If value < 0 Then Debug'Throw New ArgumentOutOfRangeException
		If value > Int32.MaxValue() Then Debug'Throw New ArgumentOutOfRangeException
		This.CurrentPosition = value As Long
	End Sub

	Override Function Position() As Int64
		If This.p = 0 Then Debug'Throw New ObjectDisposedException
		Return This.CurrentPosition As Int64
	End Function

	Override Sub Flush()
	End Sub

/*	Virtual Function GetBuffer() As Array<Byte>
		If visible = False Then Return NULL
		Return p
	End Function*/

	Override Function Read(buffer As *Byte, offset As Long, count As Long) As Long
		If This.p = 0 Then Debug'Throw New ObjectDisposedException
		If buffer = 0 Then Debug 'Throw New ArgumentNullException
		If offset < 0 Then Debug'Throw New ArgumentOutOfRangeException
		If count < 0 Then Debug'Throw New ArgumentOutOfRangeException
		If (This.StreamLength - (This.CurrentPosition + count)) < 0 Then
			count + = (This.StreamLength - (This.CurrentPosition + count))
		ElseIf count < 1 Then
			Return 0
		End If
		MoveMemory(VarPtr(buffer[offset]),VarPtr(This.p[This.CurrentPosition]),count)
		This.CurrentPosition + = count
		Return count
	End Function

	Override Function ReadByte() As Long
		Dim b As Byte
		Dim ret = Read(VarPtr(b), 0, 1)
		If ret <> 0 Then
			Return b
		Else
			Return -1
		End If
	End Function

	Override Function Seek(offset As Int64, origin As SeekOrigin) As Int64
		If This.p = 0 Then Debug'Throw New ObjectDisposedException
		If offset > Int32.MaxValue() Then Debug'Throw New ArgumentOutOfRangeException
		Select Case origin
			Case SeekOrigin.Begin
				If offset < 0 Then Debug 'Throw New IOException
				This.CurrentPosition = offset As Long
			Case SeekOrigin.Current
				Beep(440,10)
				If (This.CurrentPosition + offset) < 0 Then Debug 'Throw New IOException
				This.CurrentPosition += offset As Long
			Case SeekOrigin.End
				If (This.StreamLength + offset) < 0 Then Debug 'Throw New IOException
				This.CurrentPosition = (This.StreamLength + offset) As Long
			Case Else
				Debug 'Throw New ArgumentException
		End Select
		Return This.CurrentPosition As Int64
	End Function

	Override Sub SetLength(value As Int64)
		If This.p = 0 Then Debug'Throw New ObjectDisposedException
		If This.writable = False Then Debug 'Throw New NotSupportedException
		If This.Resizable = False Then Debug 'Throw New NotSupportedException
		If value < 0 Then Debug'Throw New ArgumentOutOfRangeException
		If value > Int32.MaxValue() Then Debug'Throw New ArgumentOutOfRangeException
		This.p = HeapReAlloc(This.handle,HEAP_ZERO_MEMORY,This.p,value As Long)
		This.StreamLength = value As Long
	End Sub

	Override Sub Write(buffer As *Byte, offset As Long, count As Long)
		If This.p = 0 Then Debug'Throw New ObjectDisposedException
		If This.writable = False Then Debug'Throw New NotSupportedException
		If buffer = 0 Then Debug 'Throw New ArgumentNullException
		If offset < 0 Then Debug'Throw New ArgumentOutOfRangeException
		If count < 0 Then Debug'Throw New ArgumentOutOfRangeException
		If count > (This.StreamLength - This.CurrentPosition) Then 
			If This.Resizable = False Then
				Debug 'Throw New NotSupportedException
			Else
				If count > (This.Capacity() - This.CurrentPosition) Then 
					This.p = HeapReAlloc(This.handle,HEAP_ZERO_MEMORY,This.p,This.CurrentPosition+count)
				End If
				This.StreamLength = This.CurrentPosition+count
			End If
		End If
		MoveMemory(VarPtr(This.p[This.CurrentPosition]),VarPtr(buffer[offset]),count)
		This.CurrentPosition + = count
	End Sub

	Override Sub WriteByte(b As Byte)
		Write(VarPtr(b), 0, 1)
	End Sub

/*	Virtual Function ToArray() As List<Byte>
		TODO:
	End Function*/

	Virtual Sub WriteTo(stream As Stream)
		If This.p = 0 Then Debug'Throw New ObjectDisposedException
		If ActiveBasic.IsNothing(stream) Then Debug 'Throw New ArgumentNullException("path")
		stream.Write(This.p,0,This.Capacity())
	End Sub

Protected
	Override Sub Dispose(disposing As Boolean)
		HeapFree(This.handle,0,InterlockedExchangePointer(ByVal VarPtr(This.p) As VoidPtr,NULL) As VoidPtr)
		HeapDestroy(InterlockedExchangePointer(ByVal VarPtr(This.handle) As VoidPtr,NULL) As HANDLE)
	End Sub

	/* status */
	writable As Boolean
	Resizable As Boolean
	visible As Boolean

	StreamLength As Long
	CurrentPosition As Long

Private
	handle As HANDLE
	p As *Byte
End Class

End NameSpace 'IO
End NameSpace 'System
