from __future__ import division
import struct
-import cStringIO as StringIO
import hashlib
import warnings
assert data2 is data
if pos != len(data):
- raise LateEnd('underread ' + repr((self, data)))
+ raise LateEnd()
return obj
+ def _pack(self, obj):
+ f = self.write(None, obj)
+
+ res = []
+ while f is not None:
+ res.append(f[1])
+ f = f[0]
+ res.reverse()
+ return ''.join(res)
+
+
def unpack(self, data):
obj = self._unpack(data)
return obj
- def _pack(self, obj):
- f = []
-
- self.write(f, obj)
-
- data = ''.join(f)
-
- return data
-
def pack(self, obj):
data = self._pack(obj)
def write(self, file, item):
if item < 0xfd:
- file.append(struct.pack('<B', item))
+ file = file, struct.pack('<B', item)
elif item <= 0xffff:
- file.append(struct.pack('<BH', 0xfd, item))
+ file = file, struct.pack('<BH', 0xfd, item)
elif item <= 0xffffffff:
- file.append(struct.pack('<BI', 0xfe, item))
+ file = file, struct.pack('<BI', 0xfe, item)
elif item <= 0xffffffffffffffff:
- file.append(struct.pack('<BQ', 0xff, item))
+ file = file, struct.pack('<BQ', 0xff, item)
else:
raise ValueError('int too large for varint')
+ return file
class VarStrType(Type):
_inner_size = VarIntType()
return read(file, length)
def write(self, file, item):
- self._inner_size.write(file, len(item))
- file.append(item)
+ file = self._inner_size.write(file, len(item))
+ return file, item
class FixedStrType(Type):
def __init__(self, length):
def write(self, file, item):
if len(item) != self.length:
raise ValueError('incorrect length!')
- file.append(item)
+ return file, item
class EnumType(Type):
def __init__(self, inner, values):
return self.keys[data], file
def write(self, file, item):
- self.inner.write(file, self.values[item])
+ return self.inner.write(file, self.values[item])
class HashType(Type):
def read(self, file):
raise ValueError("invalid hash value")
if item != 0 and item < 2**160:
warnings.warn("very low hash value - maybe you meant to use ShortHashType? %x" % (item,))
- file.append(('%064x' % (item,)).decode('hex')[::-1])
+ return file, ('%064x' % (item,)).decode('hex')[::-1]
class ShortHashType(Type):
def read(self, file):
def write(self, file, item):
if item >= 2**160:
raise ValueError("invalid hash value")
- file.append(('%040x' % (item,)).decode('hex')[::-1])
+ return file, ('%040x' % (item,)).decode('hex')[::-1]
class ListType(Type):
_inner_size = VarIntType()
return res, file
def write(self, file, item):
- self._inner_size.write(file, len(item))
+ file = self._inner_size.write(file, len(item))
for subitem in item:
- self.type.write(file, subitem)
+ file = self.type.write(file, subitem)
+ return file
class FastLittleEndianUnsignedInteger(Type):
def read(self, file):
return data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24), file
def write(self, file, item):
- StructType("<I").write(file, item)
+ return StructType("<I").write(file, item)
class StructType(Type):
def __init__(self, desc):
if struct.unpack(self.desc, data)[0] != item:
# special test because struct doesn't error on some overflows
raise ValueError("item didn't survive pack cycle (%r)" % (item,))
- file.append(data)
+ return file, data
class IPV6AddressType(Type):
def read(self, file):
raise ValueError("invalid address: %r" % (bits,))
data = '00000000000000000000ffff'.decode('hex') + ''.join(chr(x) for x in bits)
assert len(data) == 16, len(data)
- file.append(data)
+ return file, data
class ComposedType(Type):
def __init__(self, fields):
def write(self, file, item):
for key, type_ in self.fields:
- type_.write(file, item[key])
+ file = type_.write(file, item[key])
+ return file
class ChecksummedType(Type):
def __init__(self, inner):
def write(self, file, item):
data = self.inner.pack(item)
- file.append(data)
- file.append(hashlib.sha256(hashlib.sha256(data).digest()).digest()[:4])
+ file = file, data
+ return file, hashlib.sha256(hashlib.sha256(data).digest()).digest()[:4]
class FloatingIntegerType(Type):
# redundancy doesn't matter here because bitcoin checks binary bits against its own computed bits
return target, file
def write(self, file, item):
- self._inner.write(file, self._target_to_bits(item))
+ return self._inner.write(file, self._target_to_bits(item))
def truncate_to(self, x):
return self._bits_to_target(self._target_to_bits(x, _check=False))
def write(self, file, item):
if item == self.none_value:
raise ValueError("none_value used")
- self.inner.write(file, self.none_value if item is None else item)
+ return self.inner.write(file, self.none_value if item is None else item)
address_type = ComposedType([
('services', StructType('<Q')),