Skip to content

Commit fb6ce60

Browse files
committed
This closes qax-os#1523, preventing format text cell value as a numeric
- Simplify variable declaration and error return statements - Remove the internal `xlsxTabColor` data type - Using the `xlsxColor` data type instead of `xlsxTabColor` - Update unit test, improve code coverage
1 parent d0ad0f3 commit fb6ce60

14 files changed

+400
-354
lines changed

calc.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -791,11 +791,11 @@ func (f *File) CalcCellValue(sheet, cell string, opts ...Options) (result string
791791
result = token.Value()
792792
if isNum, precision, decimal := isNumeric(result); isNum {
793793
if precision > 15 {
794-
result, err = f.formattedValue(styleIdx, strings.ToUpper(strconv.FormatFloat(decimal, 'G', 15, 64)), rawCellValue)
794+
result, err = f.formattedValue(&xlsxC{S: styleIdx, V: strings.ToUpper(strconv.FormatFloat(decimal, 'G', 15, 64))}, rawCellValue, CellTypeNumber)
795795
return
796796
}
797797
if !strings.HasPrefix(result, "0") {
798-
result, err = f.formattedValue(styleIdx, strings.ToUpper(strconv.FormatFloat(decimal, 'f', -1, 64)), rawCellValue)
798+
result, err = f.formattedValue(&xlsxC{S: styleIdx, V: strings.ToUpper(strconv.FormatFloat(decimal, 'f', -1, 64))}, rawCellValue, CellTypeNumber)
799799
}
800800
}
801801
return

cell.go

+23-27
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ func (c *xlsxC) getCellBool(f *File, raw bool) (string, error) {
516516
return "FALSE", nil
517517
}
518518
}
519-
return f.formattedValue(c.S, c.V, raw)
519+
return f.formattedValue(c, raw, CellTypeBool)
520520
}
521521

522522
// setCellDefault prepares cell type and string type cell value by a given
@@ -551,7 +551,7 @@ func (c *xlsxC) getCellDate(f *File, raw bool) (string, error) {
551551
c.V = strconv.FormatFloat(excelTime, 'G', 15, 64)
552552
}
553553
}
554-
return f.formattedValue(c.S, c.V, raw)
554+
return f.formattedValue(c, raw, CellTypeBool)
555555
}
556556

557557
// getValueFrom return a value from a column/row cell, this function is
@@ -567,21 +567,20 @@ func (c *xlsxC) getValueFrom(f *File, d *xlsxSST, raw bool) (string, error) {
567567
return c.getCellDate(f, raw)
568568
case "s":
569569
if c.V != "" {
570-
xlsxSI := 0
571-
xlsxSI, _ = strconv.Atoi(strings.TrimSpace(c.V))
570+
xlsxSI, _ := strconv.Atoi(strings.TrimSpace(c.V))
572571
if _, ok := f.tempFiles.Load(defaultXMLPathSharedStrings); ok {
573-
return f.formattedValue(c.S, f.getFromStringItem(xlsxSI), raw)
572+
return f.formattedValue(&xlsxC{S: c.S, V: f.getFromStringItem(xlsxSI)}, raw, CellTypeSharedString)
574573
}
575574
if len(d.SI) > xlsxSI {
576-
return f.formattedValue(c.S, d.SI[xlsxSI].String(), raw)
575+
return f.formattedValue(&xlsxC{S: c.S, V: d.SI[xlsxSI].String()}, raw, CellTypeSharedString)
577576
}
578577
}
579-
return f.formattedValue(c.S, c.V, raw)
578+
return f.formattedValue(c, raw, CellTypeSharedString)
580579
case "inlineStr":
581580
if c.IS != nil {
582-
return f.formattedValue(c.S, c.IS.String(), raw)
581+
return f.formattedValue(&xlsxC{S: c.S, V: c.IS.String()}, raw, CellTypeInlineString)
583582
}
584-
return f.formattedValue(c.S, c.V, raw)
583+
return f.formattedValue(c, raw, CellTypeInlineString)
585584
default:
586585
if isNum, precision, decimal := isNumeric(c.V); isNum && !raw {
587586
if precision > 15 {
@@ -590,7 +589,7 @@ func (c *xlsxC) getValueFrom(f *File, d *xlsxSST, raw bool) (string, error) {
590589
c.V = strconv.FormatFloat(decimal, 'f', -1, 64)
591590
}
592591
}
593-
return f.formattedValue(c.S, c.V, raw)
592+
return f.formattedValue(c, raw, CellTypeNumber)
594593
}
595594
}
596595

