Browse Source

added StructReader

pull/55/head
Rossen Georgiev 9 years ago
parent
commit
513c68ca08
  1. 6
      docs/api/steam.util.rst
  2. 39
      steam/core/msg/structs.py
  3. 44
      steam/util/binary.py

6
docs/api/steam.util.rst

@ -22,4 +22,10 @@ util.web
:undoc-members:
:show-inheritance:
util.binary
-----------
.. automodule:: steam.util.binary
:members:
:undoc-members:
:show-inheritance:

39
steam/core/msg/structs.py

@ -1,8 +1,10 @@
"""Classes to (de)serialize various struct messages"""
import struct
import six
from six.moves import range
from steam.enums import EResult, EUniverse
from steam.enums.emsg import EMsg
from steam.util.binary import StructReader
_emsg_map = {}
@ -136,19 +138,18 @@ class ClientVACBanStatus(StructMessage):
StructMessage.__init__(self, data)
def load(self, data):
numBans, = struct.unpack_from("<I", data)
offset = 4
buf = StructReader(data)
numBans, = buf.read_format("<I")
for _ in six.moves.range(numBans):
for _ in range(numBans):
m = self.VACBanRange()
m.start, m.end, _ = struct.unpack_from("<III", data, offset)
self.ranges.append(m)
m.start, m.end, _ = buf.read_format("<III")
if m.start > m.end:
m.start, m.end = m.end, m.start
offset += 4 + 4 + 4
def __str__(self):
text = ["numBans: %d" % self.numBans]
@ -179,12 +180,9 @@ class ClientChatMsg(StructMessage):
return rbytes
def load(self, data):
(self.steamIdChatter,
self.steamIdChatRoom,
self.ChatMsgType,
) = struct.unpack_from("<QQI", data)
self.text = data[struct.calcsize("<QQI"):-1].decode('utf-8')
buf = StructReader(data)
self.steamIdChatter, self.steamIdChatRoom, self.ChatMsgType = buf.read_format("<QQI")
self.text = buf.read_cstring().decode('utf-8')
def __str__(self):
return '\n'.join(["steamIdChatter: %d" % self.steamIdChatter,
@ -254,7 +252,7 @@ class ClientMarketingMessageUpdate2(StructMessage):
def __str__(self):
return '\n'.join(["{",
"id: %s" % self.id,
"url: %s" % self.url,
"url: %s" % repr(self.url),
"flags: %d" % self.flags,
"}",
])
@ -270,19 +268,16 @@ class ClientMarketingMessageUpdate2(StructMessage):
StructMessage.__init__(self, data)
def load(self, data):
self.time, count = struct.unpack_from("<II", data)
offset = 4 + 4
for _ in six.moves.range(count):
length, = struct.unpack_from("<I", data, offset)
url_length = length-4-8-4
offset += 4
buf = StructReader(data)
self.time, count = buf.read_format("<II")
for _ in range(count):
m = self.MarketingMessage()
m.id, m.url, _, m.flags = struct.unpack_from("<Q%dssI" % (url_length - 1), data, offset)
self.messages.append(m)
offset += 8 + url_length + 4
length, m.id = buf.read_format("<IQ")
m.url = buf.read_cstring().decode('utf-8')
m.flags = buf.read_format("<I")
def __str__(self):
text = ["time: %s" % self.time,

44
steam/util/binary.py

@ -0,0 +1,44 @@
import struct
class StructReader(object):
def __init__(self, data):
"""Simplifies parsing of struct data from bytes
:param data: data bytes
:type data: :class:`bytes`
"""
if not isinstance(data, bytes):
raise ValueError("Requires bytes")
self.data = data
self.offset = 0
def read_cstring(self):
"""Reads a single null termianted string
:return: string without bytes
:rtype: :class:`bytes`
"""
null_index = self.data.find(b'\x00', self.offset)
text = self.data[self.offset:null_index] # bytes without the null
self.offset = null_index + 1 # advanced past null
return text
def read_format(self, format_text):
"""Unpack bytes using struct modules format
:param format_text: struct's module format
:type format_text: :class:`str`
:return data: result from :func:`struct.unpack_from`
:rtype: :class:`tuple`
"""
data = struct.unpack_from(format_text, self.data, self.offset)
self.offset += struct.calcsize(format_text)
return data
def skip(self, n):
"""Skips the next ``n`` bytes
:param n: number of bytes to skip
:type n: :class:`int`
"""
self.offset += n
Loading…
Cancel
Save