subclass FileIO

Blendfile is essentially a wrapper on top of io.FileIO, and besides the high level commands it adds, it also needs to open and close the underlying stream properly. It is logical to subclass io.FileIO, and makes it very convenient to use the wrapper. I am not sure whether allowing users to read from the underlying object is a good idea, but it shouldn't effect the behavior of the high level API.
master
Josiah 2021-07-19 10:50:43 -05:00
parent ad74f53617
commit 53e099e63b
No known key found for this signature in database
GPG Key ID: C7BB8573A4ABC4B9
1 changed files with 32 additions and 31 deletions

View File

@ -3,44 +3,45 @@
import io
# A class for opening and reading data from .blend files
class Blendfile():
class Blendfile(io.FileIO):
def __init__(self, filename):
self.filename = filename
with open(filename, "rb") as f:
self.stream = io.BufferedReader(f)
self.stream.seek(0)
super().__init__(filename, "rb")
self.read_header()
# File identifier, 8-byte string; should always be "BLENDER"
self.identifier = self.stream.read(7).decode("utf-8")
def read_header(self):
self.seek(0)
# Pointer size, 1-byte char; '-' indicates 8 bytes, '_' indicates 4
self.pointer_size = 8 if self.stream.read(1).decode("utf-8") == "-" else 4
# File identifier, 8-byte string; should always be "BLENDER"
self.identifier = self.read(7).decode("utf-8")
# Endianness, 1-byte char; 'v' indicates little endian, 'V' indicates big
self.endianness = "little" if self.stream.read(1).decode("utf-8") == "v" else "big"
# Pointer size, 1-byte char; '-' indicates 8 bytes, '_' indicates 4
self.pointer_size = 8 if self.read(1).decode("utf-8") == "-" else 4
# Blender version, 3-byte int; v2.93 is represented as 293, and so on
self.version = int(self.stream.read(3))
# Endianness, 1-byte char; 'v' indicates little endian, 'V' indicates big
self.endianness = "little" if self.read(1).decode("utf-8") == "v" else "big"
# Looping through file block headers to find scene header
# TODO: Implement proper error handling if the target file block does not exist.
while True:
# Blender version, 3-byte int; v2.93 is represented as 293, and so on
self.version = int(self.read(3))
# File block code; identifies type of data
code = self.stream.read(4).decode("utf-8")
# Looping through file block headers to find scene header
# TODO: Implement proper error handling if the target file block does not exist.
while True:
# Size of file block, after this header
size = int.from_bytes(self.stream.read(4), self.endianness)
# File block code; identifies type of data
code = self.read(4).decode("utf-8")
# Seeking to end of file block header
self.stream.seek(8+self.pointer_size+size, 1)
# Size of file block, after this header
size = int.from_bytes(self.read(4), self.endianness)
# Scene file block codes will always begin with "SC"
if code.startswith("SC"):
# TODO: Acquire SDNA index of scene data, to be found in DNA1 file block
# SDNA index occurs directly following file block size in header
# and is pointer_size bytes long
break
# Seeking to the start of the next file block
self.stream.seek(8+self.pointer_size+size, 1)
# Seeking to end of file block header
self.seek(8+self.pointer_size+size, 1)
# Scene file block codes will always begin with "SC"
if code.startswith("SC"):
# TODO: Acquire SDNA index of scene data, to be found in DNA1 file block
# SDNA index occurs directly following file block size in header
# and is pointer_size bytes long
break
# Seeking to the start of the next file block
self.seek(8+self.pointer_size+size, 1)