fs.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. // Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package gettext
  5. import (
  6. "archive/zip"
  7. "bytes"
  8. "fmt"
  9. "io/ioutil"
  10. "log"
  11. "os"
  12. "strings"
  13. )
  14. type fileSystem struct {
  15. FsName string
  16. FsRoot string
  17. FsZipData []byte
  18. LocaleMap map[string]bool
  19. }
  20. func newFileSystem(path string, data []byte) *fileSystem {
  21. fs := &fileSystem{
  22. FsName: path,
  23. FsZipData: data,
  24. }
  25. if err := fs.init(); err != nil {
  26. log.Printf("gettext-go: invalid domain, err = %v", err)
  27. }
  28. return fs
  29. }
  30. func (p *fileSystem) init() error {
  31. zipName := func(name string) string {
  32. if x := strings.LastIndexAny(name, `\/`); x != -1 {
  33. name = name[x+1:]
  34. }
  35. name = strings.TrimSuffix(name, ".zip")
  36. return name
  37. }
  38. // zip data
  39. if len(p.FsZipData) != 0 {
  40. p.FsRoot = zipName(p.FsName)
  41. p.LocaleMap = p.lsZip(p.FsZipData)
  42. return nil
  43. }
  44. // local dir or zip file
  45. fi, err := os.Stat(p.FsName)
  46. if err != nil {
  47. return err
  48. }
  49. // local dir
  50. if fi.IsDir() {
  51. p.FsRoot = p.FsName
  52. p.LocaleMap = p.lsDir(p.FsName)
  53. return nil
  54. }
  55. // local zip file
  56. p.FsZipData, err = ioutil.ReadFile(p.FsName)
  57. if err != nil {
  58. return err
  59. }
  60. p.FsRoot = zipName(p.FsName)
  61. p.LocaleMap = p.lsZip(p.FsZipData)
  62. return nil
  63. }
  64. func (p *fileSystem) LoadMessagesFile(domain, local, ext string) ([]byte, error) {
  65. if len(p.FsZipData) == 0 {
  66. trName := p.makeMessagesFileName(domain, local, ext)
  67. rcData, err := ioutil.ReadFile(trName)
  68. if err != nil {
  69. return nil, err
  70. }
  71. return rcData, nil
  72. } else {
  73. r, err := zip.NewReader(bytes.NewReader(p.FsZipData), int64(len(p.FsZipData)))
  74. if err != nil {
  75. return nil, err
  76. }
  77. trName := p.makeMessagesFileName(domain, local, ext)
  78. for _, f := range r.File {
  79. if f.Name != trName {
  80. continue
  81. }
  82. rc, err := f.Open()
  83. if err != nil {
  84. return nil, err
  85. }
  86. rcData, err := ioutil.ReadAll(rc)
  87. rc.Close()
  88. return rcData, err
  89. }
  90. return nil, fmt.Errorf("not found")
  91. }
  92. }
  93. func (p *fileSystem) LoadResourceFile(domain, local, name string) ([]byte, error) {
  94. if len(p.FsZipData) == 0 {
  95. rcName := p.makeResourceFileName(domain, local, name)
  96. rcData, err := ioutil.ReadFile(rcName)
  97. if err != nil {
  98. return nil, err
  99. }
  100. return rcData, nil
  101. } else {
  102. r, err := zip.NewReader(bytes.NewReader(p.FsZipData), int64(len(p.FsZipData)))
  103. if err != nil {
  104. return nil, err
  105. }
  106. rcName := p.makeResourceFileName(domain, local, name)
  107. for _, f := range r.File {
  108. if f.Name != rcName {
  109. continue
  110. }
  111. rc, err := f.Open()
  112. if err != nil {
  113. return nil, err
  114. }
  115. rcData, err := ioutil.ReadAll(rc)
  116. rc.Close()
  117. return rcData, err
  118. }
  119. return nil, fmt.Errorf("not found")
  120. }
  121. }
  122. func (p *fileSystem) makeMessagesFileName(domain, local, ext string) string {
  123. return fmt.Sprintf("%s/%s/LC_MESSAGES/%s%s", p.FsRoot, local, domain, ext)
  124. }
  125. func (p *fileSystem) makeResourceFileName(domain, local, name string) string {
  126. return fmt.Sprintf("%s/%s/LC_RESOURCE/%s/%s", p.FsRoot, local, domain, name)
  127. }
  128. func (p *fileSystem) lsZip(data []byte) map[string]bool {
  129. r, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
  130. if err != nil {
  131. return nil
  132. }
  133. ssMap := make(map[string]bool)
  134. for _, f := range r.File {
  135. if x := strings.Index(f.Name, "LC_MESSAGES"); x != -1 {
  136. s := strings.TrimRight(f.Name[:x], `\/`)
  137. if x = strings.LastIndexAny(s, `\/`); x != -1 {
  138. s = s[x+1:]
  139. }
  140. if s != "" {
  141. ssMap[s] = true
  142. }
  143. continue
  144. }
  145. if x := strings.Index(f.Name, "LC_RESOURCE"); x != -1 {
  146. s := strings.TrimRight(f.Name[:x], `\/`)
  147. if x = strings.LastIndexAny(s, `\/`); x != -1 {
  148. s = s[x+1:]
  149. }
  150. if s != "" {
  151. ssMap[s] = true
  152. }
  153. continue
  154. }
  155. }
  156. return ssMap
  157. }
  158. func (p *fileSystem) lsDir(path string) map[string]bool {
  159. list, err := ioutil.ReadDir(path)
  160. if err != nil {
  161. return nil
  162. }
  163. ssMap := make(map[string]bool)
  164. for _, dir := range list {
  165. if dir.IsDir() {
  166. ssMap[dir.Name()] = true
  167. }
  168. }
  169. return ssMap
  170. }