-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpixi.go
89 lines (79 loc) · 2.37 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
package pixi
import (
"io"
"slices"
)
const (
FileType string = "pixi" // Every file starts with these four bytes.
Version int = 1 // Every file has a version number as the second set of four bytes.
)
// Represents a single pixi file composed of one or more layers. Functions as a handle
// to access the description of the each layer as well as the data stored in each layer.
type Pixi struct {
Header *PixiHeader // The metadata about the file version and how to read information from the file.
Layers []*Layer // The metadata information about each layer in the file.
Tags []*TagSection // The string tags of the file, broken up into sections for easy appending.
}
// Convenience function to read all the metadata information from a Pixi file into a single
// containing struct.
func ReadPixi(r io.ReadSeeker) (*Pixi, error) {
pixi := &Pixi{
Header: &PixiHeader{},
Layers: make([]*Layer, 0),
Tags: make([]*TagSection, 0),
}
seenOffsets := []int64{}
// read the header first, then the layers and tags.
err := pixi.Header.ReadHeader(r)
if err != nil {
return pixi, err
}
layerOffset := pixi.Header.FirstLayerOffset
for layerOffset != 0 {
if slices.Contains(seenOffsets, layerOffset) {
return pixi, FormatError("loop detected in layer offsets")
}
seenOffsets = append(seenOffsets, layerOffset)
_, err = r.Seek(layerOffset, io.SeekStart)
if err != nil {
return pixi, err
}
rdLayer := &Layer{}
err = rdLayer.ReadLayer(r, pixi.Header)
if err != nil {
return pixi, err
}
pixi.Layers = append(pixi.Layers, rdLayer)
layerOffset = rdLayer.NextLayerStart
}
tagOffset := pixi.Header.FirstTagsOffset
for tagOffset != 0 {
if slices.Contains(seenOffsets, tagOffset) {
return pixi, FormatError("loop detected in tag offsets")
}
seenOffsets = append(seenOffsets, layerOffset)
_, err := r.Seek(tagOffset, io.SeekStart)
if err != nil {
return pixi, err
}
rdTags := &TagSection{}
err = rdTags.Read(r, pixi.Header)
if err != nil {
return pixi, err
}
pixi.Tags = append(pixi.Tags, rdTags)
tagOffset = rdTags.NextTagsStart
}
return pixi, nil
}
// 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
}