mirror of
https://github.com/pbnjay/grate.git
synced 2025-03-05 00:20:43 +02:00
unsigned int overflow is no fun
This commit is contained in:
parent
4848de04e3
commit
b239d8f2cb
169
xls/sheets.go
169
xls/sheets.go
@ -41,10 +41,10 @@ type WorkSheet struct {
|
|||||||
ss int
|
ss int
|
||||||
err error
|
err error
|
||||||
|
|
||||||
minRow uint32
|
minRow int
|
||||||
maxRow uint32
|
maxRow int // maximum valid row index (0xFFFF)
|
||||||
minCol uint16
|
minCol int
|
||||||
maxCol uint16
|
maxCol int // maximum valid column index (0xFF)
|
||||||
rows []*row
|
rows []*row
|
||||||
empty bool
|
empty bool
|
||||||
|
|
||||||
@ -81,15 +81,15 @@ type row struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *WorkSheet) placeValue(rowIndex, colIndex int, val interface{}) {
|
func (s *WorkSheet) placeValue(rowIndex, colIndex int, val interface{}) {
|
||||||
if colIndex > int(s.maxCol) || rowIndex > int(s.maxRow) {
|
if colIndex > s.maxCol || rowIndex > s.maxRow {
|
||||||
// invalid
|
// invalid
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure we always have a complete matrix
|
// ensure we always have a complete matrix
|
||||||
for len(s.rows) <= rowIndex {
|
for len(s.rows) <= rowIndex {
|
||||||
emptyRow := make([]interface{}, s.maxCol)
|
emptyRow := make([]interface{}, s.maxCol+1)
|
||||||
for i := 0; i < int(s.maxCol); i++ {
|
for i := 0; i <= s.maxCol; i++ {
|
||||||
emptyRow[i] = staticBlank
|
emptyRow[i] = staticBlank
|
||||||
}
|
}
|
||||||
s.rows = append(s.rows, &row{emptyRow})
|
s.rows = append(s.rows, &row{emptyRow})
|
||||||
@ -103,17 +103,78 @@ func (s *WorkSheet) IsEmpty() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *WorkSheet) parse() error {
|
func (s *WorkSheet) parse() error {
|
||||||
for _, r := range s.b.substreams[s.ss] {
|
inSubstream := 0
|
||||||
if r.RecType == RecTypeWsBool {
|
for idx, r := range s.b.substreams[s.ss] {
|
||||||
|
if inSubstream > 0 {
|
||||||
|
if r.RecType == RecTypeEOF {
|
||||||
|
inSubstream--
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch r.RecType {
|
||||||
|
case RecTypeBOF:
|
||||||
|
if idx > 0 {
|
||||||
|
inSubstream++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
case RecTypeWsBool:
|
||||||
if (r.Data[1] & 0x10) != 0 {
|
if (r.Data[1] & 0x10) != 0 {
|
||||||
// it's a dialog
|
// it's a dialog
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case RecTypeDimensions:
|
||||||
|
bb := bytes.NewReader(r.Data)
|
||||||
|
var minRow, maxRow uint32
|
||||||
|
var minCol, maxCol uint16
|
||||||
|
|
||||||
|
// max = 0-based index of the row AFTER the last valid index
|
||||||
|
binary.Read(bb, binary.LittleEndian, &minRow)
|
||||||
|
binary.Read(bb, binary.LittleEndian, &maxRow) // max = 0x010000
|
||||||
|
binary.Read(bb, binary.LittleEndian, &minCol)
|
||||||
|
binary.Read(bb, binary.LittleEndian, &maxCol) // max = 0x000100
|
||||||
|
//log.Printf("dimensions: %d,%d + %dx%d", minRow&0x0000FFFF, minCol,
|
||||||
|
// (maxRow&0x0000FFFF)-(minRow&0x0000FFFF), maxCol-minCol)
|
||||||
|
if minRow > 0x0000FFFF || maxRow > 0x00010000 {
|
||||||
|
log.Println("invalid dimensions")
|
||||||
|
}
|
||||||
|
if minCol > 0x00FF || maxCol > 0x0100 {
|
||||||
|
log.Println("invalid dimensions")
|
||||||
|
}
|
||||||
|
s.minRow = int(uint64(minRow) & 0x0FFFF)
|
||||||
|
s.maxRow = int(uint64(maxRow)&0x1FFFF) - 1 // translate to last valid index
|
||||||
|
s.minCol = int(uint64(minCol) & 0x000FF)
|
||||||
|
s.maxCol = int(uint64(maxCol)&0x001FF) - 1 // translate to last valid index
|
||||||
|
//log.Println(s.minCol, s.maxCol)
|
||||||
|
if (maxRow-minRow) == 0 || (maxCol-minCol) == 0 {
|
||||||
|
s.empty = true
|
||||||
|
} else {
|
||||||
|
// pre-allocate cells
|
||||||
|
s.placeValue(s.maxRow, s.maxCol, staticBlank)
|
||||||
|
}
|
||||||
|
|
||||||
|
case RecTypeRow:
|
||||||
|
bb := bytes.NewReader(r.Data)
|
||||||
|
row := &shRow{}
|
||||||
|
binary.Read(bb, binary.LittleEndian, row)
|
||||||
|
if (row.Reserved & 0xFFFF) != 0 {
|
||||||
|
log.Println("invalid Row spec")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
//log.Printf("row spec: %+v", *row)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
inSubstream = 0
|
||||||
|
|
||||||
var formulaRow, formulaCol uint16
|
var formulaRow, formulaCol uint16
|
||||||
for ridx, r := range s.b.substreams[s.ss] {
|
for ridx, r := range s.b.substreams[s.ss] {
|
||||||
|
if inSubstream > 0 {
|
||||||
|
if r.RecType == RecTypeEOF {
|
||||||
|
inSubstream--
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
bb := bytes.NewReader(r.Data)
|
bb := bytes.NewReader(r.Data)
|
||||||
//log.Println(ridx, r.RecType)
|
//log.Println(ridx, r.RecType)
|
||||||
|
|
||||||
@ -129,37 +190,11 @@ func (s *WorkSheet) parse() error {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
switch r.RecType {
|
switch r.RecType {
|
||||||
case RecTypeDimensions:
|
case RecTypeBOF:
|
||||||
binary.Read(bb, binary.LittleEndian, &s.minRow)
|
if ridx > 0 {
|
||||||
binary.Read(bb, binary.LittleEndian, &s.maxRow)
|
inSubstream++
|
||||||
binary.Read(bb, binary.LittleEndian, &s.minCol)
|
|
||||||
binary.Read(bb, binary.LittleEndian, &s.maxCol)
|
|
||||||
//log.Printf("dimensions: %d,%d + %dx%d", s.minRow&0x0000FFFF, s.minCol,
|
|
||||||
// (s.maxRow&0x0000FFFF)-(s.minRow&0x0000FFFF), s.maxCol-s.minCol)
|
|
||||||
if s.minRow > 0x0000FFFF || s.maxRow > 0x00010000 {
|
|
||||||
log.Println("invalid dimensions")
|
|
||||||
}
|
|
||||||
if s.minCol > 0x00FF || s.maxCol > 0x0100 {
|
|
||||||
log.Println("invalid dimensions")
|
|
||||||
}
|
|
||||||
s.minRow &= 0xFFFF
|
|
||||||
s.maxRow &= 0xFFFF
|
|
||||||
s.minCol &= 0x00FF
|
|
||||||
s.maxCol &= 0x00FF
|
|
||||||
|
|
||||||
if (s.maxRow-s.minRow) == 0 && (s.maxCol-s.minCol) == 0 {
|
|
||||||
s.empty = true
|
|
||||||
}
|
|
||||||
|
|
||||||
case RecTypeRow:
|
|
||||||
row := &shRow{}
|
|
||||||
binary.Read(bb, binary.LittleEndian, row)
|
|
||||||
if (row.Reserved & 0xFFFF) != 0 {
|
|
||||||
log.Println("invalid Row spec")
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
//log.Printf("row spec: %+v", *row)
|
|
||||||
|
|
||||||
case RecTypeBlank:
|
case RecTypeBlank:
|
||||||
var rowIndex, colIndex uint16
|
var rowIndex, colIndex uint16
|
||||||
binary.Read(bb, binary.LittleEndian, &rowIndex)
|
binary.Read(bb, binary.LittleEndian, &rowIndex)
|
||||||
@ -332,11 +367,11 @@ func (s *WorkSheet) parse() error {
|
|||||||
case RecTypeHLink:
|
case RecTypeHLink:
|
||||||
loc := &shRef8{}
|
loc := &shRef8{}
|
||||||
binary.Read(bb, binary.LittleEndian, loc)
|
binary.Read(bb, binary.LittleEndian, loc)
|
||||||
if loc.FirstCol > s.maxCol {
|
if int(loc.FirstCol) > s.maxCol {
|
||||||
//log.Println("invalid hyperlink column")
|
//log.Println("invalid hyperlink column")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if uint32(loc.FirstRow) > s.maxRow {
|
if int(loc.FirstRow) > s.maxRow {
|
||||||
//log.Println("invalid hyperlink row")
|
//log.Println("invalid hyperlink row")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -344,7 +379,7 @@ func (s *WorkSheet) parse() error {
|
|||||||
loc.LastRow = uint16(s.maxRow)
|
loc.LastRow = uint16(s.maxRow)
|
||||||
}
|
}
|
||||||
if loc.LastCol == 0xFF {
|
if loc.LastCol == 0xFF {
|
||||||
loc.LastCol = s.maxCol
|
loc.LastCol = uint16(s.maxCol)
|
||||||
}
|
}
|
||||||
|
|
||||||
displayText, linkText, err := decodeHyperlinks(bb)
|
displayText, linkText, err := decodeHyperlinks(bb)
|
||||||
@ -354,28 +389,24 @@ func (s *WorkSheet) parse() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// apply merge cell rules
|
// apply merge cell rules
|
||||||
for rn := loc.FirstRow; rn <= loc.LastRow; rn++ {
|
for rn := int(loc.FirstRow); rn <= int(loc.LastRow); rn++ {
|
||||||
for cn := loc.FirstCol; cn <= loc.LastCol; cn++ {
|
for cn := int(loc.FirstCol); cn <= int(loc.LastCol); cn++ {
|
||||||
if rn == loc.FirstRow && cn == loc.FirstCol {
|
if rn == int(loc.FirstRow) && cn == int(loc.FirstCol) {
|
||||||
s.placeValue(int(rn), int(cn), displayText+" <"+linkText+">")
|
s.placeValue(rn, cn, displayText+" <"+linkText+">")
|
||||||
} else if cn == loc.FirstCol {
|
} else if cn == int(loc.FirstCol) {
|
||||||
// first and last column MAY be the same
|
// first and last column MAY be the same
|
||||||
if rn == loc.LastRow {
|
if rn == int(loc.LastRow) {
|
||||||
s.placeValue(int(rn), int(cn), endRowMerged)
|
s.placeValue(rn, cn, endRowMerged)
|
||||||
} else {
|
} else {
|
||||||
s.placeValue(int(rn), int(cn), continueRowMerged)
|
s.placeValue(rn, cn, continueRowMerged)
|
||||||
}
|
}
|
||||||
} else if cn == loc.LastCol {
|
} else if cn == int(loc.LastCol) {
|
||||||
// first and last column are NOT the same
|
// first and last column are NOT the same
|
||||||
s.placeValue(int(rn), int(cn), endColumnMerged)
|
s.placeValue(rn, cn, endColumnMerged)
|
||||||
} else {
|
} else {
|
||||||
s.placeValue(int(rn), int(cn), continueColumnMerged)
|
s.placeValue(rn, cn, continueColumnMerged)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if rn == 0xFFFF {
|
|
||||||
// uint32s are fun
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case RecTypeMergeCells:
|
case RecTypeMergeCells:
|
||||||
@ -388,30 +419,26 @@ func (s *WorkSheet) parse() error {
|
|||||||
loc.LastRow = uint16(s.maxRow)
|
loc.LastRow = uint16(s.maxRow)
|
||||||
}
|
}
|
||||||
if loc.LastCol == 0xFF {
|
if loc.LastCol == 0xFF {
|
||||||
loc.LastCol = s.maxCol
|
loc.LastCol = uint16(s.maxCol)
|
||||||
}
|
}
|
||||||
for rn := loc.FirstRow; rn <= loc.LastRow; rn++ {
|
for rn := int(loc.FirstRow); rn <= int(loc.LastRow); rn++ {
|
||||||
for cn := loc.FirstCol; cn <= loc.LastCol; cn++ {
|
for cn := int(loc.FirstCol); cn <= int(loc.LastCol); cn++ {
|
||||||
if rn == loc.FirstRow && cn == loc.FirstCol {
|
if rn == int(loc.FirstRow) && cn == int(loc.FirstCol) {
|
||||||
// should be a value there already!
|
// should be a value there already!
|
||||||
} else if cn == loc.FirstCol {
|
} else if cn == int(loc.FirstCol) {
|
||||||
// first and last column MAY be the same
|
// first and last column MAY be the same
|
||||||
if rn == loc.LastRow {
|
if rn == int(loc.LastRow) {
|
||||||
s.placeValue(int(rn), int(cn), endRowMerged)
|
s.placeValue(rn, cn, endRowMerged)
|
||||||
} else {
|
} else {
|
||||||
s.placeValue(int(rn), int(cn), continueRowMerged)
|
s.placeValue(rn, cn, continueRowMerged)
|
||||||
}
|
}
|
||||||
} else if cn == loc.LastCol {
|
} else if cn == int(loc.LastCol) {
|
||||||
// first and last column are NOT the same
|
// first and last column are NOT the same
|
||||||
s.placeValue(int(rn), int(cn), endColumnMerged)
|
s.placeValue(rn, cn, endColumnMerged)
|
||||||
} else {
|
} else {
|
||||||
s.placeValue(int(rn), int(cn), continueColumnMerged)
|
s.placeValue(rn, cn, continueColumnMerged)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if rn == 0xFFFF {
|
|
||||||
// uint32s are fun
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user