### Navigation

- index
- modules |
- next |
- previous |
- PyFFI 2.2.2 documentation »
- `pyffi` — Interfacing block structured files »

# `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)
  - Implementation
  - Regression tests
- `pyffi.formats.cgf` — Crytek (.cgf and .cga)
  - Implementation
  - Regression tests
- `pyffi.formats.dae` — COLLADA (.dae)
  - Implementation
  - Regression tests
- `pyffi.formats.dds` — DirectDraw Surface (.dds)
  - Implementation
  - Regression tests
- `pyffi.formats.egm` — EGM (.egm)
  - Implementation
  - Regression tests
- `pyffi.formats.kfm` — NetImmerse/Gamebryo Keyframe Motion (.kfm)
  - Implementation
  - Regression tests
- `pyffi.formats.nif` — NetImmerse/Gamebryo (.nif and .kf)
  - Implementation
  - Regression tests
- `pyffi.formats.tga` — Targa (.tga)
  - Implementation
  - Regression tests
- `pyffi.formats.tri` — TRI (.tri)
  - Implementation
  - Regression tests

## 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. The `xml_file_path` attribute gives a list of locations of where to look for this file; in our case we have simply chosen to put `simple.xml` in the same directory as `simple.py`.
> - The `SimpleFormat.Example` class provides the generated class with a function `addInteger()` in addition to the attributes `numIntegers` and `integers` 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 of `pyffi.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.

### Navigation

- index
- modules |
- next |
- previous |
- PyFFI 2.2.2 documentation »
- `pyffi` — Interfacing block structured files »