PFP - Python Format Parser

Pfp (python format parser) is a python interpreter for 010 Editor template scripts.

Pfp uses py010parser to parse 010 templates into an AST, which is then interpreted by pfp. Pfp then returns a DOM object which can be used to access individual fields of the defined data structure.

Please read the Getting Started section for a better introduction.

TL;DR

Installation

pip install pfp

Console Script

Pfp comes with a console script that will print parsed data:

$> pfp --help
usage: pfp [-h] -t TEMPLATE [--show-offsets] [-k] input

Run pfp on input data using a specified 010 Editor template for parsing

positional arguments:
  input                 The input data stream or file to parse. Use '-' for
                        piped data

optional arguments:
  -h, --help            show this help message and exit
  -t TEMPLATE, --template TEMPLATE
                        The template to parse with
  --show-offsets        Show offsets in the parsed data of parsed fields
  -k, --keep            Keep successfully parsed data on error

Example usages:

pfp --keep -t png.bt test.png

cat test.png | pfp --keep -t png.bt -

pfp --keep -t png.bt - <test.png

PNG Parsing Example

Below is a simple PNG template that will parse the PNG image into chunks. The tEXt chunk of the PNG image will also specifically be parsed:

typedef struct {
    // null-terminated
    string label;

    char comment[length - sizeof(label)];
} TEXT;

typedef struct {
    uint length<watch=data, update=WatchLength>;
    char cname[4];

    union {
        char raw[length];

        if(cname == "tEXt") {
            TEXT tEXt;
        }
    } data;
    uint crc<watch=cname;data, update=WatchCrc32>;
} CHUNK;

uint64 magic;

while(!FEof()) {
    CHUNK chunks;
}

The python code below will use the template above to parse a PNG image, find the tEXt chunk, and change the comment:

import pfp

dom = pfp.parse(data_file="image.png", template_file="png_template.bt")

for chunk in png.chunks:
    if chunk.cname == "tEXt":
        print("Comment before: {}".format(chunk.data.tEXt.comment))
        chunk.data.tEXt.comment = "NEW COMMENT"
        print("Comment after: {}".format(chunk.data.tEXt.comment))

Notes

A few differences do exist between 010 Editor and pfp. See the Differences Between 010 and pfp section for specific, documented differences.

Contents:

pfp.create_interp(template_file=None, template=None)[source]

Create an Interp instance with the template preloaded

Template:template contents (str)
Template_file:template file path
Returns:Interp
pfp.parse(data=None, template=None, data_file=None, template_file=None, interp=None, debug=False, predefines=True, int3=True, keep_successful=False, printf=True)[source]

Parse the data stream using the supplied template. The data stream WILL NOT be automatically closed.

Data:Input data, can be either a string or a file-like object (StringIO, file, etc)
Template:template contents (str)
Data_file:PATH to the data to be used as the input stream
Template_file:template file path
Interp:the interpretor to be used (a default one will be created if None)
Debug:if debug information should be printed while interpreting the template (false)
Predefines:if built-in type information should be inserted (true)
Int3:if debugger breaks are allowed while interpreting the template (true)
Keep_successful:
 return any succesfully parsed data instead of raising an error. If an error occurred and keep_successful is True, then _pfp__error will be contain the exception object
Printf:if False, all calls to Printf (pfp.native.compat_interface.Printf) will be noops. (default=``True``)
Returns:pfp DOM

Indices and tables