diff options
Diffstat (limited to 'lib.go')
-rw-r--r-- | lib.go | 120 |
1 files changed, 106 insertions, 14 deletions
@@ -1,35 +1,35 @@ -// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of +// Copyright 2016 - 2020 The excelize Authors. All rights reserved. Use of // this source code is governed by a BSD-style license that can be found in // the LICENSE file. // // Package excelize providing a set of functions that allow you to write to // and read from XLSX files. Support reads and writes XLSX file generated by // Microsoft Excelâ„¢ 2007 and later. Support save file without losing original -// charts of XLSX. This library needs Go version 1.8 or later. +// charts of XLSX. This library needs Go version 1.10 or later. package excelize import ( "archive/zip" "bytes" + "container/list" "fmt" "io" "log" "strconv" "strings" + "unsafe" ) -// ReadZipReader can be used to read an XLSX in memory without touching the +// ReadZipReader can be used to read the spreadsheet in memory without touching the // filesystem. func ReadZipReader(r *zip.Reader) (map[string][]byte, int, error) { - fileList := make(map[string][]byte) + fileList := make(map[string][]byte, len(r.File)) worksheets := 0 for _, v := range r.File { fileList[v.Name] = readFile(v) - if len(v.Name) > 18 { - if v.Name[0:19] == "xl/worksheets/sheet" { - worksheets++ - } + if strings.HasPrefix(v.Name, "xl/worksheets/sheet") { + worksheets++ } } return fileList, worksheets, nil @@ -58,7 +58,8 @@ func readFile(file *zip.File) []byte { if err != nil { log.Fatal(err) } - buff := bytes.NewBuffer(nil) + dat := make([]byte, 0, file.FileInfo().Size()) + buff := bytes.NewBuffer(dat) _, _ = io.Copy(buff, rc) rc.Close() return buff.Bytes() @@ -104,7 +105,7 @@ func JoinCellName(col string, row int) (string, error) { if row < 1 { return "", newInvalidRowNumberError(row) } - return fmt.Sprintf("%s%d", normCol, row), nil + return normCol + strconv.Itoa(row), nil } // ColumnNameToNumber provides a function to convert Excel sheet column name @@ -159,8 +160,8 @@ func ColumnNumberToName(num int) (string, error) { // // Example: // -// CellCoordinates("A1") // returns 1, 1, nil -// CellCoordinates("Z3") // returns 26, 3, nil +// excelize.CellNameToCoordinates("A1") // returns 1, 1, nil +// excelize.CellNameToCoordinates("Z3") // returns 26, 3, nil // func CellNameToCoordinates(cell string) (int, int, error) { const msg = "cannot convert cell %q to coordinates: %v" @@ -183,7 +184,7 @@ func CellNameToCoordinates(cell string) (int, int, error) { // // Example: // -// CoordinatesToCellName(1, 1) // returns "A1", nil +// excelize.CoordinatesToCellName(1, 1) // returns "A1", nil // func CoordinatesToCellName(col, row int) (string, error) { if col < 1 || row < 1 { @@ -191,6 +192,7 @@ func CoordinatesToCellName(col, row int) (string, error) { } colname, err := ColumnNumberToName(col) if err != nil { + // Error should never happens here. return "", fmt.Errorf("invalid cell coordinates [%d, %d]: %v", col, row, err) } return fmt.Sprintf("%s%d", colname, row), nil @@ -199,6 +201,15 @@ func CoordinatesToCellName(col, row int) (string, error) { // boolPtr returns a pointer to a bool with the given value. func boolPtr(b bool) *bool { return &b } +// intPtr returns a pointer to a int with the given value. +func intPtr(i int) *int { return &i } + +// float64Ptr returns a pofloat64er to a float64 with the given value. +func float64Ptr(f float64) *float64 { return &f } + +// stringPtr returns a pointer to a string with the given value. +func stringPtr(s string) *string { return &s } + // defaultTrue returns true if b is nil, or the pointed value. func defaultTrue(b *bool) bool { if b == nil { @@ -227,11 +238,47 @@ func namespaceStrictToTransitional(content []byte) []byte { StrictNameSpaceSpreadSheet: NameSpaceSpreadSheet, } for s, n := range namespaceTranslationDic { - content = bytes.Replace(content, []byte(s), []byte(n), -1) + content = bytesReplace(content, stringToBytes(s), stringToBytes(n), -1) } return content } +// stringToBytes cast a string to bytes pointer and assign the value of this +// pointer. +func stringToBytes(s string) []byte { + return *(*[]byte)(unsafe.Pointer(&s)) +} + +// bytesReplace replace old bytes with given new. +func bytesReplace(s, old, new []byte, n int) []byte { + if n == 0 { + return s + } + + if len(old) < len(new) { + return bytes.Replace(s, old, new, n) + } + + if n < 0 { + n = len(s) + } + + var wid, i, j, w int + for i, j = 0, 0; i < len(s) && j < n; j++ { + wid = bytes.Index(s[i:], old) + if wid < 0 { + break + } + + w += copy(s[w:], s[i:i+wid]) + w += copy(s[w:], new) + i += wid + len(old) + } + + w += copy(s[w:], s[i:]) + return s[0:w] +} + // genSheetPasswd provides a method to generate password for worksheet // protection by given plaintext. When an Excel sheet is being protected with // a password, a 16-bit (two byte) long hash is generated. To verify a @@ -259,3 +306,48 @@ func genSheetPasswd(plaintext string) string { password ^= 0xCE4B return strings.ToUpper(strconv.FormatInt(password, 16)) } + +// Stack defined an abstract data type that serves as a collection of elements. +type Stack struct { + list *list.List +} + +// NewStack create a new stack. +func NewStack() *Stack { + list := list.New() + return &Stack{list} +} + +// Push a value onto the top of the stack. +func (stack *Stack) Push(value interface{}) { + stack.list.PushBack(value) +} + +// Pop the top item of the stack and return it. +func (stack *Stack) Pop() interface{} { + e := stack.list.Back() + if e != nil { + stack.list.Remove(e) + return e.Value + } + return nil +} + +// Peek view the top item on the stack. +func (stack *Stack) Peek() interface{} { + e := stack.list.Back() + if e != nil { + return e.Value + } + return nil +} + +// Len return the number of items in the stack. +func (stack *Stack) Len() int { + return stack.list.Len() +} + +// Empty the stack. +func (stack *Stack) Empty() bool { + return stack.list.Len() == 0 +} |