/
freexl.go
185 lines (151 loc) · 3.6 KB
/
freexl.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
package freexl
/*
#cgo linux pkg-config: freexl
#cgo darwin LDFLAGS: -lfreexl
#cgo windows LDFLAGS: -lfreexl
#include <stdlib.h>
#include <stdio.h>
#include <freexl.h>
// End Import
static int freexl_cell_get_type(FreeXL_CellValue cell) {
return cell.type;
}
static int freexl_cell_get_int_value(FreeXL_CellValue cell) {
return cell.value.int_value;
}
static double freexl_cell_get_double_value(FreeXL_CellValue cell) {
return cell.value.double_value;
}
static const char * freexl_cell_get_text_value(FreeXL_CellValue cell) {
return cell.value.text_value;
}
*/
import "C"
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"unsafe"
)
// Freexl handle
type Freexl struct {
handle unsafe.Pointer
MaxSheet int
Sheets []Sheet
}
// Sheet handle
type Sheet struct {
MaxRow int
MaxCol int
Name string
Values [][]string
}
// Open filepath
func Open(path string) (f *Freexl, err error) {
f = &Freexl{}
err = f.Open(path)
if err != nil {
return nil, err
}
return f, nil
}
// OpenReader with temporary file
func OpenReader(r io.Reader) (f *Freexl, err error) {
f = &Freexl{}
tmp, err := ioutil.TempFile(os.TempDir(), "freexls")
if err != nil {
return nil, err
}
defer os.Remove(tmp.Name())
_, err = io.Copy(tmp, r)
if err != nil {
return nil, err
}
err = f.Open(tmp.Name())
if err != nil {
return nil, err
}
return f, nil
}
// OpenBinary with temporary file
func OpenBinary(b []byte) (f *Freexl, err error) {
return OpenReader(bytes.NewReader(b))
}
// Open file with defined handle
func (f *Freexl) Open(path string) error {
pName := C.CString(path)
defer C.free(unsafe.Pointer(pName))
defer C.freexl_close(f.handle)
ret := C.freexl_open(pName, &f.handle)
if ret != OK {
return fmt.Errorf("Freexl: error opening %s : %d", path, ret)
}
info, err := f.getInfo(BIFF_SHEET_COUNT)
if err != nil {
return err
}
f.MaxSheet = info
f.Sheets = make([]Sheet, f.MaxSheet)
for i, sheet := range f.Sheets {
if err = sheet.getInfo(i, f.handle); err != nil {
return err
}
f.Sheets[i] = sheet
}
return nil
}
func (f *Freexl) getInfo(t int) (int, error) {
var info C.uint
ret := C.freexl_get_info(f.handle, C.ushort(t), &info)
if ret != OK {
return 0, fmt.Errorf("Freexl: error get info %d: %d", t, ret)
}
return int(info), nil
}
func (s *Sheet) getInfo(i int, handle unsafe.Pointer) error {
var name *C.char
var numRow C.uint
var numCol C.ushort
ret := C.freexl_get_worksheet_name(handle, C.ushort(i), &name)
if ret != OK {
return fmt.Errorf("Freexl: error get sheet name :%d", ret)
}
s.Name = C.GoString(name)
ret = C.freexl_select_active_worksheet(handle, C.ushort(i))
if ret != OK {
return fmt.Errorf("Freexl: failed to selct worksheet: %s", ret)
}
ret = C.freexl_worksheet_dimensions(handle, &numRow, &numCol)
if ret != OK {
return fmt.Errorf("Freexl: failed to get dimensions: %s", ret)
}
s.MaxRow = int(numRow)
s.MaxCol = int(numCol)
s.Values = make([][]string, s.MaxRow)
for i, row := range s.Values {
row = make([]string, s.MaxCol)
var cell C.FreeXL_CellValue
for j := range row {
ret = C.freexl_get_cell_value(handle, C.uint(i), C.ushort(j), &cell)
if ret != OK {
continue
}
switch C.freexl_cell_get_type(cell) {
case CELL_DOUBLE:
row[j] = fmt.Sprintf("%1.12f", float64(C.freexl_cell_get_double_value(cell)))
case CELL_INT:
row[j] = fmt.Sprintf("%d", int(C.freexl_cell_get_int_value(cell)))
case CELL_TEXT, CELL_SST_TEXT, CELL_DATE, CELL_DATETIME, CELL_TIME:
row[j] = C.GoString(C.freexl_cell_get_text_value(cell))
default:
fallthrough
case CELL_NULL:
row[j] = ""
}
}
s.Values[i] = row
}
return nil
}