diff options
Diffstat (limited to 'crawl-ref/source/python/binfile.py')
-rw-r--r-- | crawl-ref/source/python/binfile.py | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/crawl-ref/source/python/binfile.py b/crawl-ref/source/python/binfile.py new file mode 100644 index 0000000000..2ebb986539 --- /dev/null +++ b/crawl-ref/source/python/binfile.py @@ -0,0 +1,107 @@ +import struct + +class reader(object): + """Wrapper around a read-only binary file""" + def __init__(self, fileorname): + """fileorname may be a file-like object or a filename""" + self.byteorder = '=' # can also be '<' or '>' + if hasattr(fileorname, 'read'): + self.file = fileorname + else: + self.file = file(fileorname, 'rb') + + def read(self,len): return self.file.read(len) + + def stream(self, fmt, len=0): + """Unpack fmt from f and return results.""" + fmt = self.byteorder + fmt # don't enforce alignment! + if len == 0: len = struct.calcsize(fmt) + data = self.file.read(len) + return struct.unpack(fmt, data) + + def stream1(self, fmt, len=0): + """Unpack fmt from f and return just one result.""" + (data,) = self.stream(fmt,len) + return data + + def _streamStringLow(self, len): + if len <= 0: return '' + str = self.file.read(len-1) + char = self.file.read(1) + if ord(char)==0: return str + else: return str+char + + def streamCooky(self): + l = list(self.stream("4c")) + l.reverse() + return ''.join(l) + + def streamString4(self): + """Stream string prefixed with 4 bytes of length""" + (strlen,) = self.stream("I",4) + if strlen >= 2048: + print "Bad string len: %#x" % strlen + assert strlen < 2048 + return self._streamStringLow(strlen) + + def streamString2(self): + """Stream string prefixed with 2 bytes of length""" + (strlen,) = self.stream("H",2) + assert strlen < 2048 + return self._streamStringLow(strlen) + + def streamString1(self): + """Stream string prefixed with 1 byte of length""" + (strlen,) = self.stream("B",1) + assert strlen < 2048 + return self._streamStringLow(strlen) + +class writer(object): + """Wrapper around a write-only binary file""" + def __init__(self, fileorname): + """fileorname may be a file-like object or a filename""" + if hasattr(fileorname, 'write'): + self.file = fileorname + else: + self.file = file(fileorname, 'wb') + + def write(self,data): return self.file.write(data) + def stream(self, fmt, *args): + fmt = '='+fmt # add the "no alignment" flag to the fmt + self.file.write(struct.pack(fmt, *args)) + # for symmetry with reader + def stream1(self, fmt, *args): + fmt = '='+fmt # add the "no alignment" flag to the fmt + self.file.write(struct.pack(fmt, *args)) + + def streamCooky(self, cooky): + assert len(cooky)==4 + l = list(cooky) + l.reverse() + self.stream("4c", *l) + + def streamString1(self, str): + """Stream string prefixed with 1 byte of length""" + #print "writing %s" % str + # Game doesn't handle 0-length null strings + self.file.write(struct.pack("B",len(str)+1)) + self.file.write(str) + self.file.write("\0") + + def streamString2(self, str): + """Stream string prefixed with 2 bytes of length""" + #print "writing %s" % str + # Game doesn't handle 0-length null strings + self.file.write(struct.pack("H",len(str)+1)) + self.file.write(str) + self.file.write("\0") + + def streamString4(self, str): + """Stream string prefixed with 4 bytes of length""" + if str=='': + self.file.write(struct.pack("I",0)) + else: + #print "writing %s" % str + self.file.write(struct.pack("I",len(str)+1)) + self.file.write(str) + self.file.write("\0") |