This closes #1519, escape XML characters after checking cell value length

This commit is contained in:
xuri 2023-04-16 14:22:55 +08:00
parent 635ec33576
commit 17c029494a
No known key found for this signature in database
GPG Key ID: BA5E5BB1C948EDF7
2 changed files with 37 additions and 14 deletions

17
cell.go
View File

@ -451,17 +451,22 @@ func (f *File) setSharedString(val string) (int, error) {
sst.Count++ sst.Count++
sst.UniqueCount++ sst.UniqueCount++
t := xlsxT{Val: val} t := xlsxT{Val: val}
val, t.Space = trimCellValue(val) val, t.Space = trimCellValue(val, false)
sst.SI = append(sst.SI, xlsxSI{T: &t}) sst.SI = append(sst.SI, xlsxSI{T: &t})
f.sharedStringsMap[val] = sst.UniqueCount - 1 f.sharedStringsMap[val] = sst.UniqueCount - 1
return sst.UniqueCount - 1, nil return sst.UniqueCount - 1, nil
} }
// trimCellValue provides a function to set string type to cell. // trimCellValue provides a function to set string type to cell.
func trimCellValue(value string) (v string, ns xml.Attr) { func trimCellValue(value string, escape bool) (v string, ns xml.Attr) {
if utf8.RuneCountInString(value) > TotalCellChars { if utf8.RuneCountInString(value) > TotalCellChars {
value = string([]rune(value)[:TotalCellChars]) value = string([]rune(value)[:TotalCellChars])
} }
buf := &bytes.Buffer{}
if escape {
_ = xml.EscapeText(buf, []byte(value))
value = buf.String()
}
if len(value) > 0 { if len(value) > 0 {
prefix, suffix := value[0], value[len(value)-1] prefix, suffix := value[0], value[len(value)-1]
for _, ascii := range []byte{9, 10, 13, 32} { for _, ascii := range []byte{9, 10, 13, 32} {
@ -492,15 +497,13 @@ func (c *xlsxC) setCellValue(val string) {
// string. // string.
func (c *xlsxC) setInlineStr(val string) { func (c *xlsxC) setInlineStr(val string) {
c.T, c.V, c.IS = "inlineStr", "", &xlsxSI{T: &xlsxT{}} c.T, c.V, c.IS = "inlineStr", "", &xlsxSI{T: &xlsxT{}}
buf := &bytes.Buffer{} c.IS.T.Val, c.IS.T.Space = trimCellValue(val, true)
_ = xml.EscapeText(buf, []byte(val))
c.IS.T.Val, c.IS.T.Space = trimCellValue(buf.String())
} }
// setStr set cell data type and value which containing a formula string. // setStr set cell data type and value which containing a formula string.
func (c *xlsxC) setStr(val string) { func (c *xlsxC) setStr(val string) {
c.T, c.IS = "str", nil c.T, c.IS = "str", nil
c.V, c.XMLSpace = trimCellValue(val) c.V, c.XMLSpace = trimCellValue(val, false)
} }
// getCellDate parse cell value which containing a boolean. // getCellDate parse cell value which containing a boolean.
@ -1031,7 +1034,7 @@ func setRichText(runs []RichTextRun) ([]xlsxR, error) {
return textRuns, ErrCellCharsLength return textRuns, ErrCellCharsLength
} }
run := xlsxR{T: &xlsxT{}} run := xlsxR{T: &xlsxT{}}
run.T.Val, run.T.Space = trimCellValue(textRun.Text) run.T.Val, run.T.Space = trimCellValue(textRun.Text, false)
fnt := textRun.Font fnt := textRun.Font
if fnt != nil { if fnt != nil {
run.RPr = newRpr(fnt) run.RPr = newRpr(fnt)

View File

@ -177,16 +177,36 @@ func TestSetCellFloat(t *testing.T) {
} }
func TestSetCellValuesMultiByte(t *testing.T) { func TestSetCellValuesMultiByte(t *testing.T) {
value := strings.Repeat("\u042B", TotalCellChars+1)
f := NewFile() f := NewFile()
err := f.SetCellValue("Sheet1", "A1", value) row := []interface{}{
// Test set cell value with multi byte characters value
strings.Repeat("\u4E00", TotalCellChars+1),
// Test set cell value with XML escape characters
strings.Repeat("<>", TotalCellChars/2),
strings.Repeat(">", TotalCellChars-1),
strings.Repeat(">", TotalCellChars+1),
}
assert.NoError(t, f.SetSheetRow("Sheet1", "A1", &row))
// Test set cell value with XML escape characters in stream writer
_, err := f.NewSheet("Sheet2")
assert.NoError(t, err) assert.NoError(t, err)
streamWriter, err := f.NewStreamWriter("Sheet2")
v, err := f.GetCellValue("Sheet1", "A1")
assert.NoError(t, err) assert.NoError(t, err)
assert.NotEqual(t, value, v) assert.NoError(t, streamWriter.SetRow("A1", row))
assert.Equal(t, TotalCellChars, len([]rune(v))) assert.NoError(t, streamWriter.Flush())
for _, sheetName := range []string{"Sheet1", "Sheet2"} {
for cell, expected := range map[string]int{
"A1": TotalCellChars,
"B1": TotalCellChars - 1,
"C1": TotalCellChars - 1,
"D1": TotalCellChars,
} {
result, err := f.GetCellValue(sheetName, cell)
assert.NoError(t, err)
assert.Len(t, []rune(result), expected)
}
}
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetCellValuesMultiByte.xlsx")))
} }
func TestSetCellValue(t *testing.T) { func TestSetCellValue(t *testing.T) {