Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions calc.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import (
"sync"
"time"
"unicode"
"unicode/utf16"
"unicode/utf8"
"unsafe"

Expand Down Expand Up @@ -14509,7 +14508,7 @@ func (fn *formulaFuncs) TEXTJOIN(argsList *list.List) formulaArg {
return ok
}
result := strings.Join(args, delimiter.Value())
if len(utf16.Encode([]rune(result))) > TotalCellChars {
if countUTF16String(result) > TotalCellChars {
return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("TEXTJOIN function exceeds %d characters", TotalCellChars))
}
return newStringFormulaArg(result)
Expand Down
7 changes: 3 additions & 4 deletions cell.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"strconv"
"strings"
"time"
"unicode/utf16"

"github.com/xuri/efp"
)
Expand Down Expand Up @@ -447,7 +446,7 @@ func (f *File) SetCellStr(sheet, cell, value string) error {

// setCellString provides a function to set string type to shared string table.
func (f *File) setCellString(value string) (t, v string, err error) {
if len(utf16.Encode([]rune(value))) > TotalCellChars {
if countUTF16String(value) > TotalCellChars {
value = truncateUTF16Units(value, TotalCellChars)
}
t = "s"
Expand Down Expand Up @@ -510,7 +509,7 @@ func (f *File) setSharedString(val string) (int, error) {

// trimCellValue provides a function to set string type to cell.
func trimCellValue(value string, escape bool) (v string, ns xml.Attr) {
if len(utf16.Encode([]rune(value))) > TotalCellChars {
if countUTF16String(value) > TotalCellChars {
value = truncateUTF16Units(value, TotalCellChars)
}
if value != "" {
Expand Down Expand Up @@ -1211,7 +1210,7 @@ func setRichText(runs []RichTextRun) ([]xlsxR, error) {
totalCellChars int
)
for _, textRun := range runs {
totalCellChars += len(utf16.Encode([]rune(textRun.Text)))
totalCellChars += countUTF16String(textRun.Text)
if totalCellChars > TotalCellChars {
return textRuns, ErrCellCharsLength
}
Expand Down
11 changes: 11 additions & 0 deletions chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,9 @@ func (opts *Chart) parseTitle() {
// ShowPercent
// ShowSerName
// ShowVal
// Fill
// UpBars
// DownBars
// NumFmt
//
// SecondPlotValues: Specifies the values in second plot for the 'PieOfPie' and
Expand Down Expand Up @@ -935,6 +938,14 @@ func (opts *Chart) parseTitle() {
// ShowVal: Specifies that the value shall be shown in a data label.
// The 'ShowVal' property is optional. The default value is false.
//
// Fill: Set fill color of the chart.
//
// UpBars: Specifies the format for stock chart up bars. The 'UpBars' property
// is optional.
//
// DownBars: Specifies the format for stock chart down bars. The 'DownBars'
// property is optional.
//
// NumFmt: Specifies that if linked to source and set custom number format code
// for data labels. The 'NumFmt' property is optional. The default format code
// is 'General'.
Expand Down
3 changes: 1 addition & 2 deletions datavalidation.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"math"
"slices"
"strings"
"unicode/utf16"
)

// DataValidationType defined the type of data validation.
Expand Down Expand Up @@ -150,7 +149,7 @@ func (dv *DataValidation) SetInput(title, msg string) {
// for their cells.
func (dv *DataValidation) SetDropList(keys []string) error {
formula := strings.Join(keys, ",")
if MaxFieldLength < len(utf16.Encode([]rune(formula))) {
if MaxFieldLength < countUTF16String(formula) {
return ErrDataValidationFormulaLength
}
dv.Type = dataValidationTypeMap[DataValidationTypeList]
Expand Down
8 changes: 4 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
module github.com/xuri/excelize/v2

go 1.23.0
go 1.24.0

require (
github.com/richardlehane/mscfb v1.0.4
github.com/stretchr/testify v1.10.0
github.com/tiendc/go-deepcopy v1.6.1
github.com/xuri/efp v0.0.1
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9
golang.org/x/crypto v0.40.0
golang.org/x/crypto v0.42.0
golang.org/x/image v0.25.0
golang.org/x/net v0.42.0
golang.org/x/text v0.27.0
golang.org/x/net v0.44.0
golang.org/x/text v0.29.0
)

require (
Expand Down
12 changes: 6 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ github.com/xuri/efp v0.0.1 h1:fws5Rv3myXyYni8uwj2qKjVaRP30PdjeYe2Y6FDsCL8=
github.com/xuri/efp v0.0.1/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 h1:+C0TIdyyYmzadGaL/HBLbf3WdLgC29pgyhTjAT/0nuE=
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ=
golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs=
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down
9 changes: 9 additions & 0 deletions lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -941,6 +941,15 @@ func setPtrFieldsVal(fields []string, immutable, mutable reflect.Value) {
}
}

// countUTF16String returns the number of UTF-16 code units in a string.
func countUTF16String(s string) int {
var cnt int
for _, r := range s {
cnt += utf16.RuneLen(r)
}
return cnt
}

// truncateUTF16Units truncates a string to a maximum number of UTF-16 code
// units.
func truncateUTF16Units(s string, length int) string {
Expand Down
3 changes: 1 addition & 2 deletions lib_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"strings"
"sync"
"testing"
"unicode/utf16"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -357,7 +356,7 @@ func TestBstrMarshal(t *testing.T) {
func TestTruncateUTF16Units(t *testing.T) {
assertTrunc := func(s string, max int, expected string) {
assert.Equal(t, expected, truncateUTF16Units(s, max), "src=%q max=%d", s, max)
assert.LessOrEqual(t, len(utf16.Encode([]rune(truncateUTF16Units(s, max)))), max)
assert.LessOrEqual(t, countUTF16String(truncateUTF16Units(s, max)), max)
}
// No truncation
assertTrunc("ABC", 3, "ABC")
Expand Down
5 changes: 2 additions & 3 deletions sheet.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"sort"
"strconv"
"strings"
"unicode/utf16"

"github.com/tiendc/go-deepcopy"
)
Expand Down Expand Up @@ -1341,7 +1340,7 @@ func (f *File) SetHeaderFooter(sheet string, opts *HeaderFooterOptions) error {
// Check 6 string type fields: OddHeader, OddFooter, EvenHeader, EvenFooter,
// FirstFooter, FirstHeader
for i := 4; i < v.NumField()-1; i++ {
if len(utf16.Encode([]rune(v.Field(i).String()))) > MaxFieldLength {
if countUTF16String(v.Field(i).String()) > MaxFieldLength {
return newFieldLengthError(v.Type().Field(i).Name)
}
}
Expand Down Expand Up @@ -1484,7 +1483,7 @@ func checkSheetName(name string) error {
if name == "" {
return ErrSheetNameBlank
}
if len(utf16.Encode([]rune(name))) > MaxSheetNameLength {
if countUTF16String(name) > MaxSheetNameLength {
return ErrSheetNameLength
}
if strings.HasPrefix(name, "'") || strings.HasSuffix(name, "'") {
Expand Down
Loading