LazPaint LZP directory structure

From Lazarus wiki
Revision as of 16:06, 4 December 2020 by Circular (talk | contribs) (tree)

The directory structure contains additional information about the layered image, in particular originals used to render the layers.

Global header

Offset  Size  Content
------  ----  -------------------------------------------------------
0       16    Contains the string 'TMemDirectory' followed by the bytes 1A 00 00
16      8     Root 64-bit offset R0
24      8     Root 64-bit size S0
R0      S0    Root entry

The headers thus locates the root of the directory structure.

Directory

The root directory and the subdirectory have the same format.

Offset  Size  Content
------  ----  -------------------------------------------------------
0       4     Number of entries in the directory
4             First entry if any

All entries are one after another.

Entry

An entry has a variable length depending on its content.

Offset  Size  Content
------  ----  -------------------------------------------------------
0       2     Flags of the entry
2       2     Filename size in bytes FS
4       8     Offset to the content (relative to the global header)
12      8     Compressed size CS (optional)
20      8     Uncompressed size UC (optional)
?             Filename (not null terminated)

Possible flags:

  • 1: the entry is a directory
  • 2: the entry is compressed
  • $8000: the entry is small (content and name each 255 bytes or less)
Small entry

When the entry is small, the size fields are not supplied, so the entry header size without filename is 12 bytes. The content size is extracted from the filename size field. The content cannot be compressed.

CS = UC = FS shr 8
FS = FS and 255

The entry header can also be summarized as:

Offset  Size  Content
------  ----  -------------------------------------------------------
0       2     Flags of the entry
2       1     Filename size in bytes FS
3       1     Content size
4       8     Offset to the content (relative to the global header)
12      FS    Filename (not null terminated)
Non small entry

When the entry is not small, the entry header size without filename is 28 bytes. The content can be compressed using the adequate flag.

The filename is not null terminated and encoded as UTF8. Its size is supplied in bytes and not in characters.

Entry content

The entry content offset is relative to the start of the global header of the directory structure. If the flag directory flag is set, then it is to be interpreted as a directory like the root directory. Otherwise, it is to be interpreted as a file.

The root is the path '/'. An entry in the root and called 'hello' has the path '/hello'.

When directories are nested, the resulting path is concatenated with a '/' character as in Unix paths. For example, if there is a subdirectory called 'container' in the root directory and that it contains a file called 'readme.txt', then its path is '/container/readme.txt'.

A file that does not contain '.' has thus no extension and is considered to be an attribute. An attribute is a value associated to the object that the directory represents, like a number or a list of numbers.

If a file is not an attribute, it is similar to file that would be saved on a disk, like an image in PNG format.

Attributes

An attribute can have various types, but those are not saved explicitly. The reader needs to know what kind of value it expects from an attribute. Attributes are stored in ASCII unless specified.

Here is the list of possible types:

  • integer: an optional sign and a sequence of digits forming a signed 32-bit integer.
  • float: a single precision floating point number written using '.' decimal separator and that can have an exponent E.
  • boolean: either 'true' or 'false'
  • string: any sequence of characters (quotes are not added)
  • color: can be a VGA or CSS color name, an RGB value with or without hashtag using one or two digit per channel with or without the alpha channel (example: red = #f00 = ff0000ff), an RGB value expressed in CSS format (exemple: rgb(255,0,0) = rgba(100%,0,0,1))
  • list of float: float values (or 'none' to specify undefined) separated by ','
  • list of colors: color values separated by ','
  • affine matrix: an affine matrix stored as binary so a sequence of 6 single precision floats (each 4 bytes in little endian) representing ux, uy, vx, vy, tx and tx

Note:

  • a 2D coordinate is a list of 2 values (x and y), a 2D rectangle is a list of 4 values (left, top, right and bottom).
  • the affine matrix is stored as binary to ensure exact equality when comparing matrices

Tree

Here as an example of tree structure of a LazPaint file, with 3 layers and 2 originals.

The first two layers has some registry entries, for example if layer1 is an effect generated for layer2.

The second layer contains render backup, for example because it contains text that might not be rendered the same way on a different computer.

There are two originals for example because layer2 is a vector layer and layer3 is a rotated image.

root
  ├─ layers
  │   ├─ layer1
  │   │    └─ registry
  │   ├─ layer2
  │   │    ├─ registry
  │   │    └─ render
  │   └─ layer3
  ├─ originals
  │   ├─ {7F5D5954-8EAC-D992-6D0A-9CD24929EBEB}
  │   │    ├─ shape1
  │   │    ├─ shape2
  │   │    └─ shape3
  │   └─ {61BD152C-9F86-1325-B256-B50D877389E8}
  └─ registry