Need some help with Streams

BlitzMax Forums/BlitzMax Programming/Need some help with Streams

ziggy(Posted 2008) [#1]
I need to create a stream that is able to read from an 'area' of an existing stream, a sort of sub stream that can be used as a regular stream (so extended from it).

That is, for example, If I'm reading from a file using a stream, I should be able to define another stream that gets de data from the byte number X of the existing stream, and has a lenth Y.

Something like:


Any help or solution in this direction would be very apreciated.


Perturbatio(Posted 2008) [#2]
Can't you just use the same stream and seek to the locations you need, read then seek back?


ziggy(Posted 2008) [#3]
No, becouse I need to pass this streams to functions like LoadImage and the like, so I need them to be real streams.


Brucey(Posted 2008) [#4]
Create a Sub-stream type, which takes a TStream, and a start/length.

Then have it perform operations offset on the real stream by start.

eg. Seek(0) would actually translate to Seek(start).

and Eof() is true when _pos = start+length...

etc.

:o)


ziggy(Posted 2008) [#5]
Yes, that's exactly the idea. I was asking for some help to do this. Any starting point or something. will it work extending the base Stream class or do I have to do something spetial. I mean, there's no 'implements¡ on BlitzMax and I am wondering wich kind of things do I have to keep in mind before proceeding.

[EDIT]
I've seen all base stream is performing operations using a byte ptr over a data buffer. How can I create a new sub-buffer from an existing stream (using the offset and the data size) and use a regular stream from there? Any idea?


ziggy(Posted 2008) [#6]
Ok I've found it and it was easier than I suspected:
Function CreateSubStream:TStream(Stream:TStream, Pos:Int, Length:Int, MovePos:Int = False) 
	Local OldPos:Int = stream.Pos() 
	?debug
		If Stream = Null Then
			Throw "Stream was null."
		End If
		If pos < 0 Or pos > stream.Size() Then
			Throw "Byte position out of bounds."
		End If
	?
	Try
		stream.Seek(pos) 
	Catch Err:String
		Throw "Stream has to be seekable."
	End Try
	Local B:TBank = CreateBank(Length) 
	ReadBank(b, stream, 0, length) 
	Local NewStream:TStream = OpenStream(B) 
	If MovePos = False Then Stream.Seek(oldpos) 
	Return newstream
End Function

the best thing is that there's no need to create a new class, as I suspected initially, so this way I think it would be much more easy to mantain if there's any bug there.


Brucey(Posted 2008) [#7]
hmm... maybe something like this :
Type TSubStream Extends TStreamWrapper

	Field start:Int
	Field length:Int
	
	Function Create:TSubStream(stream:TStream, start:Int, length:Int)
		Local this:TSubStream = New TSubStream
		this.SetStream stream
		this.start = start
		this.length = length
		Return this
	End Function
	
	Method Eof:Int()
		Return _stream.Eof() Or (Pos() >= length)
	End Method

	Method Pos:Int()
		Return _stream.Pos() - start
	End Method

	Method Size:Int()
		Return length
	End Method
	
	Method Seek:Int( pos:Int )
		Return _stream.Seek( pos + start )
	End Method

End Type

Untested...


ziggy(Posted 2008) [#8]
That's a good approach, as my solution my be duplicating data... I'm not sure how I will implement this... thanks!

Do you know if there's any way to create a static bank from a internal stream data bank? that would be the best solution but I haven't find a way to do it.