diff --git a/calc.go b/calc.go index 5f991bafa2..0272c91b82 100644 --- a/calc.go +++ b/calc.go @@ -29,7 +29,6 @@ import ( "sync" "time" "unicode" - "unicode/utf16" "unicode/utf8" "unsafe" @@ -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) diff --git a/cell.go b/cell.go index baa5555fde..278d9f45a2 100644 --- a/cell.go +++ b/cell.go @@ -21,7 +21,6 @@ import ( "strconv" "strings" "time" - "unicode/utf16" "github.com/xuri/efp" ) @@ -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" @@ -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 != "" { @@ -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 } diff --git a/chart.go b/chart.go index 3cc11182a1..bf232020f4 100644 --- a/chart.go +++ b/chart.go @@ -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 @@ -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'. diff --git a/datavalidation.go b/datavalidation.go index 3b5a852dbc..68de62a785 100644 --- a/datavalidation.go +++ b/datavalidation.go @@ -18,7 +18,6 @@ import ( "math" "slices" "strings" - "unicode/utf16" ) // DataValidationType defined the type of data validation. @@ -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] diff --git a/go.mod b/go.mod index 91868dcb3f..571f7680c6 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/xuri/excelize/v2 -go 1.23.0 +go 1.24.0 require ( github.com/richardlehane/mscfb v1.0.4 @@ -8,10 +8,10 @@ require ( 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 ( diff --git a/go.sum b/go.sum index 106b26cd6a..f141ca1839 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/lib.go b/lib.go index 73d37c74e7..e12965d0f1 100644 --- a/lib.go +++ b/lib.go @@ -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 { diff --git a/lib_test.go b/lib_test.go index 6d33b19de7..fe5eed0530 100644 --- a/lib_test.go +++ b/lib_test.go @@ -11,7 +11,6 @@ import ( "strings" "sync" "testing" - "unicode/utf16" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -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") diff --git a/sheet.go b/sheet.go index c68bc5a032..1440ba58df 100644 --- a/sheet.go +++ b/sheet.go @@ -24,7 +24,6 @@ import ( "sort" "strconv" "strings" - "unicode/utf16" "github.com/tiendc/go-deepcopy" ) @@ -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) } } @@ -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, "'") {