-
Notifications
You must be signed in to change notification settings - Fork 0
/
pixi.go
101 lines (85 loc) · 2.56 KB
/
pixi.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package pixi
import "io"
const (
PixiFileType string = "pixi" // Every file starts with these four bytes.
PixiVersion int64 = 1 // Every file has a version number as the second set of four bytes.
)
// Information about how data is stored and organized for a particular data set
// inside a pixi file.
type Pixi struct {
Layers []*DiskLayer // The metadata information about each layer in the file.
}
func (d *Pixi) LayerOffset(l *DiskLayer) int64 {
offset := d.FirstLayerOffset()
for _, item := range d.Layers {
if item == l {
break
}
offset = item.NextLayerStart
}
return offset
}
func (d *Pixi) FirstLayerOffset() int64 {
// four for version, four for file type sequences
return 8
}
// The total size of the data portions of the file in bytes. Does not count header information
// as part of the size.
func (d *Pixi) DiskDataBytes() int64 {
size := int64(0)
for _, l := range d.Layers {
for _, t := range l.TileBytes {
size += t
}
}
return size
}
func (d *Pixi) AddBlankUncompressedLayer(backing io.ReadWriteSeeker, offset int64, layer Layer) (*DiskLayer, error) {
// seek to layer start
_, err := backing.Seek(offset, io.SeekStart)
if err != nil {
return nil, err
}
// compute tile sizes and offsets (easy since uncompressed)
diskLayer := &DiskLayer{Layer: layer}
diskLayer.Compression = CompressionNone
diskLayer.TileBytes = make([]int64, layer.DiskTiles())
diskLayer.TileOffsets = make([]int64, layer.DiskTiles())
tileOffset := offset + diskLayer.DiskHeaderSize()
for i := range diskLayer.TileBytes {
tileSize := int64(diskLayer.TileSize(i))
diskLayer.TileBytes[i] = tileSize
diskLayer.TileOffsets[i] = tileOffset
tileOffset += tileSize
}
// write the layer header
if err := WriteLayer(backing, *diskLayer); err != nil {
return nil, err
}
// write each tile in the layer, accounting for separated vs contiguous
buf := make([]byte, 0)
for i := 0; i < layer.DiskTiles(); i++ {
tileSize := layer.TileSize(i)
if tileSize != len(buf) {
buf = make([]byte, tileSize)
}
if _, err := backing.Write(buf); err != nil {
return nil, err
}
}
// write offset of previous layer last in case writes to current layer failed
if len(d.Layers) > 0 {
d.Layers[len(d.Layers)-1].NextLayerStart = offset
if err := WriteLayer(backing, *d.Layers[len(d.Layers)-1]); err != nil {
d.Layers[len(d.Layers)-1].NextLayerStart = 0
return nil, err
}
}
d.Layers = append(d.Layers, diskLayer)
return d.Layers[len(d.Layers)-1], nil
}
type Compression uint32
const (
CompressionNone Compression = 0
CompressionFlate Compression = 1
)