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
|
package xls
import (
"encoding/binary"
"math"
"reflect"
"testing"
)
func rkInt(n int32, div100 bool) uint32 {
rk := uint32(n)<<2 | 0x02
if div100 {
rk |= 0x01
}
return rk
}
func TestDecodeRK(t *testing.T) {
tests := []struct {
rk uint32
want float64
}{
{rkInt(1460, false), 1460},
{rkInt(-677083, true), -6770.83},
{rkInt(-1, false), -1},
{rkInt(4670, true), 46.7},
// Float form: the top 30 bits of an IEEE double.
{uint32(math.Float64bits(-11800) >> 32), -11800},
}
for _, tt := range tests {
if got := decodeRK(tt.rk); math.Abs(got-tt.want) > 1e-9 {
t.Errorf("decodeRK(%#x) = %v, want %v", tt.rk, got, tt.want)
}
}
}
type builder struct{ b []byte }
func (w *builder) rec(typ uint16, data []byte) {
w.b = binary.LittleEndian.AppendUint16(w.b, typ)
w.b = binary.LittleEndian.AppendUint16(w.b, uint16(len(data)))
w.b = append(w.b, data...)
}
func cellHead(row, col uint16) []byte {
b := binary.LittleEndian.AppendUint16(nil, row)
b = binary.LittleEndian.AppendUint16(b, col)
return binary.LittleEndian.AppendUint16(b, 0) // xf
}
func TestParseWorkbook(t *testing.T) {
// SST with two strings; the second ("Bærum", stored as UTF-16) is split
// across a CONTINUE record, which restarts with its own option byte.
sst := binary.LittleEndian.AppendUint32(nil, 2)
sst = binary.LittleEndian.AppendUint32(sst, 2)
sst = append(sst, 5, 0, 0)
sst = append(sst, "Konto"...)
sst = append(sst, 5, 0, 1, 'B', 0, 0xE6, 0)
cont := []byte{0, 'r', 'u', 'm'}
var sheet builder
sheet.rec(recBOF, make([]byte, 16))
sheet.rec(recLabelSST, binary.LittleEndian.AppendUint32(cellHead(0, 0), 0))
sheet.rec(recLabelSST, binary.LittleEndian.AppendUint32(cellHead(0, 1), 1))
sheet.rec(recRK, binary.LittleEndian.AppendUint32(cellHead(1, 0), rkInt(1460, false)))
mulrk := binary.LittleEndian.AppendUint16(nil, 1)
mulrk = binary.LittleEndian.AppendUint16(mulrk, 1)
for _, v := range []uint32{rkInt(-677083, true), rkInt(5, false)} {
mulrk = binary.LittleEndian.AppendUint16(mulrk, 0)
mulrk = binary.LittleEndian.AppendUint32(mulrk, v)
}
mulrk = binary.LittleEndian.AppendUint16(mulrk, 2)
sheet.rec(recMulRK, mulrk)
sheet.rec(recNumber, binary.LittleEndian.AppendUint64(cellHead(2, 0), math.Float64bits(44587.125)))
sheet.rec(recEOF, nil)
// The globals substream, with the BOUNDSHEET offset patched once its
// own length is known.
var globals builder
globals.rec(recBOF, make([]byte, 16))
globals.rec(recBoundSheet, append(make([]byte, 6), 1, 0, 'S'))
globals.rec(recSST, sst)
globals.rec(recContinue, cont)
globals.rec(recEOF, nil)
binary.LittleEndian.PutUint32(globals.b[20+4:], uint32(len(globals.b)))
grid, err := ParseWorkbook(append(globals.b, sheet.b...))
if err != nil {
t.Fatal(err)
}
want := [][]string{
{"Konto", "Bærum"},
{"1460", "-6770.83", "5"},
{"44587.125"},
}
if !reflect.DeepEqual(grid, want) {
t.Fatalf("grid = %q, want %q", grid, want)
}
}
|