lib.go 9.1 KB

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