pyffi.formats
— File format interfaces¶
When experimenting with any of the supported file formats, you can specify
an alternate location where you store your modified format description by means
of an environment variable. For instance,
to tell the library to use your version of cgf.xml
,
set the CGFXMLPATH
environment variable to the directory where
cgf.xml
can be found. The environment variables NIFXMLPATH
,
KFMXMLPATH
, DDSXMLPATH
, and TGAXMLPATH
work similarly.
Supported formats¶
pyffi.formats.bsa
— Bethesda Archive (.bsa)pyffi.formats.cgf
— Crytek (.cgf and .cga)pyffi.formats.dae
— COLLADA (.dae)pyffi.formats.dds
— DirectDraw Surface (.dds)pyffi.formats.egm
— EGM (.egm)pyffi.formats.egt
— EGT (.egt)pyffi.formats.esp
— Elder Scrolls plugin/master/save files (.esp, .esm, and .ess)pyffi.formats.kfm
— NetImmerse/Gamebryo Keyframe Motion (.kfm)pyffi.formats.nif
— NetImmerse/Gamebryo (.nif and .kf)pyffi.formats.tga
— Targa (.tga)pyffi.formats.tri
— TRI (.tri)
Adding new formats¶
This section tries to explain how you can implement your own format in pyffi.
Getting Started¶
Note that the files which make up the following example can all be found in the examples/simple directory of the source distribution of pyffi.
Suppose you have a simple file format, which consists of an integer,
followed by a list of integers as many as described by the first
integer. We start by creating an XML file, call it simple.xml
,
which describes this format in a way that pyffi can understand:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE fileformat>
<fileformat version="1.0">
<basic name="Int">A signed 32-bit integer.</basic>
<struct name="Example">
<add name="Num Integers" type="Int">
Number of integers that follow.
</add>
<add name="Integers" type="Int" arr1="Num Integers">
A list of integers.
</add>
</struct>
</fileformat>
What pyffi does is convert this simple XML description into Python classes
which automatically can read and write the structure you’ve just described.
Say this is the contents of simple.py
:
import os
import pyffi.object_models.xml
import pyffi.object_models.common
class SimpleFormat(pyffi.object_models.xml.FileFormat):
xml_file_name = 'simple.xml'
xml_file_path = [ os.path.dirname(__file__) ]
# basic types
Int = pyffi.object_models.common.Int
# extensions of generated types
class Data(pyffi.object_models.xml.FileFormat.Data):
def __init__(self):
self.example = SimpleFormat.Example()
def read(self, stream):
self.example.read(stream, self)
def write(self, stream):
self.example.write(stream, self)
class Example:
def addInteger(self, x):
self.numIntegers += 1
self.integers.update_size()
self.integers[self.numIntegers-1] = x
What happens in this piece of code?
The
pyffi.object_models.xml.FileFormat
base class triggers the transformation of xml into Python classes; how these classes can be used will be explained further.The
xml_file_name
class attribute provides the name of the xml file that describes the structures we wish to generate. Thexml_file_path
attribute gives a list of locations of where to look for this file; in our case we have simply chosen to putsimple.xml
in the same directory assimple.py
.The
SimpleFormat.Example
class provides the generated class with a functionaddInteger()
in addition to the attributesnumIntegers
andintegers
which have been created from the XML.Finally, the
pyffi.object_models.common
module implements the most common basic types, such as integers, characters, and floats. In the above example we have taken advantage ofpyffi.object_models.common.Int
, which defines a signed 32-bit integer, exactly the type we need.
Reading and Writing Files¶
To read the contents of a file of the format described by simple.xml:
from simple import SimpleFormat
x = SimpleFormat.Data()
f = open('somefile.simple', 'rb')
x.read(f)
f.close()
print(x.example)
Or, to create a new file in this format:
from simple import SimpleFormat
x = SimpleFormat.Data()
x.example.num_integers = 5
x.example.integers.update_size()
x.example.integers[0] = 3
x.example.integers[1] = 1
x.example.integers[2] = 4
x.example.integers[3] = 1
x.example.integers[4] = 5
f = open('pi.simple', 'wb')
x.write(f)
f.close()
Further References¶
With the above simple example in mind, you may wish to browse through
the source code of pyffi.formats.cgf
or
pyffi.formats.nif
to see how pyffi works for more complex file
formats.