20
0
xls/worksheet.go

196 lines
4.7 KiB
Go
Raw Normal View History

2015-03-19 10:39:41 +01:00
package xls
import (
"encoding/binary"
"fmt"
"io"
2015-03-24 06:06:52 +01:00
"unicode/utf16"
2015-03-19 10:39:41 +01:00
)
type boundsheet struct {
2015-03-19 10:39:41 +01:00
Filepos uint32
Type byte
Visible byte
Name byte
}
2015-06-16 04:37:11 +02:00
//WorkSheet in one WorkBook
2015-03-19 10:39:41 +01:00
type WorkSheet struct {
2015-09-30 05:17:25 +02:00
bs *boundsheet
wb *WorkBook
Name string
Rows map[uint16]*Row
//NOTICE: this is the max row number of the sheet, so it should be count -1
2015-03-19 10:39:41 +01:00
MaxRow uint16
}
2015-06-16 04:37:11 +02:00
func (w *WorkSheet) parse(buf io.ReadSeeker) {
2015-03-19 10:39:41 +01:00
w.Rows = make(map[uint16]*Row)
2015-09-30 04:40:01 +02:00
b := new(bof)
var bof_pre *bof
2015-03-19 10:39:41 +01:00
for {
2015-09-30 04:40:01 +02:00
if err := binary.Read(buf, binary.LittleEndian, b); err == nil {
bof_pre = w.parseBof(buf, b, bof_pre)
if b.Id == 0xa {
break
}
2015-03-19 10:39:41 +01:00
} else {
fmt.Println(err)
break
}
}
}
2015-09-30 04:40:01 +02:00
func (w *WorkSheet) parseBof(buf io.ReadSeeker, b *bof, pre *bof) *bof {
2015-03-24 06:06:52 +01:00
var col interface{}
2015-09-30 04:40:01 +02:00
switch b.Id {
2015-03-24 06:06:52 +01:00
// case 0x0E5: //MERGEDCELLS
// ws.mergedCells(buf)
2015-03-19 10:39:41 +01:00
case 0x208: //ROW
r := new(RowInfo)
binary.Read(buf, binary.LittleEndian, r)
w.addRow(r)
case 0x0BD: //MULRK
mc := new(MulrkCol)
2015-09-30 04:40:01 +02:00
size := (b.Size - 6) / 6
2015-03-19 10:39:41 +01:00
binary.Read(buf, binary.LittleEndian, &mc.Col)
mc.Xfrks = make([]XfRk, size)
for i := uint16(0); i < size; i++ {
binary.Read(buf, binary.LittleEndian, &mc.Xfrks[i])
}
binary.Read(buf, binary.LittleEndian, &mc.LastColB)
col = mc
case 0x0BE: //MULBLANK
mc := new(MulBlankCol)
2015-09-30 04:40:01 +02:00
size := (b.Size - 6) / 2
2015-03-19 10:39:41 +01:00
binary.Read(buf, binary.LittleEndian, &mc.Col)
mc.Xfs = make([]uint16, size)
for i := uint16(0); i < size; i++ {
binary.Read(buf, binary.LittleEndian, &mc.Xfs[i])
}
binary.Read(buf, binary.LittleEndian, &mc.LastColB)
col = mc
case 0x203: //NUMBER
col = new(NumberCol)
binary.Read(buf, binary.LittleEndian, col)
case 0x06: //FORMULA
2015-03-24 06:06:52 +01:00
c := new(FormulaCol)
binary.Read(buf, binary.LittleEndian, &c.Header)
2015-09-30 04:40:01 +02:00
c.Bts = make([]byte, b.Size-20)
2015-03-24 06:06:52 +01:00
binary.Read(buf, binary.LittleEndian, &c.Bts)
col = c
2015-03-19 10:39:41 +01:00
case 0x27e: //RK
col = new(RkCol)
binary.Read(buf, binary.LittleEndian, col)
case 0xFD: //LABELSST
col = new(LabelsstCol)
binary.Read(buf, binary.LittleEndian, col)
case 0x201: //BLANK
col = new(BlankCol)
binary.Read(buf, binary.LittleEndian, col)
2015-03-24 06:06:52 +01:00
case 0x1b8: //HYPERLINK
var hy HyperLink
binary.Read(buf, binary.LittleEndian, &hy.CellRange)
buf.Seek(20, 1)
var flag uint32
binary.Read(buf, binary.LittleEndian, &flag)
var count uint32
if flag&0x14 != 0 {
binary.Read(buf, binary.LittleEndian, &count)
2015-09-30 04:40:01 +02:00
hy.Description = b.utf16String(buf, count)
2015-03-24 06:06:52 +01:00
}
if flag&0x80 != 0 {
binary.Read(buf, binary.LittleEndian, &count)
2015-09-30 04:40:01 +02:00
hy.TargetFrame = b.utf16String(buf, count)
2015-03-24 06:06:52 +01:00
}
if flag&0x1 != 0 {
var guid [2]uint64
binary.Read(buf, binary.BigEndian, &guid)
if guid[0] == 0xE0C9EA79F9BACE11 && guid[1] == 0x8C8200AA004BA90B { //URL
2015-03-25 04:03:05 +01:00
hy.IsUrl = true
2015-03-24 06:06:52 +01:00
binary.Read(buf, binary.LittleEndian, &count)
2015-09-30 04:40:01 +02:00
hy.Url = b.utf16String(buf, count/2)
2015-03-25 04:03:05 +01:00
} else if guid[0] == 0x303000000000000 && guid[1] == 0xC000000000000046 { //URL{
var upCount uint16
binary.Read(buf, binary.LittleEndian, &upCount)
binary.Read(buf, binary.LittleEndian, &count)
bts := make([]byte, count)
2015-03-24 06:06:52 +01:00
binary.Read(buf, binary.LittleEndian, &bts)
2015-03-25 04:03:05 +01:00
hy.ShortedFilePath = string(bts)
buf.Seek(24, 1)
binary.Read(buf, binary.LittleEndian, &count)
if count > 0 {
binary.Read(buf, binary.LittleEndian, &count)
buf.Seek(2, 1)
2015-09-30 04:40:01 +02:00
hy.ExtendedFilePath = b.utf16String(buf, count/2+1)
2015-03-25 04:03:05 +01:00
}
2015-03-24 06:06:52 +01:00
}
}
if flag&0x8 != 0 {
binary.Read(buf, binary.LittleEndian, &count)
var bts = make([]uint16, count)
binary.Read(buf, binary.LittleEndian, &bts)
runes := utf16.Decode(bts[:len(bts)-1])
hy.TextMark = string(runes)
}
w.addRange(&hy.CellRange, &hy)
case 0x809:
2015-09-30 04:40:01 +02:00
buf.Seek(int64(b.Size), 1)
case 0xa:
2015-03-19 10:39:41 +01:00
default:
2015-09-30 04:40:01 +02:00
// log.Printf("Unknow %X,%d\n", b.Id, b.Size)
buf.Seek(int64(b.Size), 1)
2015-03-19 10:39:41 +01:00
}
if col != nil {
2015-03-24 06:06:52 +01:00
w.add(col)
2015-03-19 10:39:41 +01:00
}
2015-09-30 04:40:01 +02:00
return b
2015-03-19 10:39:41 +01:00
}
2015-03-24 06:06:52 +01:00
func (w *WorkSheet) add(content interface{}) {
2015-09-30 04:40:01 +02:00
if ch, ok := content.(contentHandler); ok {
2015-03-24 06:06:52 +01:00
if col, ok := content.(Coler); ok {
w.addCell(col, ch)
}
}
}
2015-09-30 04:40:01 +02:00
func (w *WorkSheet) addCell(col Coler, ch contentHandler) {
w.addContent(col.Row(), ch)
2015-03-24 06:06:52 +01:00
}
2015-09-30 04:40:01 +02:00
func (w *WorkSheet) addRange(rang Ranger, ch contentHandler) {
for i := rang.FirstRow(); i <= rang.LastRow(); i++ {
w.addContent(i, ch)
}
}
2015-09-30 04:40:01 +02:00
func (w *WorkSheet) addContent(row_num uint16, ch contentHandler) {
2015-03-24 06:06:52 +01:00
var row *Row
var ok bool
if row, ok = w.Rows[row_num]; !ok {
info := new(RowInfo)
info.Index = row_num
row = w.addRow(info)
2015-03-24 06:06:52 +01:00
}
row.Cols[ch.FirstCol()] = ch
2015-03-19 10:39:41 +01:00
}
func (w *WorkSheet) addRow(info *RowInfo) (row *Row) {
if info.Index > w.MaxRow {
w.MaxRow = info.Index
}
var ok bool
if row, ok = w.Rows[info.Index]; ok {
row.info = info
} else {
2015-09-30 04:40:01 +02:00
row = &Row{info: info, Cols: make(map[uint16]contentHandler)}
2015-03-19 10:39:41 +01:00
w.Rows[info.Index] = row
}
return
}