clean code and add some comments
This commit is contained in:
parent
4b7153c0ef
commit
e7a933588c
28
bof.go
28
bof.go
@ -1,31 +1,26 @@
|
|||||||
package xls
|
package xls
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"io"
|
"io"
|
||||||
"unicode/utf16"
|
"unicode/utf16"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BOF struct {
|
//the information unit in xls file
|
||||||
|
type bof struct {
|
||||||
Id uint16
|
Id uint16
|
||||||
Size uint16
|
Size uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BOF) Reader(buf io.ReadSeeker) io.ReadSeeker {
|
//read the utf16 string from reader
|
||||||
rts := make([]byte, b.Size)
|
func (b *bof) utf16String(buf io.ReadSeeker, count uint32) string {
|
||||||
buf.Read(rts)
|
|
||||||
return bytes.NewReader(rts)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BOF) Utf16String(buf io.ReadSeeker, count uint32) string {
|
|
||||||
var bts = make([]uint16, count)
|
var bts = make([]uint16, count)
|
||||||
binary.Read(buf, binary.LittleEndian, &bts)
|
binary.Read(buf, binary.LittleEndian, &bts)
|
||||||
runes := utf16.Decode(bts[:len(bts)-1])
|
runes := utf16.Decode(bts[:len(bts)-1])
|
||||||
return string(runes)
|
return string(runes)
|
||||||
}
|
}
|
||||||
|
|
||||||
type BIFFHeader struct {
|
type biffHeader struct {
|
||||||
Ver uint16
|
Ver uint16
|
||||||
Type uint16
|
Type uint16
|
||||||
Id_make uint16
|
Id_make uint16
|
||||||
@ -33,16 +28,3 @@ type BIFFHeader struct {
|
|||||||
Flags uint32
|
Flags uint32
|
||||||
Min_ver uint32
|
Min_ver uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
// func parseBofsForWb(bts []byte, wb *WorkBook) {
|
|
||||||
// bof := new(BOF)
|
|
||||||
// var bof_pre *BOF
|
|
||||||
// buf := bytes.NewReader(bts)
|
|
||||||
// for {
|
|
||||||
// if err := binary.Read(buf, binary.LittleEndian, bof); err == nil {
|
|
||||||
// bof_pre = bof.ActForWb(buf, wb, bof_pre)
|
|
||||||
// } else {
|
|
||||||
// break
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
@ -4,11 +4,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// range type of multi rows
|
||||||
type Ranger interface {
|
type Ranger interface {
|
||||||
FirstRow() uint16
|
FirstRow() uint16
|
||||||
LastRow() uint16
|
LastRow() uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// range type of multi cells in multi rows
|
||||||
type CellRange struct {
|
type CellRange struct {
|
||||||
FirstRowB uint16
|
FirstRowB uint16
|
||||||
LastRowB uint16
|
LastRowB uint16
|
||||||
@ -32,6 +34,7 @@ func (c *CellRange) LastCol() uint16 {
|
|||||||
return c.LastColB
|
return c.LastColB
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//hyperlink type's content
|
||||||
type HyperLink struct {
|
type HyperLink struct {
|
||||||
CellRange
|
CellRange
|
||||||
Description string
|
Description string
|
||||||
@ -43,6 +46,7 @@ type HyperLink struct {
|
|||||||
IsUrl bool
|
IsUrl bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//get the hyperlink string, use the public variable Url to get the original Url
|
||||||
func (h *HyperLink) String(wb *WorkBook) []string {
|
func (h *HyperLink) String(wb *WorkBook) []string {
|
||||||
res := make([]string, h.LastColB-h.FristColB+1)
|
res := make([]string, h.LastColB-h.FristColB+1)
|
||||||
var str string
|
var str string
|
||||||
|
3
col.go
3
col.go
@ -5,7 +5,8 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ContentHandler interface {
|
//content type
|
||||||
|
type contentHandler interface {
|
||||||
String(*WorkBook) []string
|
String(*WorkBook) []string
|
||||||
FirstCol() uint16
|
FirstCol() uint16
|
||||||
LastCol() uint16
|
LastCol() uint16
|
||||||
|
2
row.go
2
row.go
@ -12,5 +12,5 @@ type RowInfo struct {
|
|||||||
|
|
||||||
type Row struct {
|
type Row struct {
|
||||||
info *RowInfo
|
info *RowInfo
|
||||||
Cols map[uint16]ContentHandler
|
Cols map[uint16]contentHandler
|
||||||
}
|
}
|
||||||
|
16
workbook.go
16
workbook.go
@ -8,6 +8,7 @@ import (
|
|||||||
"unicode/utf16"
|
"unicode/utf16"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//xls workbook type
|
||||||
type WorkBook struct {
|
type WorkBook struct {
|
||||||
Is5ver bool
|
Is5ver bool
|
||||||
Type uint16
|
Type uint16
|
||||||
@ -22,7 +23,8 @@ type WorkBook struct {
|
|||||||
continue_utf16 uint16
|
continue_utf16 uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
func newWookBookFromOle2(rs io.ReadSeeker) *WorkBook {
|
//read workbook from ole2 file
|
||||||
|
func newWorkBookFromOle2(rs io.ReadSeeker) *WorkBook {
|
||||||
wb := new(WorkBook)
|
wb := new(WorkBook)
|
||||||
wb.Formats = make(map[uint16]*Format)
|
wb.Formats = make(map[uint16]*Format)
|
||||||
// wb.bts = bts
|
// wb.bts = bts
|
||||||
@ -33,13 +35,13 @@ func newWookBookFromOle2(rs io.ReadSeeker) *WorkBook {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *WorkBook) Parse(buf io.ReadSeeker) {
|
func (w *WorkBook) Parse(buf io.ReadSeeker) {
|
||||||
bof := new(BOF)
|
b := new(bof)
|
||||||
bof_pre := new(BOF)
|
bof_pre := new(bof)
|
||||||
// buf := bytes.NewReader(bts)
|
// buf := bytes.NewReader(bts)
|
||||||
offset := 0
|
offset := 0
|
||||||
for {
|
for {
|
||||||
if err := binary.Read(buf, binary.LittleEndian, bof); err == nil {
|
if err := binary.Read(buf, binary.LittleEndian, b); err == nil {
|
||||||
bof_pre, bof, offset = w.parseBof(buf, bof, bof_pre, offset)
|
bof_pre, b, offset = w.parseBof(buf, b, bof_pre, offset)
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -59,7 +61,7 @@ func (w *WorkBook) addFormat(format *Format) {
|
|||||||
w.Formats[format.Head.Index] = format
|
w.Formats[format.Head.Index] = format
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wb *WorkBook) parseBof(buf io.ReadSeeker, b *BOF, pre *BOF, offset_pre int) (after *BOF, after_using *BOF, offset int) {
|
func (wb *WorkBook) parseBof(buf io.ReadSeeker, b *bof, pre *bof, offset_pre int) (after *bof, after_using *bof, offset int) {
|
||||||
after = b
|
after = b
|
||||||
after_using = pre
|
after_using = pre
|
||||||
var bts = make([]byte, b.Size)
|
var bts = make([]byte, b.Size)
|
||||||
@ -67,7 +69,7 @@ func (wb *WorkBook) parseBof(buf io.ReadSeeker, b *BOF, pre *BOF, offset_pre int
|
|||||||
buf_item := bytes.NewReader(bts)
|
buf_item := bytes.NewReader(bts)
|
||||||
switch b.Id {
|
switch b.Id {
|
||||||
case 0x809:
|
case 0x809:
|
||||||
bif := new(BIFFHeader)
|
bif := new(biffHeader)
|
||||||
binary.Read(buf_item, binary.LittleEndian, bif)
|
binary.Read(buf_item, binary.LittleEndian, bif)
|
||||||
if bif.Ver != 0x600 {
|
if bif.Ver != 0x600 {
|
||||||
wb.Is5ver = true
|
wb.Is5ver = true
|
||||||
|
46
worksheet.go
46
worksheet.go
@ -26,12 +26,12 @@ type WorkSheet struct {
|
|||||||
|
|
||||||
func (w *WorkSheet) parse(buf io.ReadSeeker) {
|
func (w *WorkSheet) parse(buf io.ReadSeeker) {
|
||||||
w.Rows = make(map[uint16]*Row)
|
w.Rows = make(map[uint16]*Row)
|
||||||
bof := new(BOF)
|
b := new(bof)
|
||||||
var bof_pre *BOF
|
var bof_pre *bof
|
||||||
for {
|
for {
|
||||||
if err := binary.Read(buf, binary.LittleEndian, bof); err == nil {
|
if err := binary.Read(buf, binary.LittleEndian, b); err == nil {
|
||||||
bof_pre = w.parseBof(buf, bof, bof_pre)
|
bof_pre = w.parseBof(buf, b, bof_pre)
|
||||||
if bof.Id == 0xa {
|
if b.Id == 0xa {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -41,9 +41,9 @@ func (w *WorkSheet) parse(buf io.ReadSeeker) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WorkSheet) parseBof(buf io.ReadSeeker, bof *BOF, pre *BOF) *BOF {
|
func (w *WorkSheet) parseBof(buf io.ReadSeeker, b *bof, pre *bof) *bof {
|
||||||
var col interface{}
|
var col interface{}
|
||||||
switch bof.Id {
|
switch b.Id {
|
||||||
// case 0x0E5: //MERGEDCELLS
|
// case 0x0E5: //MERGEDCELLS
|
||||||
// ws.mergedCells(buf)
|
// ws.mergedCells(buf)
|
||||||
case 0x208: //ROW
|
case 0x208: //ROW
|
||||||
@ -52,7 +52,7 @@ func (w *WorkSheet) parseBof(buf io.ReadSeeker, bof *BOF, pre *BOF) *BOF {
|
|||||||
w.addRow(r)
|
w.addRow(r)
|
||||||
case 0x0BD: //MULRK
|
case 0x0BD: //MULRK
|
||||||
mc := new(MulrkCol)
|
mc := new(MulrkCol)
|
||||||
size := (bof.Size - 6) / 6
|
size := (b.Size - 6) / 6
|
||||||
binary.Read(buf, binary.LittleEndian, &mc.Col)
|
binary.Read(buf, binary.LittleEndian, &mc.Col)
|
||||||
mc.Xfrks = make([]XfRk, size)
|
mc.Xfrks = make([]XfRk, size)
|
||||||
for i := uint16(0); i < size; i++ {
|
for i := uint16(0); i < size; i++ {
|
||||||
@ -62,7 +62,7 @@ func (w *WorkSheet) parseBof(buf io.ReadSeeker, bof *BOF, pre *BOF) *BOF {
|
|||||||
col = mc
|
col = mc
|
||||||
case 0x0BE: //MULBLANK
|
case 0x0BE: //MULBLANK
|
||||||
mc := new(MulBlankCol)
|
mc := new(MulBlankCol)
|
||||||
size := (bof.Size - 6) / 2
|
size := (b.Size - 6) / 2
|
||||||
binary.Read(buf, binary.LittleEndian, &mc.Col)
|
binary.Read(buf, binary.LittleEndian, &mc.Col)
|
||||||
mc.Xfs = make([]uint16, size)
|
mc.Xfs = make([]uint16, size)
|
||||||
for i := uint16(0); i < size; i++ {
|
for i := uint16(0); i < size; i++ {
|
||||||
@ -76,7 +76,7 @@ func (w *WorkSheet) parseBof(buf io.ReadSeeker, bof *BOF, pre *BOF) *BOF {
|
|||||||
case 0x06: //FORMULA
|
case 0x06: //FORMULA
|
||||||
c := new(FormulaCol)
|
c := new(FormulaCol)
|
||||||
binary.Read(buf, binary.LittleEndian, &c.Header)
|
binary.Read(buf, binary.LittleEndian, &c.Header)
|
||||||
c.Bts = make([]byte, bof.Size-20)
|
c.Bts = make([]byte, b.Size-20)
|
||||||
binary.Read(buf, binary.LittleEndian, &c.Bts)
|
binary.Read(buf, binary.LittleEndian, &c.Bts)
|
||||||
col = c
|
col = c
|
||||||
case 0x27e: //RK
|
case 0x27e: //RK
|
||||||
@ -98,11 +98,11 @@ func (w *WorkSheet) parseBof(buf io.ReadSeeker, bof *BOF, pre *BOF) *BOF {
|
|||||||
|
|
||||||
if flag&0x14 != 0 {
|
if flag&0x14 != 0 {
|
||||||
binary.Read(buf, binary.LittleEndian, &count)
|
binary.Read(buf, binary.LittleEndian, &count)
|
||||||
hy.Description = bof.Utf16String(buf, count)
|
hy.Description = b.utf16String(buf, count)
|
||||||
}
|
}
|
||||||
if flag&0x80 != 0 {
|
if flag&0x80 != 0 {
|
||||||
binary.Read(buf, binary.LittleEndian, &count)
|
binary.Read(buf, binary.LittleEndian, &count)
|
||||||
hy.TargetFrame = bof.Utf16String(buf, count)
|
hy.TargetFrame = b.utf16String(buf, count)
|
||||||
}
|
}
|
||||||
if flag&0x1 != 0 {
|
if flag&0x1 != 0 {
|
||||||
var guid [2]uint64
|
var guid [2]uint64
|
||||||
@ -110,7 +110,7 @@ func (w *WorkSheet) parseBof(buf io.ReadSeeker, bof *BOF, pre *BOF) *BOF {
|
|||||||
if guid[0] == 0xE0C9EA79F9BACE11 && guid[1] == 0x8C8200AA004BA90B { //URL
|
if guid[0] == 0xE0C9EA79F9BACE11 && guid[1] == 0x8C8200AA004BA90B { //URL
|
||||||
hy.IsUrl = true
|
hy.IsUrl = true
|
||||||
binary.Read(buf, binary.LittleEndian, &count)
|
binary.Read(buf, binary.LittleEndian, &count)
|
||||||
hy.Url = bof.Utf16String(buf, count/2)
|
hy.Url = b.utf16String(buf, count/2)
|
||||||
} else if guid[0] == 0x303000000000000 && guid[1] == 0xC000000000000046 { //URL{
|
} else if guid[0] == 0x303000000000000 && guid[1] == 0xC000000000000046 { //URL{
|
||||||
var upCount uint16
|
var upCount uint16
|
||||||
binary.Read(buf, binary.LittleEndian, &upCount)
|
binary.Read(buf, binary.LittleEndian, &upCount)
|
||||||
@ -123,7 +123,7 @@ func (w *WorkSheet) parseBof(buf io.ReadSeeker, bof *BOF, pre *BOF) *BOF {
|
|||||||
if count > 0 {
|
if count > 0 {
|
||||||
binary.Read(buf, binary.LittleEndian, &count)
|
binary.Read(buf, binary.LittleEndian, &count)
|
||||||
buf.Seek(2, 1)
|
buf.Seek(2, 1)
|
||||||
hy.ExtendedFilePath = bof.Utf16String(buf, count/2+1)
|
hy.ExtendedFilePath = b.utf16String(buf, count/2+1)
|
||||||
}
|
}
|
||||||
log.Println(hy)
|
log.Println(hy)
|
||||||
}
|
}
|
||||||
@ -139,21 +139,21 @@ func (w *WorkSheet) parseBof(buf io.ReadSeeker, bof *BOF, pre *BOF) *BOF {
|
|||||||
w.addRange(&hy.CellRange, &hy)
|
w.addRange(&hy.CellRange, &hy)
|
||||||
case 0x809:
|
case 0x809:
|
||||||
log.Println("sheet start")
|
log.Println("sheet start")
|
||||||
buf.Seek(int64(bof.Size), 1)
|
buf.Seek(int64(b.Size), 1)
|
||||||
case 0xa:
|
case 0xa:
|
||||||
log.Println("sheet end")
|
log.Println("sheet end")
|
||||||
default:
|
default:
|
||||||
// log.Printf("Unknow %X,%d\n", bof.Id, bof.Size)
|
// log.Printf("Unknow %X,%d\n", b.Id, b.Size)
|
||||||
buf.Seek(int64(bof.Size), 1)
|
buf.Seek(int64(b.Size), 1)
|
||||||
}
|
}
|
||||||
if col != nil {
|
if col != nil {
|
||||||
w.add(col)
|
w.add(col)
|
||||||
}
|
}
|
||||||
return bof
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WorkSheet) add(content interface{}) {
|
func (w *WorkSheet) add(content interface{}) {
|
||||||
if ch, ok := content.(ContentHandler); ok {
|
if ch, ok := content.(contentHandler); ok {
|
||||||
if col, ok := content.(Coler); ok {
|
if col, ok := content.(Coler); ok {
|
||||||
w.addCell(col, ch)
|
w.addCell(col, ch)
|
||||||
}
|
}
|
||||||
@ -161,18 +161,18 @@ func (w *WorkSheet) add(content interface{}) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WorkSheet) addCell(col Coler, ch ContentHandler) {
|
func (w *WorkSheet) addCell(col Coler, ch contentHandler) {
|
||||||
w.addContent(col.Row(), ch)
|
w.addContent(col.Row(), ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WorkSheet) addRange(rang Ranger, ch ContentHandler) {
|
func (w *WorkSheet) addRange(rang Ranger, ch contentHandler) {
|
||||||
|
|
||||||
for i := rang.FirstRow(); i <= rang.LastRow(); i++ {
|
for i := rang.FirstRow(); i <= rang.LastRow(); i++ {
|
||||||
w.addContent(i, ch)
|
w.addContent(i, ch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WorkSheet) addContent(row_num uint16, ch ContentHandler) {
|
func (w *WorkSheet) addContent(row_num uint16, ch contentHandler) {
|
||||||
var row *Row
|
var row *Row
|
||||||
var ok bool
|
var ok bool
|
||||||
if row, ok = w.Rows[row_num]; !ok {
|
if row, ok = w.Rows[row_num]; !ok {
|
||||||
@ -191,7 +191,7 @@ func (w *WorkSheet) addRow(info *RowInfo) (row *Row) {
|
|||||||
if row, ok = w.Rows[info.Index]; ok {
|
if row, ok = w.Rows[info.Index]; ok {
|
||||||
row.info = info
|
row.info = info
|
||||||
} else {
|
} else {
|
||||||
row = &Row{info: info, Cols: make(map[uint16]ContentHandler)}
|
row = &Row{info: info, Cols: make(map[uint16]contentHandler)}
|
||||||
w.Rows[info.Index] = row
|
w.Rows[info.Index] = row
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
50
xls.go
50
xls.go
@ -6,8 +6,8 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//Open one xls file
|
||||||
func Open(file string, charset string) (*WorkBook, error) {
|
func Open(file string, charset string) (*WorkBook, error) {
|
||||||
|
|
||||||
if bts, err := ioutil.ReadFile(file); err == nil {
|
if bts, err := ioutil.ReadFile(file); err == nil {
|
||||||
return parse(bts, charset)
|
return parse(bts, charset)
|
||||||
} else {
|
} else {
|
||||||
@ -16,30 +16,38 @@ func Open(file string, charset string) (*WorkBook, error) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Open xls file from reader
|
||||||
func OpenReader(reader io.ReadCloser, charset string) (*WorkBook, error) {
|
func OpenReader(reader io.ReadCloser, charset string) (*WorkBook, error) {
|
||||||
bts, _ := ioutil.ReadAll(reader)
|
if bts, err := ioutil.ReadAll(reader); err == nil {
|
||||||
return parse(bts, charset)
|
return parse(bts, charset)
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parse(bts []byte, charset string) (*WorkBook, error) {
|
func parse(bts []byte, charset string) (wb *WorkBook, err error) {
|
||||||
ole, _ := ole2.Open(bts, charset)
|
var ole *ole2.Ole
|
||||||
dir, err := ole.ListDir()
|
if ole, err = ole2.Open(bts, charset); err == nil {
|
||||||
var book *ole2.File
|
var dir []*ole2.File
|
||||||
for _, file := range dir {
|
if dir, err = ole.ListDir(); err == nil {
|
||||||
name := file.Name()
|
var book *ole2.File
|
||||||
if name == "Workbook" {
|
for _, file := range dir {
|
||||||
book = file
|
name := file.Name()
|
||||||
// break
|
if name == "Workbook" {
|
||||||
}
|
book = file
|
||||||
if name == "Book" {
|
// break
|
||||||
book = file
|
}
|
||||||
// break
|
if name == "Book" {
|
||||||
|
book = file
|
||||||
|
// break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if book != nil {
|
||||||
|
wb = newWorkBookFromOle2(ole.OpenFile(book))
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if book != nil {
|
return
|
||||||
wb := newWookBookFromOle2(ole.OpenFile(book))
|
|
||||||
return wb, nil
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user