lib.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. // Copyright 2016 - 2021 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 Excel™ 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.15 or later.
  11. package excelize
  12. import (
  13. "archive/zip"
  14. "bytes"
  15. "container/list"
  16. "encoding/xml"
  17. "fmt"
  18. "io"
  19. "strconv"
  20. "strings"
  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. var docPart = map[string]string{
  27. "[content_types].xml": "[Content_Types].xml",
  28. "xl/sharedstrings.xml": "xl/sharedStrings.xml",
  29. }
  30. fileList := make(map[string][]byte, len(r.File))
  31. worksheets := 0
  32. for _, v := range r.File {
  33. fileName := strings.Replace(v.Name, "\\", "/", -1)
  34. if partName, ok := docPart[strings.ToLower(fileName)]; ok {
  35. fileName = partName
  36. }
  37. if fileList[fileName], err = readFile(v); err != nil {
  38. return nil, 0, err
  39. }
  40. if strings.HasPrefix(fileName, "xl/worksheets/sheet") {
  41. worksheets++
  42. }
  43. }
  44. return fileList, worksheets, nil
  45. }
  46. // readXML provides a function to read XML content as string.
  47. func (f *File) readXML(name string) []byte {
  48. if content, ok := f.XLSX[name]; ok {
  49. return content
  50. }
  51. if content, ok := f.streams[name]; ok {
  52. return content.rawData.buf.Bytes()
  53. }
  54. return []byte{}
  55. }
  56. // saveFileList provides a function to update given file content in file list
  57. // of XLSX.
  58. func (f *File) saveFileList(name string, content []byte) {
  59. newContent := make([]byte, 0, len(XMLHeader)+len(content))
  60. newContent = append(newContent, []byte(XMLHeader)...)
  61. newContent = append(newContent, content...)
  62. f.XLSX[name] = newContent
  63. }
  64. // Read file content as string in a archive file.
  65. func readFile(file *zip.File) ([]byte, error) {
  66. rc, err := file.Open()
  67. if err != nil {
  68. return nil, err
  69. }
  70. dat := make([]byte, 0, file.FileInfo().Size())
  71. buff := bytes.NewBuffer(dat)
  72. _, _ = io.Copy(buff, rc)
  73. rc.Close()
  74. return buff.Bytes(), nil
  75. }
  76. // SplitCellName splits cell name to column name and row number.
  77. //
  78. // Example:
  79. //
  80. // excelize.SplitCellName("AK74") // return "AK", 74, nil
  81. //
  82. func SplitCellName(cell string) (string, int, error) {
  83. alpha := func(r rune) bool {
  84. return ('A' <= r && r <= 'Z') || ('a' <= r && r <= 'z')
  85. }
  86. if strings.IndexFunc(cell, alpha) == 0 {
  87. i := strings.LastIndexFunc(cell, alpha)
  88. if i >= 0 && i < len(cell)-1 {
  89. col, rowstr := cell[:i+1], cell[i+1:]
  90. if row, err := strconv.Atoi(rowstr); err == nil && row > 0 {
  91. return col, row, nil
  92. }
  93. }
  94. }
  95. return "", -1, newInvalidCellNameError(cell)
  96. }
  97. // JoinCellName joins cell name from column name and row number.
  98. func JoinCellName(col string, row int) (string, error) {
  99. normCol := strings.Map(func(rune rune) rune {
  100. switch {
  101. case 'A' <= rune && rune <= 'Z':
  102. return rune
  103. case 'a' <= rune && rune <= 'z':
  104. return rune - 32
  105. }
  106. return -1
  107. }, col)
  108. if len(col) == 0 || len(col) != len(normCol) {
  109. return "", newInvalidColumnNameError(col)
  110. }
  111. if row < 1 {
  112. return "", newInvalidRowNumberError(row)
  113. }
  114. return normCol + strconv.Itoa(row), nil
  115. }
  116. // ColumnNameToNumber provides a function to convert Excel sheet column name
  117. // to int. Column name case insensitive. The function returns an error if
  118. // column name incorrect.
  119. //
  120. // Example:
  121. //
  122. // excelize.ColumnNameToNumber("AK") // returns 37, nil
  123. //
  124. func ColumnNameToNumber(name string) (int, error) {
  125. if len(name) == 0 {
  126. return -1, newInvalidColumnNameError(name)
  127. }
  128. col := 0
  129. multi := 1
  130. for i := len(name) - 1; i >= 0; i-- {
  131. r := name[i]
  132. if r >= 'A' && r <= 'Z' {
  133. col += int(r-'A'+1) * multi
  134. } else if r >= 'a' && r <= 'z' {
  135. col += int(r-'a'+1) * multi
  136. } else {
  137. return -1, newInvalidColumnNameError(name)
  138. }
  139. multi *= 26
  140. }
  141. if col > TotalColumns {
  142. return -1, ErrColumnNumber
  143. }
  144. return col, nil
  145. }
  146. // ColumnNumberToName provides a function to convert the integer to Excel
  147. // sheet column title.
  148. //
  149. // Example:
  150. //
  151. // excelize.ColumnNumberToName(37) // returns "AK", nil
  152. //
  153. func ColumnNumberToName(num int) (string, error) {
  154. if num < 1 {
  155. return "", fmt.Errorf("incorrect column number %d", num)
  156. }
  157. if num > TotalColumns {
  158. return "", ErrColumnNumber
  159. }
  160. var col string
  161. for num > 0 {
  162. col = string(rune((num-1)%26+65)) + col
  163. num = (num - 1) / 26
  164. }
  165. return col, nil
  166. }
  167. // CellNameToCoordinates converts alphanumeric cell name to [X, Y] coordinates
  168. // or returns an error.
  169. //
  170. // Example:
  171. //
  172. // excelize.CellNameToCoordinates("A1") // returns 1, 1, nil
  173. // excelize.CellNameToCoordinates("Z3") // returns 26, 3, nil
  174. //
  175. func CellNameToCoordinates(cell string) (int, int, error) {
  176. const msg = "cannot convert cell %q to coordinates: %v"
  177. colname, row, err := SplitCellName(cell)
  178. if err != nil {
  179. return -1, -1, fmt.Errorf(msg, cell, err)
  180. }
  181. if row > TotalRows {
  182. return -1, -1, fmt.Errorf("row number exceeds maximum limit")
  183. }
  184. col, err := ColumnNameToNumber(colname)
  185. return col, row, err
  186. }
  187. // CoordinatesToCellName converts [X, Y] coordinates to alpha-numeric cell
  188. // name or returns an error.
  189. //
  190. // Example:
  191. //
  192. // excelize.CoordinatesToCellName(1, 1) // returns "A1", nil
  193. // excelize.CoordinatesToCellName(1, 1, true) // returns "$A$1", nil
  194. //
  195. func CoordinatesToCellName(col, row int, abs ...bool) (string, error) {
  196. if col < 1 || row < 1 {
  197. return "", fmt.Errorf("invalid cell coordinates [%d, %d]", col, row)
  198. }
  199. sign := ""
  200. for _, a := range abs {
  201. if a {
  202. sign = "$"
  203. }
  204. }
  205. colname, err := ColumnNumberToName(col)
  206. return sign + colname + sign + strconv.Itoa(row), err
  207. }
  208. // boolPtr returns a pointer to a bool with the given value.
  209. func boolPtr(b bool) *bool { return &b }
  210. // intPtr returns a pointer to a int with the given value.
  211. func intPtr(i int) *int { return &i }
  212. // float64Ptr returns a pofloat64er to a float64 with the given value.
  213. func float64Ptr(f float64) *float64 { return &f }
  214. // stringPtr returns a pointer to a string with the given value.
  215. func stringPtr(s string) *string { return &s }
  216. // defaultTrue returns true if b is nil, or the pointed value.
  217. func defaultTrue(b *bool) bool {
  218. if b == nil {
  219. return true
  220. }
  221. return *b
  222. }
  223. // parseFormatSet provides a method to convert format string to []byte and
  224. // handle empty string.
  225. func parseFormatSet(formatSet string) []byte {
  226. if formatSet != "" {
  227. return []byte(formatSet)
  228. }
  229. return []byte("{}")
  230. }
  231. // namespaceStrictToTransitional provides a method to convert Strict and
  232. // Transitional namespaces.
  233. func namespaceStrictToTransitional(content []byte) []byte {
  234. var namespaceTranslationDic = map[string]string{
  235. StrictSourceRelationship: SourceRelationship.Value,
  236. StrictSourceRelationshipOfficeDocument: SourceRelationshipOfficeDocument,
  237. StrictSourceRelationshipChart: SourceRelationshipChart,
  238. StrictSourceRelationshipComments: SourceRelationshipComments,
  239. StrictSourceRelationshipImage: SourceRelationshipImage,
  240. StrictNameSpaceSpreadSheet: NameSpaceSpreadSheet.Value,
  241. }
  242. for s, n := range namespaceTranslationDic {
  243. content = bytesReplace(content, []byte(s), []byte(n), -1)
  244. }
  245. return content
  246. }
  247. // bytesReplace replace old bytes with given new.
  248. func bytesReplace(s, old, new []byte, n int) []byte {
  249. if n == 0 {
  250. return s
  251. }
  252. if len(old) < len(new) {
  253. return bytes.Replace(s, old, new, n)
  254. }
  255. if n < 0 {
  256. n = len(s)
  257. }
  258. var wid, i, j, w int
  259. for i, j = 0, 0; i < len(s) && j < n; j++ {
  260. wid = bytes.Index(s[i:], old)
  261. if wid < 0 {
  262. break
  263. }
  264. w += copy(s[w:], s[i:i+wid])
  265. w += copy(s[w:], new)
  266. i += wid + len(old)
  267. }
  268. w += copy(s[w:], s[i:])
  269. return s[0:w]
  270. }
  271. // genSheetPasswd provides a method to generate password for worksheet
  272. // protection by given plaintext. When an Excel sheet is being protected with
  273. // a password, a 16-bit (two byte) long hash is generated. To verify a
  274. // password, it is compared to the hash. Obviously, if the input data volume
  275. // is great, numerous passwords will match the same hash. Here is the
  276. // algorithm to create the hash value:
  277. //
  278. // take the ASCII values of all characters shift left the first character 1 bit,
  279. // the second 2 bits and so on (use only the lower 15 bits and rotate all higher bits,
  280. // the highest bit of the 16-bit value is always 0 [signed short])
  281. // XOR all these values
  282. // XOR the count of characters
  283. // XOR the constant 0xCE4B
  284. func genSheetPasswd(plaintext string) string {
  285. var password int64 = 0x0000
  286. var charPos uint = 1
  287. for _, v := range plaintext {
  288. value := int64(v) << charPos
  289. charPos++
  290. rotatedBits := value >> 15 // rotated bits beyond bit 15
  291. value &= 0x7fff // first 15 bits
  292. password ^= (value | rotatedBits)
  293. }
  294. password ^= int64(len(plaintext))
  295. password ^= 0xCE4B
  296. return strings.ToUpper(strconv.FormatInt(password, 16))
  297. }
  298. // getRootElement extract root element attributes by given XML decoder.
  299. func getRootElement(d *xml.Decoder) []xml.Attr {
  300. tokenIdx := 0
  301. for {
  302. token, _ := d.Token()
  303. if token == nil {
  304. break
  305. }
  306. switch startElement := token.(type) {
  307. case xml.StartElement:
  308. tokenIdx++
  309. if tokenIdx == 1 {
  310. return startElement.Attr
  311. }
  312. }
  313. }
  314. return nil
  315. }
  316. // genXMLNamespace generate serialized XML attributes with a multi namespace
  317. // by given element attributes.
  318. func genXMLNamespace(attr []xml.Attr) string {
  319. var rootElement string
  320. for _, v := range attr {
  321. if lastSpace := getXMLNamespace(v.Name.Space, attr); lastSpace != "" {
  322. if lastSpace == NameSpaceXML {
  323. lastSpace = "xml"
  324. }
  325. rootElement += fmt.Sprintf("%s:%s=\"%s\" ", lastSpace, v.Name.Local, v.Value)
  326. continue
  327. }
  328. rootElement += fmt.Sprintf("%s=\"%s\" ", v.Name.Local, v.Value)
  329. }
  330. return strings.TrimSpace(rootElement) + ">"
  331. }
  332. // getXMLNamespace extract XML namespace from specified element name and attributes.
  333. func getXMLNamespace(space string, attr []xml.Attr) string {
  334. for _, attribute := range attr {
  335. if attribute.Value == space {
  336. return attribute.Name.Local
  337. }
  338. }
  339. return space
  340. }
  341. // replaceNameSpaceBytes provides a function to replace the XML root element
  342. // attribute by the given component part path and XML content.
  343. func (f *File) replaceNameSpaceBytes(path string, contentMarshal []byte) []byte {
  344. var oldXmlns = []byte(`xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">`)
  345. var newXmlns = []byte(templateNamespaceIDMap)
  346. if attr, ok := f.xmlAttr[path]; ok {
  347. newXmlns = []byte(genXMLNamespace(attr))
  348. }
  349. return bytesReplace(contentMarshal, oldXmlns, newXmlns, -1)
  350. }
  351. // addNameSpaces provides a function to add a XML attribute by the given
  352. // component part path.
  353. func (f *File) addNameSpaces(path string, ns xml.Attr) {
  354. exist := false
  355. mc := false
  356. ignore := -1
  357. if attr, ok := f.xmlAttr[path]; ok {
  358. for i, attribute := range attr {
  359. if attribute.Name.Local == ns.Name.Local && attribute.Name.Space == ns.Name.Space {
  360. exist = true
  361. }
  362. if attribute.Name.Local == "Ignorable" && getXMLNamespace(attribute.Name.Space, attr) == "mc" {
  363. ignore = i
  364. }
  365. if attribute.Name.Local == "mc" && attribute.Name.Space == "xmlns" {
  366. mc = true
  367. }
  368. }
  369. }
  370. if !exist {
  371. f.xmlAttr[path] = append(f.xmlAttr[path], ns)
  372. if !mc {
  373. f.xmlAttr[path] = append(f.xmlAttr[path], SourceRelationshipCompatibility)
  374. }
  375. if ignore == -1 {
  376. f.xmlAttr[path] = append(f.xmlAttr[path], xml.Attr{
  377. Name: xml.Name{Local: "Ignorable", Space: "mc"},
  378. Value: ns.Name.Local,
  379. })
  380. return
  381. }
  382. f.setIgnorableNameSpace(path, ignore, ns)
  383. }
  384. }
  385. // setIgnorableNameSpace provides a function to set XML namespace as ignorable
  386. // by the given attribute.
  387. func (f *File) setIgnorableNameSpace(path string, index int, ns xml.Attr) {
  388. ignorableNS := []string{"c14", "cdr14", "a14", "pic14", "x14", "xdr14", "x14ac", "dsp", "mso14", "dgm14", "x15", "x12ac", "x15ac", "xr", "xr2", "xr3", "xr4", "xr5", "xr6", "xr7", "xr8", "xr9", "xr10", "xr11", "xr12", "xr13", "xr14", "xr15", "x15", "x16", "x16r2", "mo", "mx", "mv", "o", "v"}
  389. if inStrSlice(strings.Fields(f.xmlAttr[path][index].Value), ns.Name.Local) == -1 && inStrSlice(ignorableNS, ns.Name.Local) != -1 {
  390. f.xmlAttr[path][index].Value = strings.TrimSpace(fmt.Sprintf("%s %s", f.xmlAttr[path][index].Value, ns.Name.Local))
  391. }
  392. }
  393. // addSheetNameSpace add XML attribute for worksheet.
  394. func (f *File) addSheetNameSpace(sheet string, ns xml.Attr) {
  395. name := f.sheetMap[trimSheetName(sheet)]
  396. f.addNameSpaces(name, ns)
  397. }
  398. // isNumeric determines whether an expression is a valid numeric type and get
  399. // the precision for the numeric.
  400. func isNumeric(s string) (bool, int) {
  401. dot := false
  402. p := 0
  403. for i, v := range s {
  404. if v == '.' {
  405. if dot {
  406. return false, 0
  407. }
  408. dot = true
  409. } else if v < '0' || v > '9' {
  410. if i == 0 && v == '-' {
  411. continue
  412. }
  413. return false, 0
  414. } else if dot {
  415. p++
  416. }
  417. }
  418. return true, p
  419. }
  420. // Stack defined an abstract data type that serves as a collection of elements.
  421. type Stack struct {
  422. list *list.List
  423. }
  424. // NewStack create a new stack.
  425. func NewStack() *Stack {
  426. list := list.New()
  427. return &Stack{list}
  428. }
  429. // Push a value onto the top of the stack.
  430. func (stack *Stack) Push(value interface{}) {
  431. stack.list.PushBack(value)
  432. }
  433. // Pop the top item of the stack and return it.
  434. func (stack *Stack) Pop() interface{} {
  435. e := stack.list.Back()
  436. if e != nil {
  437. stack.list.Remove(e)
  438. return e.Value
  439. }
  440. return nil
  441. }
  442. // Peek view the top item on the stack.
  443. func (stack *Stack) Peek() interface{} {
  444. e := stack.list.Back()
  445. if e != nil {
  446. return e.Value
  447. }
  448. return nil
  449. }
  450. // Len return the number of items in the stack.
  451. func (stack *Stack) Len() int {
  452. return stack.list.Len()
  453. }
  454. // Empty the stack.
  455. func (stack *Stack) Empty() bool {
  456. return stack.list.Len() == 0
  457. }