Skip to content

Commit

Permalink
This closes #1519, escape XML characters after checking cell value le…
Browse files Browse the repository at this point in the history
…ngth
  • Loading branch information
xuri committed Apr 16, 2023
1 parent 635ec33 commit 17c0294
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 16 deletions.
17 changes: 10 additions & 7 deletions cell.go
Original file line number Diff line number Diff line change
Expand Up @@ -451,17 +451,22 @@ func (f *File) setSharedString(val string) (int, error) {
sst.Count++
sst.UniqueCount++
t := xlsxT{Val: val}
val, t.Space = trimCellValue(val)
val, t.Space = trimCellValue(val, false)
sst.SI = append(sst.SI, xlsxSI{T: &t})
f.sharedStringsMap[val] = sst.UniqueCount - 1
return sst.UniqueCount - 1, nil
}

// 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 {
value = string([]rune(value)[:TotalCellChars])
}
buf := &bytes.Buffer{}
if escape {
_ = xml.EscapeText(buf, []byte(value))
value = buf.String()
}
if len(value) > 0 {
prefix, suffix := value[0], value[len(value)-1]
for _, ascii := range []byte{9, 10, 13, 32} {
Expand Down Expand Up @@ -492,15 +497,13 @@ func (c *xlsxC) setCellValue(val string) {
// string.
func (c *xlsxC) setInlineStr(val string) {
c.T, c.V, c.IS = "inlineStr", "", &xlsxSI{T: &xlsxT{}}
buf := &bytes.Buffer{}
_ = xml.EscapeText(buf, []byte(val))
c.IS.T.Val, c.IS.T.Space = trimCellValue(buf.String())
c.IS.T.Val, c.IS.T.Space = trimCellValue(val, true)
}

// setStr set cell data type and value which containing a formula string.
func (c *xlsxC) setStr(val string) {
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.
Expand Down Expand Up @@ -1031,7 +1034,7 @@ func setRichText(runs []RichTextRun) ([]xlsxR, error) {
return textRuns, ErrCellCharsLength
}
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
if fnt != nil {
run.RPr = newRpr(fnt)
Expand Down
38 changes: 29 additions & 9 deletions cell_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,16 +177,36 @@ func TestSetCellFloat(t *testing.T) {
}

func TestSetCellValuesMultiByte(t *testing.T) {
value := strings.Repeat("\u042B", TotalCellChars+1)

f := NewFile()
err := f.SetCellValue("Sheet1", "A1", value)
assert.NoError(t, err)

v, err := f.GetCellValue("Sheet1", "A1")
assert.NoError(t, err)
assert.NotEqual(t, value, v)
assert.Equal(t, TotalCellChars, len([]rune(v)))
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)
streamWriter, err := f.NewStreamWriter("Sheet2")
assert.NoError(t, err)
assert.NoError(t, streamWriter.SetRow("A1", row))
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) {
Expand Down

0 comments on commit 17c0294

Please sign in to comment.