pyffi.formats.bsa — Bethesda Archive (.bsa)

Last Built: Mar 06, 2020

pyffi.formats.bsa — Bethesda Archive (.bsa)

Warning

This module is still a work in progress, and is not yet ready for production use.

A .bsa file is an archive format used by Bethesda (Morrowind, Oblivion, Fallout 3).

Implementation

class pyffi.formats.bsa.BsaFormat[source]

Bases: pyffi.object_models.xml.FileFormat

This class implements the BSA format.

class BZString(**kwargs)[source]

Bases: pyffi.object_models.common.SizedString

get_size(data=None)[source]

Return number of bytes this type occupies in a file.

Returns

Number of bytes.

read(stream, data=None)[source]

Read string from stream.

Parameters

stream (file) – The stream to read from.

write(stream, data=None)[source]

Write string to stream.

Parameters

stream (file) – The stream to write to.

Data

alias of Header

class FileVersion(**kwargs)[source]

Bases: pyffi.object_models.common.UInt

Basic type which implements the header of a BSA file.

get_size(data=None)[source]

Return number of bytes the header string occupies in a file.

Returns

Number of bytes.

read(stream, data)[source]

Read header string from stream and check it.

Parameters

stream (file) – The stream to read from.

write(stream, data)[source]

Write the header string to stream.

Parameters

stream (file) – The stream to write to.

class Hash(**kwargs)[source]

Bases: pyffi.object_models.common.UInt64

get_detail_display()[source]

Return an object that can be used to display the instance.

class Header(template=None, argument=None, parent=None)[source]

Bases: pyffi.formats.bsa._Header, pyffi.object_models.Data

A class to contain the actual bsa data.

inspect(stream)[source]

Quickly checks if stream contains BSA data, and reads the header.

Parameters

stream (file) – The stream to inspect.

inspect_quick(stream)[source]

Quickly checks if stream contains BSA data, and gets the version, by looking at the first 8 bytes.

Parameters

stream (file) – The stream to inspect.

read(stream)[source]

Read a bsa file.

Parameters

stream (file) – The stream from which to read.

write(stream)[source]

Write a bsa file.

Parameters

stream (file) – The stream to which to write.

UInt32

alias of pyffi.object_models.common.UInt

class ZString(**kwargs)

Bases: pyffi.object_models.xml.basic.BasicBase, pyffi.object_models.editable.EditableLineEdit

String of variable length (null terminated).

>>> from tempfile import TemporaryFile
>>> f = TemporaryFile()
>>> s = ZString()
>>> if f.write('abcdefghijklmnopqrst\x00'.encode("ascii")): pass # b'abc...'
>>> if f.seek(0): pass # ignore result for py3k
>>> s.read(f)
>>> str(s)
'abcdefghijklmnopqrst'
>>> if f.seek(0): pass # ignore result for py3k
>>> s.set_value('Hi There!')
>>> s.write(f)
>>> if f.seek(0): pass # ignore result for py3k
>>> m = ZString()
>>> m.read(f)
>>> str(m)
'Hi There!'
get_hash(data=None)

Return a hash value for this string.

Returns

An immutable object that can be used as a hash.

get_size(data=None)

Return number of bytes this type occupies in a file.

Returns

Number of bytes.

get_value()

Return the string.

Returns

The stored string.

Return type

C{bytes}

read(stream, data=None)

Read string from stream.

Parameters

stream (file) – The stream to read from.

set_value(value)

Set string to C{value}.

Parameters

value (str (will be encoded as default) or C{bytes}) – The value to assign.

write(stream, data=None)

Write string to stream.

Parameters

stream (file) – The stream to write to.

static version_number(version_str)[source]

Converts version string into an integer.

Parameters

version_str (str) – The version string.

Returns

A version integer.

>>> BsaFormat.version_number('103')
103
>>> BsaFormat.version_number('XXX')
-1

Regression tests

Read a BSA file

>>> # check and read bsa file
>>> from os.path import dirname
>>> dirpath = __file__
>>> for i in range(4): #recurse up to root repo dir
...     dirpath = dirname(dirpath)
>>> repo_root = dirpath
>>> format_root = os.path.join(repo_root, 'tests', 'formats', 'bsa')
>>> stream = open(os.path.join(format_root, 'test.bsa'), 'rb')
>>> data = BsaFormat.Data()
>>> data.inspect_quick(stream)
>>> data.version
103
>>> data.inspect(stream)
>>> data.folders_offset
36
>>> hex(data.archive_flags.get_attributes_values(data))
'0x703'
>>> data.num_folders
1
>>> data.num_files
7
>>> #data.read(stream)
>>> # TODO check something else...

Parse all BSA files in a directory tree

>>> for stream, data in BsaFormat.walkData(format_root):
...     try:
...         # the replace call makes the doctest also pass on windows
...         os_path = stream.name
...         split = (os_path.split(os.sep))[-4:]
...         rejoin = os.path.join(*split).replace(os.sep, "/")
...         print("reading %s" % rejoin)
...         data.read(stream)
...     except Exception:
...         print(
...             "Warning: read failed due corrupt file,"
...             " corrupt format description, or bug.") 
reading tests/formats/bsa/test.bsa

Create an BSA file from scratch and write to file

>>> data = BsaFormat.Data()
>>> # TODO store something...
>>> from tempfile import TemporaryFile
>>> stream = TemporaryFile()
>>> #data.write(stream)