summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/python/binfile.py
diff options
context:
space:
mode:
Diffstat (limited to 'crawl-ref/source/python/binfile.py')
-rw-r--r--crawl-ref/source/python/binfile.py107
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")