Need help with BYTES

BlitzMax Forums/BlitzMax Programming/Need help with BYTES

Trader3564(Posted 2008) [#1]
Hi, ive been going nuts.

I hope someone can help me get this awnsers. (some of the awnsers i know already, but i ask anyway, just in case im doing somethign wrong, i find out)

1) How do i create a Byte array
2) How do i append another Byte array to one
3) How do i pick 1 or more bytes from a byte array
4) How do i resize a byte array (e.g. remove the first bytes)

Basicly, we all know the commands LEFT$, MID$, RIGHT$, etc... for string manipulation. And we know arrays. Now all i need is be able todo this on byte level.
But actualy, i also need to be able to read Shorts, and Ints. But if needed i write my own class.

I know off the TBank, but im not sure how you van do point 1 to 4 with a TBank. So thats why i tought i need it as an array.

Basicly, what i want todo is, read the buffer of a SocketStream (entirely) and then append the new data, to the old data, that was saved in the buffer of the class.
As this buffer grows and grows, another method would check for packets and cut them out one by one.

Thanks for helping!


Brucey(Posted 2008) [#2]
1)
Local mybytes:byte[200]


2)
Local mybytes:byte[200]
Local myotherbytes:byte[100]
Local allmybytes:byte[] = mybytes + myotherbytes


3)
Local mybytes:byte[200]

Local abyte:byte = mybytes[15]


4)
Local mybytes:byte[200]
Print mybytes.length

mybytes = mybytes[5..]
Print mybytes.length


not really tested... :-p


Volker(Posted 2008) [#3]
4)
If you want to resize your array dynamically, remember
that resizing is slow.


