summaryrefslogtreecommitdiff
path: root/lib.go
diff options
context:
space:
mode:
Diffstat (limited to 'lib.go')
-rw-r--r--lib.go120
1 files changed, 106 insertions, 14 deletions
diff --git a/lib.go b/lib.go
index b99b175..41b03c7 100644
--- a/lib.go
+++ b/lib.go
@@ -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
+}