mirror of
https://github.com/pbnjay/grate.git
synced 2024-12-13 13:58:27 +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
|
||||
err error
|
||||
|
||||
minRow uint32
|
||||
maxRow uint32
|
||||
minCol uint16
|
||||
maxCol uint16
|
||||
minRow int
|
||||
maxRow int // maximum valid row index (0xFFFF)
|
||||
minCol int
|
||||
maxCol int // maximum valid column index (0xFF)
|
||||
rows []*row
|
||||
empty bool
|
||||
|
||||
@ -81,15 +81,15 @@ type row struct {
|
||||
}
|
||||
|
||||
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
|
||||
return
|
||||
}
|
||||
|
||||
// ensure we always have a complete matrix
|
||||
for len(s.rows) <= rowIndex {
|
||||
emptyRow := make([]interface{}, s.maxCol)
|
||||
for i := 0; i < int(s.maxCol); i++ {
|
||||
emptyRow := make([]interface{}, s.maxCol+1)
|
||||
for i := 0; i <= s.maxCol; i++ {
|
||||
emptyRow[i] = staticBlank
|
||||
}
|
||||
s.rows = append(s.rows, &row{emptyRow})
|
||||
@ -103,17 +103,78 @@ func (s *WorkSheet) IsEmpty() bool {
|
||||
}
|
||||
|
||||
func (s *WorkSheet) parse() error {
|
||||
for _, r := range s.b.substreams[s.ss] {
|
||||
if r.RecType == RecTypeWsBool {
|
||||
inSubstream := 0
|
||||
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 {
|
||||
// it's a dialog
|
||||
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
|
||||
for ridx, r := range s.b.substreams[s.ss] {
|
||||
if inSubstream > 0 {
|
||||
if r.RecType == RecTypeEOF {
|
||||
inSubstream--
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
bb := bytes.NewReader(r.Data)
|
||||
//log.Println(ridx, r.RecType)
|
||||
|
||||
@ -129,37 +190,11 @@ func (s *WorkSheet) parse() error {
|
||||
*/
|
||||
|
||||
switch r.RecType {
|
||||
case RecTypeDimensions:
|
||||
binary.Read(bb, binary.LittleEndian, &s.minRow)
|
||||
binary.Read(bb, binary.LittleEndian, &s.maxRow)
|
||||
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")
|
||||
case RecTypeBOF:
|
||||
if ridx > 0 {
|
||||
inSubstream++
|
||||
continue
|
||||
}
|
||||
//log.Printf("row spec: %+v", *row)
|
||||
|
||||
case RecTypeBlank:
|
||||
var rowIndex, colIndex uint16
|
||||
binary.Read(bb, binary.LittleEndian, &rowIndex)
|
||||
@ -332,11 +367,11 @@ func (s *WorkSheet) parse() error {
|
||||
case RecTypeHLink:
|
||||
loc := &shRef8{}
|
||||
binary.Read(bb, binary.LittleEndian, loc)
|
||||
if loc.FirstCol > s.maxCol {
|
||||
if int(loc.FirstCol) > s.maxCol {
|
||||
//log.Println("invalid hyperlink column")
|
||||
continue
|
||||
}
|
||||
if uint32(loc.FirstRow) > s.maxRow {
|
||||
if int(loc.FirstRow) > s.maxRow {
|
||||
//log.Println("invalid hyperlink row")
|
||||
continue
|
||||
}
|
||||
@ -344,7 +379,7 @@ func (s *WorkSheet) parse() error {
|
||||
loc.LastRow = uint16(s.maxRow)
|
||||
}
|
||||
if loc.LastCol == 0xFF {
|
||||
loc.LastCol = s.maxCol
|
||||
loc.LastCol = uint16(s.maxCol)
|
||||
}
|
||||
|
||||
displayText, linkText, err := decodeHyperlinks(bb)
|
||||
@ -354,28 +389,24 @@ func (s *WorkSheet) parse() error {
|
||||
}
|
||||
|
||||
// apply merge cell rules
|
||||
for rn := loc.FirstRow; rn <= loc.LastRow; rn++ {
|
||||
for cn := loc.FirstCol; cn <= loc.LastCol; cn++ {
|
||||
if rn == loc.FirstRow && cn == loc.FirstCol {
|
||||
s.placeValue(int(rn), int(cn), displayText+" <"+linkText+">")
|
||||
} else if cn == loc.FirstCol {
|
||||
for rn := int(loc.FirstRow); rn <= int(loc.LastRow); rn++ {
|
||||
for cn := int(loc.FirstCol); cn <= int(loc.LastCol); cn++ {
|
||||
if rn == int(loc.FirstRow) && cn == int(loc.FirstCol) {
|
||||
s.placeValue(rn, cn, displayText+" <"+linkText+">")
|
||||
} else if cn == int(loc.FirstCol) {
|
||||
// first and last column MAY be the same
|
||||
if rn == loc.LastRow {
|
||||
s.placeValue(int(rn), int(cn), endRowMerged)
|
||||
if rn == int(loc.LastRow) {
|
||||
s.placeValue(rn, cn, endRowMerged)
|
||||
} 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
|
||||
s.placeValue(int(rn), int(cn), endColumnMerged)
|
||||
s.placeValue(rn, cn, endColumnMerged)
|
||||
} else {
|
||||
s.placeValue(int(rn), int(cn), continueColumnMerged)
|
||||
s.placeValue(rn, cn, continueColumnMerged)
|
||||
}
|
||||
}
|
||||
if rn == 0xFFFF {
|
||||
// uint32s are fun
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
case RecTypeMergeCells:
|
||||
@ -388,30 +419,26 @@ func (s *WorkSheet) parse() error {
|
||||
loc.LastRow = uint16(s.maxRow)
|
||||
}
|
||||
if loc.LastCol == 0xFF {
|
||||
loc.LastCol = s.maxCol
|
||||
loc.LastCol = uint16(s.maxCol)
|
||||
}
|
||||
for rn := loc.FirstRow; rn <= loc.LastRow; rn++ {
|
||||
for cn := loc.FirstCol; cn <= loc.LastCol; cn++ {
|
||||
if rn == loc.FirstRow && cn == loc.FirstCol {
|
||||
for rn := int(loc.FirstRow); rn <= int(loc.LastRow); rn++ {
|
||||
for cn := int(loc.FirstCol); cn <= int(loc.LastCol); cn++ {
|
||||
if rn == int(loc.FirstRow) && cn == int(loc.FirstCol) {
|
||||
// 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
|
||||
if rn == loc.LastRow {
|
||||
s.placeValue(int(rn), int(cn), endRowMerged)
|
||||
if rn == int(loc.LastRow) {
|
||||
s.placeValue(rn, cn, endRowMerged)
|
||||
} 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
|
||||
s.placeValue(int(rn), int(cn), endColumnMerged)
|
||||
s.placeValue(rn, cn, endColumnMerged)
|
||||
} else {
|
||||
s.placeValue(int(rn), int(cn), continueColumnMerged)
|
||||
s.placeValue(rn, cn, continueColumnMerged)
|
||||
}
|
||||
}
|
||||
if rn == 0xFFFF {
|
||||
// uint32s are fun
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user