move read/write into IO class

This commit is contained in:
2014-10-14 12:02:57 +02:00
parent 092430476d
commit 4220a679f3

View File

@@ -61,8 +61,8 @@ def open_blend(filename, access="rb"):
Known issue: does not support packaged blend files
"""
handle = open(filename, access)
magic = read_string(handle, 7)
if magic == "BLENDER":
magic = handle.read(7)
if magic == b"BLENDER":
log.debug("normal blendfile detected")
handle.seek(0, os.SEEK_SET)
res = BlendFile(handle)
@@ -89,112 +89,6 @@ def open_blend(filename, access="rb"):
return res
######################################################
# Write a string to the file.
######################################################
def write_string(handle, astring, fieldlen):
assert(isinstance(astring, str))
stringw = ""
if len(astring) >= fieldlen:
stringw = astring[0:fieldlen]
else:
stringw = astring + '\0'
handle.write(stringw.encode('utf-8'))
def write_bytes(handle, astring, fieldlen):
assert(isinstance(astring, (bytes, bytearray)))
stringw = b''
if len(astring) >= fieldlen:
stringw = astring[0:fieldlen]
else:
stringw = astring + b'\0'
print(stringw)
print(handle)
handle.write(stringw)
def _string_struct(length):
if length < len(_string_struct.STRING):
st = _string_struct.STRING[length]
else:
st = struct.Struct("%ds" % length)
return st
_string_struct.STRING = [struct.Struct("%ds" % i) for i in range(0, 2048)]
def read_string(handle, length):
"""
read_string reads a String of given length from a file handle
"""
st = _string_struct(length)
return st.unpack(handle.read(st.size))[0].decode('utf-8')
def read_string0(data, offset):
"""
read_string0 reads a zero terminating String from a file handle
"""
add = 0
# TODO, faster method!
while data[offset + add] != 0:
add += 1
st = _string_struct(add)
result = st.unpack_from(data, offset)[0].decode('utf-8')
return result
######################################################
# ReadUShort reads an unsigned short from a file handle
######################################################
USHORT = [struct.Struct("<H"), struct.Struct(">H")]
def ReadUShort(handle, fileheader):
us = USHORT[fileheader.endian_index]
return us.unpack(handle.read(us.size))[0]
######################################################
# ReadUInt reads an unsigned integer from a file handle
######################################################
UINT = [struct.Struct("<I"), struct.Struct(">I")]
def ReadUInt(handle, fileheader):
us = UINT[fileheader.endian_index]
return us.unpack(handle.read(us.size))[0]
def ReadInt(handle, fileheader):
return struct.unpack(fileheader.endian_str + "i", handle.read(4))[0]
def ReadFloat(handle, fileheader):
return struct.unpack(fileheader.endian_str + "f", handle.read(4))[0]
SSHORT = [struct.Struct("<h"), struct.Struct(">h")]
def ReadShort(handle, fileheader):
us = SSHORT[fileheader.endian_index]
return us.unpack(handle.read(us.size))[0]
ULONG = [struct.Struct("<Q"), struct.Struct(">Q")]
def ReadULong(handle, fileheader):
us = ULONG[fileheader.endian_index]
return us.unpack(handle.read(us.size))[0]
######################################################
# ReadPointer reads an pointerfrom a file handle
# the pointersize is given by the header (BlendFileHeader)
######################################################
def ReadPointer(handle, header):
if header.pointer_size == 4:
us = UINT[header.endian_index]
return us.unpack(handle.read(us.size))[0]
if header.pointer_size == 8:
us = ULONG[header.endian_index]
return us.unpack(handle.read(us.size))[0]
######################################################
@@ -433,9 +327,9 @@ class DNACatalog:
def __init__(self, header, block, handle):
log.debug("building DNA catalog")
shortstruct = USHORT[header.endian_index]
shortstruct2 = struct.Struct(str(USHORT[header.endian_index].format.decode() + 'H'))
intstruct = UINT[header.endian_index]
shortstruct = DNA_IO.USHORT[header.endian_index]
shortstruct2 = struct.Struct(str(DNA_IO.USHORT[header.endian_index].format.decode() + 'H'))
intstruct = DNA_IO.UINT[header.endian_index]
data = handle.read(block.size)
self.names = []
self.types = []
@@ -447,7 +341,7 @@ class DNACatalog:
log.debug("building #%d names" % names_len)
for i in range(names_len):
tName = read_string0(data, offset)
tName = DNA_IO.read_string0(data, offset)
offset = offset + len(tName) + 1
self.names.append(DNAName(tName))
del names_len
@@ -458,7 +352,7 @@ class DNACatalog:
offset += 4
log.debug("building #"+str(types_len)+" types")
for i in range(types_len):
tType = read_string0(data, offset)
tType = DNA_IO.read_string0(data, offset)
self.types.append([tType, 0, None])
offset += len(tType) + 1
@@ -588,15 +482,15 @@ class DNAStructure:
if len(rest) == 0:
if fname.is_pointer:
return ReadPointer(handle, header)
return DNA_IO.read_pointer(handle, header)
elif ftype[0] == "int":
return ReadInt(handle, header)
return DNA_IO.read_int(handle, header)
elif ftype[0] == "short":
return ReadShort(handle, header)
return DNA_IO.read_short(handle, header)
elif ftype[0] == "float":
return ReadFloat(handle, header)
return DNA_IO.read_float(handle, header)
elif ftype[0] == "char":
return read_string(handle, fname.array_size)
return DNA_IO.read_string(handle, fname.array_size)
else:
return ftype[2].field_get(header, handle, rest)
@@ -618,9 +512,9 @@ class DNAStructure:
if len(rest) == 0:
if ftype[0] == "char":
if type(value) is str:
return write_string(handle, value, fname.array_size)
return DNA_IO.write_string(handle, value, fname.array_size)
else:
return write_bytes(handle, value, fname.array_size)
return DNA_IO.write_bytes(handle, value, fname.array_size)
else:
return ftype[2].field_set(header, handle, rest, value)
else:
@@ -628,6 +522,121 @@ class DNAStructure:
return None
class DNA_IO:
"""
Module like class, for read-write utility functions.
Only stores static methods & constants.
"""
__slots__ = ()
# ----
# Methods for read/write,
# these are only here to avoid clogging global-namespace
@staticmethod
def write_string(handle, astring, fieldlen):
assert(isinstance(astring, str))
stringw = ""
if len(astring) >= fieldlen:
stringw = astring[0:fieldlen]
else:
stringw = astring + '\0'
handle.write(stringw.encode('utf-8'))
@staticmethod
def write_bytes(handle, astring, fieldlen):
assert(isinstance(astring, (bytes, bytearray)))
stringw = b''
if len(astring) >= fieldlen:
stringw = astring[0:fieldlen]
else:
stringw = astring + b'\0'
print(stringw)
print(handle)
handle.write(stringw)
_STRING = [struct.Struct("%ds" % i) for i in range(0, 2048)]
@staticmethod
def _string_struct(length):
if length < len(DNA_IO._STRING):
st = DNA_IO._STRING[length]
else:
st = struct.Struct("%ds" % length)
return st
@staticmethod
def read_string(handle, length):
"""
read_string reads a String of given length from a file handle
"""
st = DNA_IO._string_struct(length)
return st.unpack(handle.read(st.size))[0].decode('utf-8')
@staticmethod
def read_string0(data, offset):
"""
read_string0 reads a zero terminating String from a file handle
"""
add = 0
# TODO, faster method!
while data[offset + add] != 0:
add += 1
st = DNA_IO._string_struct(add)
result = st.unpack_from(data, offset)[0].decode('utf-8')
return result
USHORT = struct.Struct("<H"), struct.Struct(">H")
@staticmethod
def read_ushort(handle, fileheader):
st = USHORT[fileheader.endian_index]
return st.unpack(handle.read(st.size))[0]
UINT = struct.Struct("<I"), struct.Struct(">I")
@staticmethod
def read_uint(handle, fileheader):
st = UINT[fileheader.endian_index]
return st.unpack(handle.read(st.size))[0]
SINT = struct.Struct("<i"), struct.Struct(">i")
@staticmethod
def read_int(handle, fileheader):
st = SINT[fileheader.endian_index]
return st.unpack(handle.read(st.size))[0]
@staticmethod
def read_float(handle, fileheader):
return struct.unpack(fileheader.endian_str + "f", handle.read(4))[0]
SSHORT = struct.Struct("<h"), struct.Struct(">h")
@staticmethod
def read_short(handle, fileheader):
st = SSHORT[fileheader.endian_index]
return st.unpack(handle.read(st.size))[0]
ULONG = struct.Struct("<Q"), struct.Struct(">Q")
@staticmethod
def read_ulong(handle, fileheader):
st = ULONG[fileheader.endian_index]
return st.unpack(handle.read(st.size))[0]
@staticmethod
def read_pointer(handle, header):
"""
ReadPointer reads an pointerfrom a file handle
the pointersize is given by the header (BlendFileHeader)
"""
if header.pointer_size == 4:
st = UINT[header.endian_index]
return st.unpack(handle.read(st.size))[0]
if header.pointer_size == 8:
st = ULONG[header.endian_index]
return st.unpack(handle.read(st.size))[0]
class DNAField:
"""