lib.go 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. // Copyright 2016 - 2020 The excelize Authors. All rights reserved. Use of
  2. // this source code is governed by a BSD-style license that can be found in
  3. // the LICENSE file.
  4. //
  5. // Package excelize providing a set of functions that allow you to write to
  6. // and read from XLSX / XLSM / XLTM files. Supports reading and writing
  7. // spreadsheet documents generated by Microsoft Exce™ 2007 and later. Supports
  8. // complex components by high compatibility, and provided streaming API for
  9. // generating or reading data from a worksheet with huge amounts of data. This
  10. // library needs Go version 1.10 or later.
  11. package excelize
  12. import (
  13. "archive/zip"
  14. "bytes"
  15. "container/list"
  16. "fmt"
  17. "io"
  18. "strconv"
  19. "strings"
  20. "unsafe"
  21. )
  22. // ReadZipReader can be used to read the spreadsheet in memory without touching the
  23. // filesystem.
  24. func ReadZipReader(r *zip.Reader) (map[string][]byte, int, error) {
  25. var err error
  26. fileList := make(map[string][]byte, len(r.File))
  27. worksheets := 0
  28. for _, v := range r.File {
  29. if fileList[v.Name], err = readFile(v); err != nil {
  30. return nil, 0, err
  31. }
  32. if strings.HasPrefix(v.Name, "xl/worksheets/sheet") {
  33. worksheets++
  34. }
  35. }
  36. return fileList, worksheets, nil
  37. }
  38. // readXML provides a function to read XML content as string.
  39. func (f *File) readXML(name string) []byte {
  40. if content, ok := f.XLSX[name]; ok {
  41. return content
  42. }
  43. return []byte{}
  44. }
  45. // saveFileList provides a function to update given file content in file list
  46. // of XLSX.
  47. func (f *File) saveFileList(name string, content []byte) {
  48. newContent := make([]byte, 0, len(XMLHeader)+len(content))
  49. newContent = append(newContent, []byte(XMLHeader)...)
  50. newContent = append(newContent, content...)
  51. f.XLSX[name] = newContent
  52. }
  53. // Read file content as string in a archive file.
  54. func readFile(file *zip.File) ([]byte, error) {
  55. rc, err := file.Open()
  56. if err != nil {
  57. return nil, err
  58. }
  59. dat := make([]byte, 0, file.FileInfo().Size())
  60. buff := bytes.NewBuffer(dat)
  61. _, _ = io.Copy(buff, rc)
  62. rc.Close()
  63. return buff.Bytes(), nil
  64. }
  65. // SplitCellName splits cell name to column name and row number.
  66. //
  67. // Example:
  68. //
  69. // excelize.SplitCellName("AK74") // return "AK", 74, nil
  70. //
  71. func SplitCellName(cell string) (string, int, error) {
  72. alpha := func(r rune) bool {
  73. return ('A' <= r && r <= 'Z') || ('a' <= r && r <= 'z')
  74. }
  75. if strings.IndexFunc(cell, alpha) == 0 {
  76. i := strings.LastIndexFunc(cell, alpha)
  77. if i >= 0 && i < len(cell)-1 {
  78. col, rowstr := cell[:i+1], cell[i+1:]
  79. if row, err := strconv.Atoi(rowstr); err == nil && row > 0 {
  80. return col, row, nil
  81. }
  82. }
  83. }
  84. return "", -1, newInvalidCellNameError(cell)
  85. }
  86. // JoinCellName joins cell name from column name and row number.
  87. func JoinCellName(col string, row int) (string, error) {
  88. normCol := strings.Map(func(rune rune) rune {
  89. switch {
  90. case 'A' <= rune && rune <= 'Z':
  91. return rune
  92. case 'a' <= rune && rune <= 'z':
  93. return rune - 32
  94. }
  95. return -1
  96. }, col)
  97. if len(col) == 0 || len(col) != len(normCol) {
  98. return "", newInvalidColumnNameError(col)
  99. }
  100. if row < 1 {
  101. return "", newInvalidRowNumberError(row)
  102. }
  103. return normCol + strconv.Itoa(row), nil
  104. }
  105. // ColumnNameToNumber provides a function to convert Excel sheet column name
  106. // to int. Column name case insensitive. The function returns an error if
  107. // column name incorrect.
  108. //
  109. // Example:
  110. //
  111. // excelize.ColumnNameToNumber("AK") // returns 37, nil
  112. //
  113. func ColumnNameToNumber(name string) (int, error) {
  114. if len(name) == 0 {
  115. return -1, newInvalidColumnNameError(name)
  116. }
  117. col := 0
  118. multi := 1
  119. for i := len(name) - 1; i >= 0; i-- {
  120. r := name[i]
  121. if r >= 'A' && r <= 'Z' {
  122. col += int(r-'A'+1) * multi
  123. } else if r >= 'a' && r <= 'z' {
  124. col += int(r-'a'+1) * multi
  125. } else {
  126. return -1, newInvalidColumnNameError(name)
  127. }
  128. multi *= 26
  129. }
  130. if col > TotalColumns {
  131. return -1, fmt.Errorf("column number exceeds maximum limit")
  132. }
  133. return col, nil
  134. }
  135. // ColumnNumberToName provides a function to convert the integer to Excel
  136. // sheet column title.
  137. //
  138. // Example:
  139. //
  140. // excelize.ColumnNumberToName(37) // returns "AK", nil
  141. //
  142. func ColumnNumberToName(num int) (string, error) {
  143. if num < 1 {
  144. return "", fmt.Errorf("incorrect column number %d", num)
  145. }
  146. if num > TotalColumns {
  147. return "", fmt.Errorf("column number exceeds maximum limit")
  148. }
  149. var col string
  150. for num > 0 {
  151. col = string((num-1)%26+65) + col
  152. num = (num - 1) / 26
  153. }
  154. return col, nil
  155. }
  156. // CellNameToCoordinates converts alphanumeric cell name to [X, Y] coordinates
  157. // or returns an error.
  158. //
  159. // Example:
  160. //
  161. // excelize.CellNameToCoordinates("A1") // returns 1, 1, nil
  162. // excelize.CellNameToCoordinates("Z3") // returns 26, 3, nil
  163. //
  164. func CellNameToCoordinates(cell string) (int, int, error) {
  165. const msg = "cannot convert cell %q to coordinates: %v"
  166. colname, row, err := SplitCellName(cell)
  167. if err != nil {
  168. return -1, -1, fmt.Errorf(msg, cell, err)
  169. }
  170. if row > TotalRows {
  171. return -1, -1, fmt.Errorf("row number exceeds maximum limit")
  172. }
  173. col, err := ColumnNameToNumber(colname)
  174. return col, row, err
  175. }
  176. // CoordinatesToCellName converts [X, Y] coordinates to alpha-numeric cell
  177. // name or returns an error.
  178. //
  179. // Example:
  180. //
  181. // excelize.CoordinatesToCellName(1, 1) // returns "A1", nil
  182. //
  183. func CoordinatesToCellName(col, row int) (string, error) {
  184. if col < 1 || row < 1 {
  185. return "", fmt.Errorf("invalid cell coordinates [%d, %d]", col, row)
  186. }
  187. colname, err := ColumnNumberToName(col)
  188. return fmt.Sprintf("%s%d", colname, row), err
  189. }
  190. // boolPtr returns a pointer to a bool with the given value.
  191. func boolPtr(b bool) *bool { return &b }
  192. // intPtr returns a pointer to a int with the given value.
  193. func intPtr(i int) *int { return &i }
  194. // float64Ptr returns a pofloat64er to a float64 with the given value.
  195. func float64Ptr(f float64) *float64 { return &f }
  196. // stringPtr returns a pointer to a string with the given value.
  197. func stringPtr(s string) *string { return &s }
  198. // defaultTrue returns true if b is nil, or the pointed value.
  199. func defaultTrue(b *bool) bool {
  200. if b == nil {
  201. return true
  202. }
  203. return *b
  204. }
  205. // parseFormatSet provides a method to convert format string to []byte and
  206. // handle empty string.
  207. func parseFormatSet(formatSet string) []byte {
  208. if formatSet != "" {
  209. return []byte(formatSet)
  210. }
  211. return []byte("{}")
  212. }
  213. // namespaceStrictToTransitional provides a method to convert Strict and
  214. // Transitional namespaces.
  215. func namespaceStrictToTransitional(content []byte) []byte {
  216. var namespaceTranslationDic = map[string]string{
  217. StrictSourceRelationship: SourceRelationship,
  218. StrictSourceRelationshipChart: SourceRelationshipChart,
  219. StrictSourceRelationshipComments: SourceRelationshipComments,
  220. StrictSourceRelationshipImage: SourceRelationshipImage,
  221. StrictNameSpaceSpreadSheet: NameSpaceSpreadSheet,
  222. }
  223. for s, n := range namespaceTranslationDic {
  224. content = bytesReplace(content, stringToBytes(s), stringToBytes(n), -1)
  225. }
  226. return content
  227. }
  228. // stringToBytes cast a string to bytes pointer and assign the value of this
  229. // pointer.
  230. func stringToBytes(s string) []byte {
  231. return *(*[]byte)(unsafe.Pointer(&s))
  232. }
  233. // bytesReplace replace old bytes with given new.
  234. func bytesReplace(s, old, new []byte, n int) []byte {
  235. if n == 0 {
  236. return s
  237. }
  238. if len(old) < len(new) {
  239. return bytes.Replace(s, old, new, n)
  240. }
  241. if n < 0 {
  242. n = len(s)
  243. }
  244. var wid, i, j, w int
  245. for i, j = 0, 0; i < len(s) && j < n; j++ {
  246. wid = bytes.Index(s[i:], old)
  247. if wid < 0 {
  248. break
  249. }
  250. w += copy(s[w:], s[i:i+wid])
  251. w += copy(s[w:], new)
  252. i += wid + len(old)
  253. }
  254. w += copy(s[w:], s[i:])
  255. return s[0:w]
  256. }
  257. // genSheetPasswd provides a method to generate password for worksheet
  258. // protection by given plaintext. When an Excel sheet is being protected with
  259. // a password, a 16-bit (two byte) long hash is generated. To verify a
  260. // password, it is compared to the hash. Obviously, if the input data volume
  261. // is great, numerous passwords will match the same hash. Here is the
  262. // algorithm to create the hash value:
  263. //
  264. // take the ASCII values of all characters shift left the first character 1 bit,
  265. // the second 2 bits and so on (use only the lower 15 bits and rotate all higher bits,
  266. // the highest bit of the 16-bit value is always 0 [signed short])
  267. // XOR all these values
  268. // XOR the count of characters
  269. // XOR the constant 0xCE4B
  270. func genSheetPasswd(plaintext string) string {
  271. var password int64 = 0x0000
  272. var charPos uint = 1
  273. for _, v := range plaintext {
  274. value := int64(v) << charPos
  275. charPos++
  276. rotatedBits := value >> 15 // rotated bits beyond bit 15
  277. value &= 0x7fff // first 15 bits
  278. password ^= (value | rotatedBits)
  279. }
  280. password ^= int64(len(plaintext))
  281. password ^= 0xCE4B
  282. return strings.ToUpper(strconv.FormatInt(password, 16))
  283. }
  284. // Stack defined an abstract data type that serves as a collection of elements.
  285. type Stack struct {
  286. list *list.List
  287. }
  288. // NewStack create a new stack.
  289. func NewStack() *Stack {
  290. list := list.New()
  291. return &Stack{list}
  292. }
  293. // Push a value onto the top of the stack.
  294. func (stack *Stack) Push(value interface{}) {
  295. stack.list.PushBack(value)
  296. }
  297. // Pop the top item of the stack and return it.
  298. func (stack *Stack) Pop() interface{} {
  299. e := stack.list.Back()
  300. if e != nil {
  301. stack.list.Remove(e)
  302. return e.Value
  303. }
  304. return nil
  305. }
  306. // Peek view the top item on the stack.
  307. func (stack *Stack) Peek() interface{} {
  308. e := stack.list.Back()
  309. if e != nil {
  310. return e.Value
  311. }
  312. return nil
  313. }
  314. // Len return the number of items in the stack.
  315. func (stack *Stack) Len() int {
  316. return stack.list.Len()
  317. }
  318. // Empty the stack.
  319. func (stack *Stack) Empty() bool {
  320. return stack.list.Len() == 0
  321. }