1. Header Block
2. Big Block Depot
3. Big Data Blocks
3.1 Small Block Depot
3.2 Property Set Storage
3.3 Property Storage
3.4 Where Are The Small Data Blocks?
3.5 Property Sets
4. Trash Blocks
Table 1: LAOLA Header
Table 2: Property Storage
Copying. This file and the here referenced source codes are distributed under the terms of Version 2 of the GNU General Public License from June 1991. If you have no copy you should find one here.
Diese Veröffentlichung erfolgt ohne Berücksichtigung eines eventuellen Patentschutzes. Warennamen werden ohne Gewährleistung einer freien Verwendung benutzt.
Data types. Laola files have three basic data types:
1. 4 byte integers ("long") 0x12345678 -> 0x78 0x56 0x34 0x12
2. 2 byte integers ("word") 0x1234 0x5678 -> 0x34 0x12 0x78 0x56
3. 1 byte integers ("char") 0x12 0x34 0x56 0x78 -> 0x12 0x34 0x56 0x78
Integers are stored in "little endian" ("VAX", "x86") mode. That means they
are stored eightbitwise, the least significant byte first. Char streams are
stored first in, first out.
file <=> union of big blocks {-1, 0, 1 .. $maxblock},
($maxblock = (sizeof(file)-1) / 0x200 -1), $maxblock e {1, 2, .. }
Basic parts.
The big blocks divide the file into the four basic parts:Dead non trash information. The Laola blocks seem to contain several constant data entries. Some of them seem to be (still?) with absolutely no function, the functions of others are still not clear. Anyway, for the creation of Laola files it would be enough just to copy these values. In the tables at the end of this document the constant values are marked with a dot ".", the known and changing values with an exclamation mark "!".
00000: d0 cf 11 e0 a1 b1 1a e1 00 00 00 00 00 00 00 00
00010: 00 00 00 00 00 00 00 00 3b 00 03 00 fe ff 09 00
00020: 06 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00
00030: 01 00 00 00 00 00 00 00 00 10 00 00 02 00 00 00
00040: 01 00 00 00 fe ff ff ff 00 00 00 00 00 00 00 00
00050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff *
00: stream $laola_id identifier {d0 cf 11 e0 a1 b1 1a e1}
2c: long $num_of_bbd_blocks Number of big block depot blocks
30: long $root_startblock Root chain's first big block
3c: long $sbd_startblock small block depot's first big block
4c[]: long $bbd_list[i] array of $num_of_bbd_blocks big block numbers
(for detailed info look at: Table 1)
big block depot <=> union of big blocks {bbd_list[i]},
bbd_list consists out of $num_of_bbd_blocks elements, stored from
position <header:4c> on.
Example:
00200: fd ff ff ff 05 00 00 00 fe ff ff ff 04 00 00 00 00210: 06 00 00 00 fe ff ff ff 07 00 00 00 08 00 00 00 00220: 09 00 00 00 0a 00 00 00 0b 00 00 00 fe ff ff ff 00230: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff *The big block depot is representing a table of block numbers, their index starts with zero. Entry 0, in this example with the value 0xfffffffd (-3), refers to block 0. Entry 1, with the value 0x00000005 refers to block 1. Entry 2 refers to block 2 ... and so on. Each entry may have one of these values:
0xfffffffd (-3) : this block is a special block 0xfffffffe (-2) : end of chain 0xffffffff (-1) : unused 0 .. $maxblock : next element of chain (a big block number) $maxblock+1 .. : not definedIn the header the variable $root_startblock has been initiated, the example gives the value 1 to it. These value tells which block is the first in a chain of blocks belonging to the "root". In the example it would be read out as follows:
Note: The small block depot may be absent. In that case $sbd_startblock is 0xfffffffe (-2).
small block depot <=> union of big blocks {sbd_list[i]},
sbd_list consists out of (number of chain_elements(sbd_list))
elements. The list is read out from the big block depot,
the lists start is $sbd_startblock (-> Section 2)
Example:
00600: 01 00 00 00 fe ff ff ff ff ff ff ff ff ff ff ff
00610: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
The entries of the small block depot do *not* refer to absolute positions
in the file, like the entries of the big block depot. They refer to the
positions in the (file made out of big blocks) according to the the big
block list @sbd. This list is denoted by the root entry of the property
storage. So first property storage has to be explained.
property set storage blocks <=> union of big blocks {root_list[i]},
root_list consists out of (number of chain_elements(root_list))
elements. The list is read out from the big block depot,
the lists start is $root_startblock (-> Section 2)
Example: 00400: 52 00 6f 00 6f 00 74 00 20 00 45 00 6e 00 74 00 R o o t E n t 00410: 72 00 79 00 00 00 00 00 00 00 00 00 00 00 00 00 r y 00420: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00430: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00440: 16 00 05 00 ff ff ff ff ff ff ff ff 03 00 00 00 00450: 00 09 02 00 00 00 00 00 c0 00 00 00 00 00 00 46 00460: 00 00 00 00 00 00 00 00 00 00 00 00 86 29 f6 1f 00470: ad 57 bb 01 03 00 00 00 00 0f 00 00 00 00 00 00 40: word $pps_sizeofname size of $pps_rawname 42: byte $pps_type type of pps (1=storage|2=stream|5=root) 44: long $pps_prev previous pps 48: long $pps_next next pps 4c: long $pps_dir directory pps 74: long $pps_sb starting block of property 78: long $pps_size size of property (for detailed info look at: Table 2)The first 0x40 bytes are reserved for the name of the pps. The length of the name stands in $pps_sizeofname. The name can be converted to an ASCII string $pps_name just by removing every second char. In this example the length of the name is 0x16, and in the end $pps_name is "Root Entry\00". The C-style zero should be removed. If the case occurs that $pps_sizeofname is zero, then this 0x80 block is no pps and has to be ignored.
Each pps can have a successor and a predecessor. Each pps also can be a directory (or "storage"). $pps_prev, $pps_next, $pps_dir refer to the ascending number of the 0x80 blocks as mentioned above. So in the example the pps starting at 0x400 gets the handle (number) 0, the pps starting at 0x480 gets the handle 1, the pps starting at 0500 gets the handle 2 and so on. When read skillfully, an ordered listing of pps results in the end (look at function get_pps_chain in "laola.pl").
Property types. Each pps has a type out of this three:
If $pps_size is not zero, $pps_sb points to the starting block of the belonging property. The starting block refers to the big block depot, if $pps_size is greater or equal 0x1000 (4096) bytes. If the property's size is smaller, $pps_sb refers to the small block depot. There is one exception: $pps_sb of the Root entry (always pps 0) does always refer to the big block depot.
It now is easy to read the "files" in: the big or small block list has to be catched (as did before with root_list and sbd_list) from the big or small block depots, the so referred blocks have to be read and at the last step the size might have to be truncated to fit to $pps_size.
If the type of a pps is root or storage, at least the variables $pps_ts2d and $pps_ts2s get initialized. Together these variables build a 64 bit integer variable, that represents time and date. This variable counts all 10^-7 seconds, starting at 01/01/1601 00:00. If the type is root, $pps_sb is pointing to the first big block of the small block list @sb_list. See just below:
00200: fd ff ff ff 05 00 00 00 fe ff ff ff 04 00 00 00
00210: 06 00 00 00 fe ff ff ff 07 00 00 00 08 00 00 00
00220: 09 00 00 00 0a 00 00 00 0b 00 00 00 fe ff ff ff
00230: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff *
it results in the chain: {3, 4, 6, 7, 8, 9, a, b}. The so yielded chain
gives the blocks that provide the space for the small blocks. So small
block references refer to positions in the "small block file", that in
this example is build of the big block chain starting with block 3.
small data blocks <=> union of big blocks {sb_list[i]},
sb_list consists out of (number of chain_elements(sb_list))
elements. The list is read out from the big block depot,
the lists start is
$root_startblock -> property storage 0 -> pps_sb
With this in mind, everything needed to pull out some file out of a Laola
archive is available. You could test this with
"lls -s". But there is still more behind the thing.Summary and further information are - still to be done ! -
Table 1: Block 0 (laola header)
offset type value const? function
00: stream $laola_id ! identifier {d0 cf 11 e0 a1 b1 1a e1}
08: long 0 . ?
0c: long 0 . ?
10: long 0 . ?
14: long 0 . ?
18: word 3b . ? revision ?
1a: word 3 . ? version ?
1c: word -2 . ?
1e: byte 9 . ?
1f: byte 0 . ?
20: long 6 . ?
24: long 0 . ?
28: long 0 . ?
2c: long $num_of_bbd_blocks ! Number of big block depot blocks
30: long $root_startblock ! Root chain 1st block
34: long 0 . ?
38: long 1000 . ?
3c: long $sbd_startblock ! small block depot 1st block
40: long 1 . ?
44: long -2 . ?
48: long 0 . ?
4c[]: long $bbd_list[i] ! array of $num_of_bbd_blocks big block
numbers
The rest of block 0 should be:
long -1 .
####
Table 2: Property Storage
offset type value const? function
00: stream $pps_rawname ! name of the pps
40: word $pps_sizeofname ! size of $pps_rawname
42: byte $pps_type ! type of pps (1=storage|2=stream|5=root)
43: byte $pps_uk0 ! ?
44: long $pps_prev ! previous pps
48: long $pps_next ! next pps
4c: long $pps_dir ! directory pps
50: stream 00 09 02 00 . ?
54: long 0 . ?
58: long c0 . ?
5c: stream 00 00 00 46 . ?
60: long 0 . ?
64: long $pps_ts1s ! timestamp 1 : "seconds"
68: long $pps_ts1d ! timestamp 1 : "days"
6c: long $pps_ts2s ! timestamp 2 : "seconds"
70: long $pps_ts2d ! timestamp 2 : "days"
74: long $pps_sb ! starting block of property
78: long $pps_size ! size of property
7c: long . ?