.dat file format of Fallout 2: Python (read-write) parsing library

Application

Fallout 2

File extension

dat

KS implementation details

License: CC0-1.0

References

This page hosts a formal specification of .dat file format of Fallout 2 using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Python (read-write) source code to parse .dat file format of Fallout 2

fallout2_dat.py

# This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
# type: ignore

import kaitaistruct
from kaitaistruct import ReadWriteKaitaiStruct, KaitaiStream, BytesIO
from enum import IntEnum
import zlib


if getattr(kaitaistruct, 'API_VERSION', (0, 9)) < (0, 11):
    raise Exception("Incompatible Kaitai Struct Python API: 0.11 or later is required, but you have %s" % (kaitaistruct.__version__))

class Fallout2Dat(ReadWriteKaitaiStruct):

    class Compression(IntEnum):
        none = 0
        zlib = 1
    def __init__(self, _io=None, _parent=None, _root=None):
        super(Fallout2Dat, self).__init__(_io)
        self._parent = _parent
        self._root = _root or self
        self._should_write_footer = False
        self.footer__enabled = True
        self._should_write_index = False
        self.index__enabled = True

    def _read(self):
        pass
        self._dirty = False


    def _fetch_instances(self):
        pass
        _ = self.footer
        if hasattr(self, '_m_footer'):
            pass
            self._m_footer._fetch_instances()

        _ = self.index
        if hasattr(self, '_m_index'):
            pass
            self._m_index._fetch_instances()



    def _write__seq(self, io=None):
        super(Fallout2Dat, self)._write__seq(io)
        self._should_write_footer = self.footer__enabled
        self._should_write_index = self.index__enabled


    def _check(self):
        if self.footer__enabled:
            pass
            if self._m_footer._root != self._root:
                raise kaitaistruct.ConsistencyError(u"footer", self._root, self._m_footer._root)
            if self._m_footer._parent != self:
                raise kaitaistruct.ConsistencyError(u"footer", self, self._m_footer._parent)

        if self.index__enabled:
            pass
            if self._m_index._root != self._root:
                raise kaitaistruct.ConsistencyError(u"index", self._root, self._m_index._root)
            if self._m_index._parent != self:
                raise kaitaistruct.ConsistencyError(u"index", self, self._m_index._parent)

        self._dirty = False

    class File(ReadWriteKaitaiStruct):
        def __init__(self, _io=None, _parent=None, _root=None):
            super(Fallout2Dat.File, self).__init__(_io)
            self._parent = _parent
            self._root = _root
            self._should_write_contents_raw = False
            self.contents_raw__enabled = True
            self._should_write_contents_zlib = False
            self.contents_zlib__enabled = True

        def _read(self):
            self.name = Fallout2Dat.Pstr(self._io, self, self._root)
            self.name._read()
            self.flags = KaitaiStream.resolve_enum(Fallout2Dat.Compression, self._io.read_u1())
            self.size_unpacked = self._io.read_u4le()
            self.size_packed = self._io.read_u4le()
            self.offset = self._io.read_u4le()
            self._dirty = False


        def _fetch_instances(self):
            pass
            self.name._fetch_instances()
            _ = self.contents_raw
            if hasattr(self, '_m_contents_raw'):
                pass

            _ = self.contents_zlib
            if hasattr(self, '_m_contents_zlib'):
                pass



        def _write__seq(self, io=None):
            super(Fallout2Dat.File, self)._write__seq(io)
            self._should_write_contents_raw = self.contents_raw__enabled
            self._should_write_contents_zlib = self.contents_zlib__enabled
            self.name._write__seq(self._io)
            self._io.write_u1(int(self.flags))
            self._io.write_u4le(self.size_unpacked)
            self._io.write_u4le(self.size_packed)
            self._io.write_u4le(self.offset)


        def _check(self):
            if self.name._root != self._root:
                raise kaitaistruct.ConsistencyError(u"name", self._root, self.name._root)
            if self.name._parent != self:
                raise kaitaistruct.ConsistencyError(u"name", self, self.name._parent)
            if self.contents_raw__enabled:
                pass
                if self.flags == Fallout2Dat.Compression.none:
                    pass
                    if len(self._m_contents_raw) != self.size_unpacked:
                        raise kaitaistruct.ConsistencyError(u"contents_raw", self.size_unpacked, len(self._m_contents_raw))


            if self.contents_zlib__enabled:
                pass
                if self.flags == Fallout2Dat.Compression.zlib:
                    pass


            self._dirty = False

        @property
        def contents(self):
            if hasattr(self, '_m_contents'):
                return self._m_contents

            if  ((self.flags == Fallout2Dat.Compression.zlib) or (self.flags == Fallout2Dat.Compression.none)) :
                pass
                self._m_contents = (self.contents_zlib if self.flags == Fallout2Dat.Compression.zlib else self.contents_raw)

            return getattr(self, '_m_contents', None)

        def _invalidate_contents(self):
            del self._m_contents
        @property
        def contents_raw(self):
            if self._should_write_contents_raw:
                self._write_contents_raw()
            if hasattr(self, '_m_contents_raw'):
                return self._m_contents_raw

            if not self.contents_raw__enabled:
                return None

            if self.flags == Fallout2Dat.Compression.none:
                pass
                io = self._root._io
                _pos = io.pos()
                io.seek(self.offset)
                self._m_contents_raw = io.read_bytes(self.size_unpacked)
                io.seek(_pos)

            return getattr(self, '_m_contents_raw', None)

        @contents_raw.setter
        def contents_raw(self, v):
            self._dirty = True
            self._m_contents_raw = v

        def _write_contents_raw(self):
            self._should_write_contents_raw = False
            if self.flags == Fallout2Dat.Compression.none:
                pass
                io = self._root._io
                _pos = io.pos()
                io.seek(self.offset)
                io.write_bytes(self._m_contents_raw)
                io.seek(_pos)


        @property
        def contents_zlib(self):
            if self._should_write_contents_zlib:
                self._write_contents_zlib()
            if hasattr(self, '_m_contents_zlib'):
                return self._m_contents_zlib

            if not self.contents_zlib__enabled:
                return None

            if self.flags == Fallout2Dat.Compression.zlib:
                pass
                io = self._root._io
                _pos = io.pos()
                io.seek(self.offset)
                self._raw__m_contents_zlib = io.read_bytes(self.size_packed)
                self._m_contents_zlib = zlib.decompress(self._raw__m_contents_zlib)
                io.seek(_pos)

            return getattr(self, '_m_contents_zlib', None)

        @contents_zlib.setter
        def contents_zlib(self, v):
            self._dirty = True
            self._m_contents_zlib = v

        def _write_contents_zlib(self):
            self._should_write_contents_zlib = False
            if self.flags == Fallout2Dat.Compression.zlib:
                pass
                io = self._root._io
                _pos = io.pos()
                io.seek(self.offset)
                self._raw__m_contents_zlib = zlib.compress(self._m_contents_zlib)
                if len(self._raw__m_contents_zlib) != self.size_packed:
                    raise kaitaistruct.ConsistencyError(u"contents_zlib", self.size_packed, len(self._raw__m_contents_zlib))
                io.write_bytes(self._raw__m_contents_zlib)
                io.seek(_pos)



    class Footer(ReadWriteKaitaiStruct):
        def __init__(self, _io=None, _parent=None, _root=None):
            super(Fallout2Dat.Footer, self).__init__(_io)
            self._parent = _parent
            self._root = _root

        def _read(self):
            self.index_size = self._io.read_u4le()
            self.file_size = self._io.read_u4le()
            self._dirty = False


        def _fetch_instances(self):
            pass


        def _write__seq(self, io=None):
            super(Fallout2Dat.Footer, self)._write__seq(io)
            self._io.write_u4le(self.index_size)
            self._io.write_u4le(self.file_size)


        def _check(self):
            self._dirty = False


    class Index(ReadWriteKaitaiStruct):
        def __init__(self, _io=None, _parent=None, _root=None):
            super(Fallout2Dat.Index, self).__init__(_io)
            self._parent = _parent
            self._root = _root

        def _read(self):
            self.file_count = self._io.read_u4le()
            self.files = []
            for i in range(self.file_count):
                _t_files = Fallout2Dat.File(self._io, self, self._root)
                try:
                    _t_files._read()
                finally:
                    self.files.append(_t_files)

            self._dirty = False


        def _fetch_instances(self):
            pass
            for i in range(len(self.files)):
                pass
                self.files[i]._fetch_instances()



        def _write__seq(self, io=None):
            super(Fallout2Dat.Index, self)._write__seq(io)
            self._io.write_u4le(self.file_count)
            for i in range(len(self.files)):
                pass
                self.files[i]._write__seq(self._io)



        def _check(self):
            if len(self.files) != self.file_count:
                raise kaitaistruct.ConsistencyError(u"files", self.file_count, len(self.files))
            for i in range(len(self.files)):
                pass
                if self.files[i]._root != self._root:
                    raise kaitaistruct.ConsistencyError(u"files", self._root, self.files[i]._root)
                if self.files[i]._parent != self:
                    raise kaitaistruct.ConsistencyError(u"files", self, self.files[i]._parent)

            self._dirty = False


    class Pstr(ReadWriteKaitaiStruct):
        def __init__(self, _io=None, _parent=None, _root=None):
            super(Fallout2Dat.Pstr, self).__init__(_io)
            self._parent = _parent
            self._root = _root

        def _read(self):
            self.size = self._io.read_u4le()
            self.str = (self._io.read_bytes(self.size)).decode(u"ASCII")
            self._dirty = False


        def _fetch_instances(self):
            pass


        def _write__seq(self, io=None):
            super(Fallout2Dat.Pstr, self)._write__seq(io)
            self._io.write_u4le(self.size)
            self._io.write_bytes((self.str).encode(u"ASCII"))


        def _check(self):
            if len((self.str).encode(u"ASCII")) != self.size:
                raise kaitaistruct.ConsistencyError(u"str", self.size, len((self.str).encode(u"ASCII")))
            self._dirty = False


    @property
    def footer(self):
        if self._should_write_footer:
            self._write_footer()
        if hasattr(self, '_m_footer'):
            return self._m_footer

        if not self.footer__enabled:
            return None

        _pos = self._io.pos()
        self._io.seek(self._io.size() - 8)
        self._m_footer = Fallout2Dat.Footer(self._io, self, self._root)
        self._m_footer._read()
        self._io.seek(_pos)
        return getattr(self, '_m_footer', None)

    @footer.setter
    def footer(self, v):
        self._dirty = True
        self._m_footer = v

    def _write_footer(self):
        self._should_write_footer = False
        _pos = self._io.pos()
        self._io.seek(self._io.size() - 8)
        self._m_footer._write__seq(self._io)
        self._io.seek(_pos)

    @property
    def index(self):
        if self._should_write_index:
            self._write_index()
        if hasattr(self, '_m_index'):
            return self._m_index

        if not self.index__enabled:
            return None

        _pos = self._io.pos()
        self._io.seek((self._io.size() - 8) - self.footer.index_size)
        self._m_index = Fallout2Dat.Index(self._io, self, self._root)
        self._m_index._read()
        self._io.seek(_pos)
        return getattr(self, '_m_index', None)

    @index.setter
    def index(self, v):
        self._dirty = True
        self._m_index = v

    def _write_index(self):
        self._should_write_index = False
        _pos = self._io.pos()
        self._io.seek((self._io.size() - 8) - self.footer.index_size)
        self._m_index._write__seq(self._io)
        self._io.seek(_pos)