Trader3564(Posted 2008) [#4]
Ok, i have yet another problem, that is, having the bytes, i cant do anything with them, as it gives type errors.

Any ideas how to make this work? I dont specificly need a bytearray, but i want to be able todo the logic as follows.

SuperStrict

Graphics 640, 480

Local client:OClient = OClient.Create("127.0.0.1", 6121)

While Not KeyHit(KEY_ESCAPE)
	client.onRecieve()
Wend

Rem
Function ToString(bytes:Byte[])
	Local str:String
	Local char:String
	Local i:Int = 0

	While char = Chr(bytes[i..i+1])
		str = str + char
		i = i + 1
	Wend
	Return str
End Function
EndRem

Type OClient
	Field host:String
	Field port:Int
	Field socket:TSocket
	Field stream:TSocketstream
	Field buffer:TBytes
	
	Function Create:OClient(host:String, port:Int)
		Local client:OClient = New OClient
		client.host = host
		client.port = port
		client.socket = CreateTCPSocket()
		ConnectSocket(client.socket, HostIp(host), port)
		
		If client Then
			client.stream = CreateSocketStream(client.socket)
			Return client
		Else
			Return Null
		End If
	End Function
	
	Method onPacketReceive(packetType:Byte, packetData:Byte[])
		Print "Received packet type: " + packetType +  " with data: " + packetData[..SizeOf(packetData)]
	End Method
	
	Method onRecieve()
		If SocketReadAvail(Self.socket) > 0
			Self.buffer.Append(Self._ReadBytes())
			Local size:Int = SizeOf(Self.buffer.bytes)
			
			If size > 3 Then
				packetSize = Self.buffer.ReadShort(1)
				If size - 3 >= packetSize Then
					packetType = Self.buffer.ReadByte(0)
					packetData = Self.buffer.ReadBytes(3, packetSize)
					Self.buffer.Pop(size)
					Self.onPacketReceive(packetType, packetData)
				End If
			End If
		End If
	End Method
	
	Method _ReadBytes()
		Local bytes:Byte[]
		While SocketReadAvail(Self.socket) > 0
			bytes = bytes + ReadByte(Self.stream)
		Wend
		Return bytes
	End Method
End Type

Type TBytes
	Field bytes:Byte[]
	
	Method Write(bytes:Byte)
		Self.bytes = bytes
	End Method
	
	Method Append(bytes:Byte)
		Self.bytes = Self.bytes + bytes
	End Method
	
	Method Pop(length:Int)
		Self.bytes = Self.bytes[length..(SizeOf(Self.bytes)-length)]
	End Method
	
	Method Read()
		Return Self.bytes
	End Method
	
	Method ReadBytes:Byte(offset:Int, length:Int) 
		Return Self.bytes[offset..(offset+length)]
	End Method
	
	Method ReadByte:Byte(offset:Int) 
		Return Self.bytes[offset..(offset+1)]
	End Method
	
	Method ReadShort:Short(offset:Int) 
		Return Self.bytes[offset..(offset+2)]
	End Method
	
	Method ReadInt:Int(offset:Int) 
		Return Self.bytes[offset..(offset+4)]
	End Method
	
	Method ReadLong:Long(offset:Int) 
		Return Self.bytes[offset..(offset+4)]
	End Method
	
	Method ReadFloat:Float(offset:Int) 
		Return Self.bytes[offset..(offset+4)]
	End Method
	
	Method ReadDouble:Double(offset:Int) 
		Return Self.bytes[offset..(offset+8)]
	End Method
End Type



Jesse(Posted 2008) [#5]
first understand that a string and an array can not be used the same way.
you can not print an array of bytes and a string the same way or read them the same way. Arrays of bytes have to be read or printed one byte at a time unlike strings. You can access each byte of the string through the corresponding index and print its "byte value". if you want to see the actual character you have to convert the byte to a char such as:
name:string = "Jesse"
print name[0]
print chr(name[0])

this will print 74 and the letter "J"

with this in mind I have somewhat fixed your code to work first with bytes:


and then with strings:


As you can see the one with string is a lot simpler but only because it is done by the compiler, unlike the one with bytes that everything has to be coded.

note that I have not tested so there might be some logic errors.

[edited]

look at this code:
http://www.blitzmax.com/Community/posts.php?topic=81750#921145
In principle it does the same thing but with tbanks and is alot simpler


ziggy(Posted 2008) [#6]
I would add that BlitzMax strings are 2 bytes strings due to unicode. so be careful!


Brucey(Posted 2008) [#7]
and String.FromBytes(bytearray, size) is sometimes useful too :-)


Jesse(Posted 2008) [#8]
and String.FromBytes(bytearray, size) is sometimes useful too :-)

lol, just learned something new :-). stuff I constatly see but ignore.


Trader3564(Posted 2008) [#9]
AH! thats it, i knew it was something like Brucey, i did this back in feb. this year ,but i forgot. I was playign with CString()... but it was FromBytes()
Great.

Also, to get an INT from a byte, how does that work? if i just put a byte in an INT it will give a type error. If i make it a string, it will convert to a charcter. I need to be able to get the byte number. Since i store values between 0-255 in bytes. :)


Brucey(Posted 2008) [#10]
To get an Int, you need to do something like :
' if you have a byte array
Print Int Ptr(Byte Ptr(bytes) + offset)[0]

' if you have a byte ptr
Int Ptr(byteptr + offset)[0]

Which should return you the contents of the 4 bytes from offset.

You can make a Byte Ptr from a Byte Array with
Local byteptr:Byte Ptr = bytes



Trader3564(Posted 2008) [#11]
thanks!


Trader3564(Posted 2008) [#12]
ugh... im sorry for not managing this on my own but its nasty.

i have fixed the code and did some other work on it, yet i still keep getting errors in SuperStrict, i just cant figure how to solve the last type issues.

SuperStrict

Graphics 640, 480

Local client:OClient = OClient.Create("127.0.0.1", 6121)

If Not client Then End

While Not KeyHit(KEY_ESCAPE)
	'If KeyHit(KEY_SPACE) Then client.Send("Test")
	client.onRecieve()
Wend

Type OClient
	Field host:String
	Field port:Int
	Field socket:TSocket
	Field stream:TSocketstream
	Field buffer:TBytes
	
	Function Create:OClient(host:String, port:Int)
		Local client:OClient = New OClient
		client.host = host
		client.port = port
		client.socket = CreateTCPSocket()
		ConnectSocket(client.socket, HostIp(host), port)
		
		If client Then
			client.stream = CreateSocketStream(client.socket)
			Return client
		Else
			Return Null
		End If
	End Function
	
	Method onPacketReceive(packetType:Byte, packetData:Byte[])
		Print "Received packet type: " + String(Int Ptr(packetType)[0]) +  " with data: " String.FromBytes(packetData, SizeOf(packetData))
	End Method
	
	Method onRecieve()
		If SocketReadAvail(Self.socket) > 0
			While SocketReadAvail(Self.socket) > 0
				Self.buffer.Append(ReadByte(Self.stream))
			Wend

			Local size:Int = SizeOf(Self.buffer.bytes)
			
			If size > 3 Then
				Local packetSize:Short = Self.buffer.ReadShort(1)
				If size - 3 >= packetSize Then
					Local packetType:Byte = Self.buffer.ReadByte(0)
					Local packetData:Byte[] = Self.buffer.ReadBytes(3, packetSize)
					Self.buffer.Pop(size)
					Self.onPacketReceive(packetType, packetData)
				End If
			End If
		End If
	End Method
End Type

Type TBytes
	Field bytes:Byte[]
	
	Method Set(bytes:Byte[])
		Self.bytes = bytes
	End Method
	
	Method Append(bytes:Byte)
		Self.bytes[Self.bytes.length] = bytes
	End Method
	
	Method Pop(length:Int)
		Self.bytes = Self.bytes[length..(SizeOf(Self.bytes)-length)]
	End Method
	
	Method Get:Byte[]()
		Return Self.bytes
	End Method
	
	Method ReadBytes:Byte[](offset:Int, length:Int) 
		Return Self.bytes[offset..(offset+length)]
	End Method
	
	Method ReadByte:Byte(offset:Int) 
		Return Self.bytes[offset..(offset+1)]
	End Method
	
	Method ReadShort:Short(offset:Int) 
		Return Self.bytes[offset..(offset+2)]
	End Method
	
	Method ReadInt:Int(offset:Int) 
		Return Self.bytes[offset..(offset+4)]
	End Method
	
	Method ReadLong:Long(offset:Int) 
		Return Self.bytes[offset..(offset+4)]
	End Method
	
	Method ReadFloat:Float(offset:Int) 
		Return Self.bytes[offset..(offset+4)]
	End Method
	
	Method ReadDouble:Double(offset:Int) 
		Return Self.bytes[offset..(offset+8)]
	End Method
End Type


Isnt there a way todo this without ByteArray maybe? What would be faster? I have no idea! Would a TBank work fast enough?... cant i make a MemmoryStream or something? that i would just append from the TCP stream to the Buffer stream, and pop the packets off when they arrived 100%.


tonyg(Posted 2008) [#13]
You're returning a byte array but declared a byte. You either need to extract the byte you want to return or change the return to byte[].


Jesse(Posted 2008) [#14]
	
	Method Append(bytes:Byte)
		Self.bytes[Self.bytes.length] = bytes
	End Method


what?


Brucey(Posted 2008) [#15]
Heh :-)

I think he meant :
	Method Append(bytes:Byte[])
		Self.bytes :+ bytes
	End Method



Jesse(Posted 2008) [#16]
I guess I shouldn't post in this thread anymore. I know when I am being ignored. Neither your suggestions or mine are being used.

thi is your suggestion:
' if you have a byte array
Print Int Ptr(Byte Ptr(bytes) + offset)[0]

' if you have a byte ptr
Int Ptr(byteptr + offset)[0]

and this is what he did:
	
	Method ReadInt:Int(offset:Int) 
		Return Self.bytes[offset..(offset+4)]
	End Method



Brucey(Posted 2008) [#17]
I'm guessing part of the problem is a lack of understanding of all this ptr nonsense. Some of it can take a while to get ones head around.

and this is what he did

Not entirely fair, as it looks like that is his original effort, which he hasn't actually changed yet. Some of these functions would probably be easier with a Bank, rather than a byte array - as least code wise, since Bank has most of this functionality already. No Pop or append though - excepting for the Resize method.

What would be faster? I have no idea! Would a TBank work fast enough?

Probably about the same speed, I'd guess. At least not noticeably different.

If you want to stick to byte[], I suggest adding an extra field :
	Field bytePtr:Byte Ptr

which you align with your array - makes the rest of your code tidier.
	Method Set(bytes:Byte[])
		Self.bytes = bytes
		bytePtr = Self.bytes
	End Method

and so on for each method which requires a new byte[] object : Append and Pop.

And subsequently this method :
	Method ReadInt:Int(offset:Int) 
		Return Self.bytes[offset..(offset+4)]
	End Method

could be changed to
	Method ReadInt:Int(offset:Int) 
		Return Int Ptr(bytePtr + offset)[0]
	End Method


... and so on for the others.


Jesse(Posted 2008) [#18]

Not entirely fair, as it looks like that is his original effort, which he hasn't actually changed yet.



I guess. So, excuse my impatience. :-)