-
Notifications
You must be signed in to change notification settings - Fork 7
/
table_sill.go
121 lines (103 loc) · 2.54 KB
/
table_sill.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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package graphite
import (
"encoding/binary"
"errors"
"fmt"
"sort"
"github.com/benoitkugler/textlayout/fonts/binaryreader"
)
type tableSill []languageRecord
// replace the trailing space by zero
func spaceToZero(x Tag) Tag {
switch {
case x == 0x20202020:
return 0
case (x & 0x00FFFFFF) == 0x00202020:
return x & 0xFF000000
case (x & 0x0000FFFF) == 0x00002020:
return x & 0xFFFF0000
case (x & 0x000000FF) == 0x00000020:
return x & 0xFFFFFF00
default:
return x
}
}
func zeroToSpace(x Tag) Tag {
switch {
case x == 0:
return 0x20202020
case (x & 0x00FFFFFF) == 0:
return x & 0xFF202020
case (x & 0x0000FFFF) == 0:
return x & 0xFFFF2020
case (x & 0x000000FF) == 0:
return x & 0xFFFFFF20
default:
return x
}
}
// getFeatures selects the features and values for the given language, or
// the default ones if the language is not found.
func (si tableSill) getFeatures(langname Tag, features tableFeat) FeaturesValue {
langname = spaceToZero(langname)
for _, rec := range si {
if rec.langcode == langname {
return rec.applyValues(features)
}
}
return features.defaultFeatures()
}
type languageRecord struct {
settings []languageSetting
langcode Tag
}
// resolve the feature
func (lr languageRecord) applyValues(features tableFeat) FeaturesValue {
var out FeaturesValue
for _, set := range lr.settings {
if _, ok := features.findFeature(set.FeatureId); ok {
out = append(out, FeatureValue{
ID: zeroToSpace(set.FeatureId), // from the internal convention to the external
Value: set.Value,
})
}
}
// sort by Id
sort.Slice(out, func(i, j int) bool { return out[i].ID < out[j].ID })
return out
}
type languageSetting struct {
FeatureId Tag
Value int16
_ [2]byte
}
func parseTableSill(data []byte) (tableSill, error) {
r := binaryreader.NewReader(data)
if len(data) < 12 {
return nil, errors.New("invalid Sill table (EOF)")
}
_, _ = r.Uint32()
numLangs, _ := r.Uint16()
r.Skip(6)
type languageEntry struct {
Langcode [4]byte
NumSettings uint16
Offset uint16
}
entries := make([]languageEntry, numLangs)
err := r.ReadStruct(entries)
if err != nil {
return nil, fmt.Errorf("invalid Sill table: %s", err)
}
out := make(tableSill, numLangs)
for i, entry := range entries {
out[i].langcode = Tag(binary.BigEndian.Uint32(entry.Langcode[:]))
out[i].settings = make([]languageSetting, entry.NumSettings)
r.SetPos(int(entry.Offset))
err := r.ReadStruct(out[i].settings)
if err != nil {
return nil, fmt.Errorf("invalid Sill table: %s", err)
}
}
return out, nil
}