@@ -1325,47 +1324,44 @@ func (f *File) getCellStringFunc(sheet, cell string, fn func(x *xlsxWorksheet, c
13251324
// formattedValue provides a function to returns a value after formatted. If
13261325
// it is possible to apply a format to the cell value, it will do so, if not
13271326
// then an error will be returned, along with the raw value of the cell.
1328-
func (f *File) formattedValue(s int, v string, raw bool) (string, error) {
1329-
if raw {
1330-
return v, nil
1331-
}
1332-
if s == 0 {
1333-
return v, nil
1327+
func (f *File) formattedValue(c *xlsxC, raw bool, cellType CellType) (string, error) {
1328+
if raw || c.S == 0 {
1329+
return c.V, nil
13341330
}
13351331
styleSheet, err := f.stylesReader()
13361332
if err != nil {
1337-
return v, err
1333+
return c.V, err
13381334
}
13391335
if styleSheet.CellXfs == nil {
1340-
return v, err
1336+
return c.V, err
13411337
}
1342-
if s >= len(styleSheet.CellXfs.Xf) || s < 0 {
1343-
return v, err
1338+
if c.S >= len(styleSheet.CellXfs.Xf) || c.S < 0 {
1339+
return c.V, err
13441340
}
13451341
var numFmtID int
1346-
if styleSheet.CellXfs.Xf[s].NumFmtID != nil {
1347-
numFmtID = *styleSheet.CellXfs.Xf[s].NumFmtID
1342+
if styleSheet.CellXfs.Xf[c.S].NumFmtID != nil {
1343+
numFmtID = *styleSheet.CellXfs.Xf[c.S].NumFmtID
13481344
}
13491345
date1904 := false
13501346
wb, err := f.workbookReader()
13511347
if err != nil {
1352-
return v, err
1348+
return c.V, err
13531349
}
13541350
if wb != nil && wb.WorkbookPr != nil {
13551351
date1904 = wb.WorkbookPr.Date1904
13561352
}
13571353
if ok := builtInNumFmtFunc[numFmtID]; ok != nil {
1358-
return ok(v, builtInNumFmt[numFmtID], date1904), err
1354+
return ok(c.V, builtInNumFmt[numFmtID], date1904, cellType), err
13591355
}
13601356
if styleSheet.NumFmts == nil {
1361-
return v, err
1357+
return c.V, err
13621358
}
13631359
for _, xlsxFmt := range styleSheet.NumFmts.NumFmt {
13641360
if xlsxFmt.NumFmtID == numFmtID {
1365-
return format(v, xlsxFmt.FormatCode, date1904), err
1361+
return format(c.V, xlsxFmt.FormatCode, date1904, cellType), err
13661362
}
13671363
}
1368-
return v, err
1364+
return c.V, err
13691365
}
13701366

13711367
// prepareCellStyle provides a function to prepare style index of cell in

cell_test.go

+29-16
Original file line numberDiff line numberDiff line change
@@ -803,29 +803,29 @@ func TestSetCellRichText(t *testing.T) {
803803

804804
func TestFormattedValue(t *testing.T) {
805805
f := NewFile()
806-
result, err := f.formattedValue(0, "43528", false)
806+
result, err := f.formattedValue(&xlsxC{S: 0, V: "43528"}, false, CellTypeNumber)
807807
assert.NoError(t, err)
808808
assert.Equal(t, "43528", result)
809809

810810
// S is too large
811-
result, err = f.formattedValue(15, "43528", false)
811+
result, err = f.formattedValue(&xlsxC{S: 15, V: "43528"}, false, CellTypeNumber)
812812
assert.NoError(t, err)
813813
assert.Equal(t, "43528", result)
814814

815815
// S is too small
816-
result, err = f.formattedValue(-15, "43528", false)
816+
result, err = f.formattedValue(&xlsxC{S: -15, V: "43528"}, false, CellTypeNumber)
817817
assert.NoError(t, err)
818818
assert.Equal(t, "43528", result)
819819

820-
result, err = f.formattedValue(1, "43528", false)
820+
result, err = f.formattedValue(&xlsxC{S: 1, V: "43528"}, false, CellTypeNumber)
821821
assert.NoError(t, err)
822822
assert.Equal(t, "43528", result)
823823
customNumFmt := "[$-409]MM/DD/YYYY"
824824
_, err = f.NewStyle(&Style{
825825
CustomNumFmt: &customNumFmt,
826826
})
827827
assert.NoError(t, err)
828-
result, err = f.formattedValue(1, "43528", false)
828+
result, err = f.formattedValue(&xlsxC{S: 1, V: "43528"}, false, CellTypeNumber)
829829
assert.NoError(t, err)
830830
assert.Equal(t, "03/04/2019", result)
831831

@@ -834,15 +834,15 @@ func TestFormattedValue(t *testing.T) {
834834
f.Styles.CellXfs.Xf = append(f.Styles.CellXfs.Xf, xlsxXf{
835835
NumFmtID: &numFmtID,
836836
})
837-
result, err = f.formattedValue(2, "43528", false)
837+
result, err = f.formattedValue(&xlsxC{S: 2, V: "43528"}, false, CellTypeNumber)
838838
assert.NoError(t, err)
839839
assert.Equal(t, "43528", result)
840840

841841
// Test format value with invalid number format ID
842842
f.Styles.CellXfs.Xf = append(f.Styles.CellXfs.Xf, xlsxXf{
843843
NumFmtID: nil,
844844
})
845-
result, err = f.formattedValue(3, "43528", false)
845+
result, err = f.formattedValue(&xlsxC{S: 3, V: "43528"}, false, CellTypeNumber)
846846
assert.NoError(t, err)
847847
assert.Equal(t, "43528", result)
848848

@@ -851,7 +851,16 @@ func TestFormattedValue(t *testing.T) {
851851
f.Styles.CellXfs.Xf = append(f.Styles.CellXfs.Xf, xlsxXf{
852852
NumFmtID: &numFmtID,
853853
})
854-
result, err = f.formattedValue(1, "43528", false)
854+
result, err = f.formattedValue(&xlsxC{S: 1, V: "43528"}, false, CellTypeNumber)
855+
assert.NoError(t, err)
856+
assert.Equal(t, "43528", result)
857+
858+
// Test format numeric value with shared string data type
859+
f.Styles.NumFmts, numFmtID = nil, 11
860+
f.Styles.CellXfs.Xf = append(f.Styles.CellXfs.Xf, xlsxXf{
861+
NumFmtID: &numFmtID,
862+
})
863+
result, err = f.formattedValue(&xlsxC{S: 5, V: "43528"}, false, CellTypeSharedString)
855864
assert.NoError(t, err)
856865
assert.Equal(t, "43528", result)
857866

@@ -860,32 +869,36 @@ func TestFormattedValue(t *testing.T) {
860869
NumFmt: 1,
861870
})
862871
assert.NoError(t, err)
863-
result, err = f.formattedValue(styleID, "310.56", false)
872+
result, err = f.formattedValue(&xlsxC{S: styleID, V: "310.56"}, false, CellTypeNumber)
864873
assert.NoError(t, err)
865874
assert.Equal(t, "311", result)
866875

867876
for _, fn := range builtInNumFmtFunc {
868-
assert.Equal(t, "0_0", fn("0_0", "", false))
877+
assert.Equal(t, "0_0", fn("0_0", "", false, CellTypeNumber))
869878
}
870879

871880
// Test format value with unsupported charset workbook
872881
f.WorkBook = nil
873882
f.Pkg.Store(defaultXMLPathWorkbook, MacintoshCyrillicCharset)
874-
_, err = f.formattedValue(1, "43528", false)
883+
_, err = f.formattedValue(&xlsxC{S: 1, V: "43528"}, false, CellTypeNumber)
875884
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
876885

877886
// Test format value with unsupported charset style sheet
878887
f.Styles = nil
879888
f.Pkg.Store(defaultXMLPathStyles, MacintoshCyrillicCharset)
880-
_, err = f.formattedValue(1, "43528", false)
889+
_, err = f.formattedValue(&xlsxC{S: 1, V: "43528"}, false, CellTypeNumber)
881890
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
891+
892+
for _, fn := range builtInNumFmtFunc {
893+
assert.Equal(t, fn("text", "0", false, CellTypeNumber), "text")
894+
}
882895
}
883896

884897
func TestFormattedValueNilXfs(t *testing.T) {
885898
// Set the CellXfs to nil and verify that the formattedValue function does not crash
886899
f := NewFile()
887900
f.Styles.CellXfs = nil
888-
result, err := f.formattedValue(3, "43528", false)
901+
result, err := f.formattedValue(&xlsxC{S: 3, V: "43528"}, false, CellTypeNumber)
889902
assert.NoError(t, err)
890903
assert.Equal(t, "43528", result)
891904
}
@@ -894,7 +907,7 @@ func TestFormattedValueNilNumFmts(t *testing.T) {
894907
// Set the NumFmts value to nil and verify that the formattedValue function does not crash
895908
f := NewFile()
896909
f.Styles.NumFmts = nil
897-
result, err := f.formattedValue(3, "43528", false)
910+
result, err := f.formattedValue(&xlsxC{S: 3, V: "43528"}, false, CellTypeNumber)
898911
assert.NoError(t, err)
899912
assert.Equal(t, "43528", result)
900913
}
@@ -903,7 +916,7 @@ func TestFormattedValueNilWorkbook(t *testing.T) {
903916
// Set the Workbook value to nil and verify that the formattedValue function does not crash
904917
f := NewFile()
905918
f.WorkBook = nil
906-
result, err := f.formattedValue(3, "43528", false)
919+
result, err := f.formattedValue(&xlsxC{S: 3, V: "43528"}, false, CellTypeNumber)
907920
assert.NoError(t, err)
908921
assert.Equal(t, "43528", result)
909922
}
@@ -913,7 +926,7 @@ func TestFormattedValueNilWorkbookPr(t *testing.T) {
913926
// crash.
914927
f := NewFile()
915928
f.WorkBook.WorkbookPr = nil
916-
result, err := f.formattedValue(3, "43528", false)
929+
result, err := f.formattedValue(&xlsxC{S: 3, V: "43528"}, false, CellTypeNumber)
917930
assert.NoError(t, err)
918931
assert.Equal(t, "43528", result)
919932
}

chart_test.go

+6
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,12 @@ func TestDeleteDrawing(t *testing.T) {
121121
path := "xl/drawings/drawing1.xml"
122122
f.Pkg.Store(path, MacintoshCyrillicCharset)
123123
assert.EqualError(t, f.deleteDrawing(0, 0, path, "Chart"), "XML syntax error on line 1: invalid UTF-8")
124+
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
125+
assert.NoError(t, err)
126+
f.Drawings.Store(path, &xlsxWsDr{TwoCellAnchor: []*xdrCellAnchor{{
127+
GraphicFrame: string(MacintoshCyrillicCharset),
128+
}}})
129+
assert.EqualError(t, f.deleteDrawing(0, 0, path, "Chart"), "XML syntax error on line 1: invalid UTF-8")
124130
}
125131

126132
func TestAddChart(t *testing.T) {

crypt_test.go

+22
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,14 @@
1212
package excelize
1313

1414
import (
15+
"bytes"
16+
"encoding/binary"
1517
"os"
1618
"path/filepath"
1719
"strings"
1820
"testing"
1921

22+
"github.com/richardlehane/mscfb"
2023
"github.com/stretchr/testify/assert"
2124
)
2225

@@ -51,6 +54,25 @@ func TestEncrypt(t *testing.T) {
5154
// Test remove password by save workbook with options
5255
assert.NoError(t, f.Save(Options{Password: ""}))
5356
assert.NoError(t, f.Close())
57+
58+
doc, err := mscfb.New(bytes.NewReader(raw))
59+
assert.NoError(t, err)
60+
encryptionInfoBuf, encryptedPackageBuf := extractPart(doc)
61+
binary.LittleEndian.PutUint64(encryptionInfoBuf[20:32], uint64(0))
62+
_, err = standardDecrypt(encryptionInfoBuf, encryptedPackageBuf, &Options{Password: "password"})
63+
assert.NoError(t, err)
64+
_, err = decrypt(nil, nil, nil)
65+
assert.EqualError(t, err, "crypto/aes: invalid key size 0")
66+
_, err = agileDecrypt(encryptionInfoBuf, MacintoshCyrillicCharset, &Options{Password: "password"})
67+
assert.EqualError(t, err, "XML syntax error on line 1: invalid character entity &0 (no semicolon)")
68+
_, err = convertPasswdToKey("password", nil, Encryption{
69+
KeyEncryptors: KeyEncryptors{KeyEncryptor: []KeyEncryptor{
70+
{EncryptedKey: EncryptedKey{KeyData: KeyData{SaltValue: "=="}}},
71+
}},
72+
})
73+
assert.EqualError(t, err, "illegal base64 data at input byte 0")
74+
_, err = createIV([]byte{0}, Encryption{KeyData: KeyData{SaltValue: "=="}})
75+
assert.EqualError(t, err, "illegal base64 data at input byte 0")
5476
}
5577

5678
func TestEncryptionMechanism(t *testing.T) {

excelize.go

+3-4
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,10 @@ func OpenFile(filename string, opts ...Options) (*File, error) {
101101
}
102102
f, err := OpenReader(file, opts...)
103103
if err != nil {
104-
closeErr := file.Close()
105-
if closeErr == nil {
106-
return f, err
104+
if closeErr := file.Close(); closeErr != nil {
105+
return f, closeErr
107106
}
108-
return f, closeErr
107+
return f, err
109108
}
110109
f.Path = filename
111110
return f, file.Close()

numfmt.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ type languageInfo struct {
3131
// numberFormat directly maps the number format parser runtime required
3232
// fields.
3333
type numberFormat struct {
34+
cellType CellType
3435
section []nfp.Section
3536
t time.Time
3637
sectionIdx int
@@ -336,6 +337,9 @@ var (
336337
// prepareNumberic split the number into two before and after parts by a
337338
// decimal point.
338339
func (nf *numberFormat) prepareNumberic(value string) {
340+
if nf.cellType != CellTypeNumber && nf.cellType != CellTypeDate {
341+
return
342+
}
339343
if nf.isNumeric, _, _ = isNumeric(value); !nf.isNumeric {
340344
return
341345
}
@@ -344,9 +348,9 @@ func (nf *numberFormat) prepareNumberic(value string) {
344348
// format provides a function to return a string parse by number format
345349
// expression. If the given number format is not supported, this will return
346350
// the original cell value.
347-
func format(value, numFmt string, date1904 bool) string {
351+
func format(value, numFmt string, date1904 bool, cellType CellType) string {
348352
p := nfp.NumberFormatParser()
349-
nf := numberFormat{section: p.Parse(numFmt), value: value, date1904: date1904}
353+
nf := numberFormat{section: p.Parse(numFmt), value: value, date1904: date1904, cellType: cellType}
350354
nf.number, nf.valueSectionType = nf.getValueSectionType(value)
351355
nf.prepareNumberic(value)
352356
for i, section := range nf.section {
@@ -947,7 +951,7 @@ func (nf *numberFormat) textHandler() (result string) {
947951
if token.TType == nfp.TokenTypeLiteral {
948952
result += token.TValue
949953
}
950-
if token.TType == nfp.TokenTypeTextPlaceHolder {
954+
if token.TType == nfp.TokenTypeTextPlaceHolder || token.TType == nfp.TokenTypeZeroPlaceHolder {
951955
result += nf.value
952956
}
953957
}

numfmt_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1005,7 +1005,7 @@ func TestNumFmt(t *testing.T) {
10051005
{"-8.0450685976001E-21", "0_);[Red]\\(0\\)", "(0)"},
10061006
{"-8.04506", "0_);[Red]\\(0\\)", "(8)"},
10071007
} {
1008-
result := format(item[0], item[1], false)
1008+
result := format(item[0], item[1], false, CellTypeNumber)
10091009
assert.Equal(t, item[2], result, item)
10101010
}
10111011
}

0 commit comments

Comments
 (0)