...
1
2
3
4
5 package cldr
6
7 import (
8 "archive/zip"
9 "bytes"
10 "encoding/xml"
11 "fmt"
12 "io"
13 "log"
14 "os"
15 "path/filepath"
16 "regexp"
17 )
18
19
20 type Decoder struct {
21 dirFilter []string
22 sectionFilter []string
23 loader Loader
24 cldr *CLDR
25 curLocale string
26 }
27
28
29
30 func (d *Decoder) SetSectionFilter(filter ...string) {
31 d.sectionFilter = filter
32
33 }
34
35
36
37
38 func (d *Decoder) SetDirFilter(dir ...string) {
39 d.dirFilter = dir
40 }
41
42
43 type Loader interface {
44 Len() int
45 Path(i int) string
46 Reader(i int) (io.ReadCloser, error)
47 }
48
49 var fileRe = regexp.MustCompile(`.*[/\\](.*)[/\\](.*)\.xml`)
50
51
52 func (d *Decoder) Decode(l Loader) (cldr *CLDR, err error) {
53 d.cldr = makeCLDR()
54 for i := 0; i < l.Len(); i++ {
55 fname := l.Path(i)
56 if m := fileRe.FindStringSubmatch(fname); m != nil {
57 if len(d.dirFilter) > 0 && !in(d.dirFilter, m[1]) {
58 continue
59 }
60 var r io.ReadCloser
61 if r, err = l.Reader(i); err == nil {
62 err = d.decode(m[1], m[2], r)
63 r.Close()
64 }
65 if err != nil {
66 return nil, err
67 }
68 }
69 }
70 d.cldr.finalize(d.sectionFilter)
71 return d.cldr, nil
72 }
73
74 func (d *Decoder) decode(dir, id string, r io.Reader) error {
75 var v interface{}
76 var l *LDML
77 cldr := d.cldr
78 switch {
79 case dir == "supplemental":
80 v = cldr.supp
81 case dir == "transforms":
82 return nil
83 case dir == "bcp47":
84 v = cldr.bcp47
85 case dir == "validity":
86 return nil
87 default:
88 ok := false
89 if v, ok = cldr.locale[id]; !ok {
90 l = &LDML{}
91 v, cldr.locale[id] = l, l
92 }
93 }
94 x := xml.NewDecoder(r)
95 if err := x.Decode(v); err != nil {
96 log.Printf("%s/%s: %v", dir, id, err)
97 return err
98 }
99 if l != nil {
100 if l.Identity == nil {
101 return fmt.Errorf("%s/%s: missing identity element", dir, id)
102 }
103
104
105
106
107
108
109 }
110 return nil
111 }
112
113 type pathLoader []string
114
115 func makePathLoader(path string) (pl pathLoader, err error) {
116 err = filepath.Walk(path, func(path string, _ os.FileInfo, err error) error {
117 pl = append(pl, path)
118 return err
119 })
120 return pl, err
121 }
122
123 func (pl pathLoader) Len() int {
124 return len(pl)
125 }
126
127 func (pl pathLoader) Path(i int) string {
128 return pl[i]
129 }
130
131 func (pl pathLoader) Reader(i int) (io.ReadCloser, error) {
132 return os.Open(pl[i])
133 }
134
135
136 func (d *Decoder) DecodePath(path string) (cldr *CLDR, err error) {
137 loader, err := makePathLoader(path)
138 if err != nil {
139 return nil, err
140 }
141 return d.Decode(loader)
142 }
143
144 type zipLoader struct {
145 r *zip.Reader
146 }
147
148 func (zl zipLoader) Len() int {
149 return len(zl.r.File)
150 }
151
152 func (zl zipLoader) Path(i int) string {
153 return zl.r.File[i].Name
154 }
155
156 func (zl zipLoader) Reader(i int) (io.ReadCloser, error) {
157 return zl.r.File[i].Open()
158 }
159
160
161 func (d *Decoder) DecodeZip(r io.Reader) (cldr *CLDR, err error) {
162 buffer, err := io.ReadAll(r)
163 if err != nil {
164 return nil, err
165 }
166 archive, err := zip.NewReader(bytes.NewReader(buffer), int64(len(buffer)))
167 if err != nil {
168 return nil, err
169 }
170 return d.Decode(zipLoader{archive})
171 }
172
View as plain text