barometer: update DMA's vendoring packages
[barometer.git] / src / dma / vendor / golang.org / x / text / unicode / cldr / decode.go
1 // Copyright 2013 The Go Authors. 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
5 package cldr
6
7 import (
8         "archive/zip"
9         "bytes"
10         "encoding/xml"
11         "fmt"
12         "io"
13         "io/ioutil"
14         "log"
15         "os"
16         "path/filepath"
17         "regexp"
18 )
19
20 // A Decoder loads an archive of CLDR data.
21 type Decoder struct {
22         dirFilter     []string
23         sectionFilter []string
24         loader        Loader
25         cldr          *CLDR
26         curLocale     string
27 }
28
29 // SetSectionFilter takes a list top-level LDML element names to which
30 // evaluation of LDML should be limited.  It automatically calls SetDirFilter.
31 func (d *Decoder) SetSectionFilter(filter ...string) {
32         d.sectionFilter = filter
33         // TODO: automatically set dir filter
34 }
35
36 // SetDirFilter limits the loading of LDML XML files of the specied directories.
37 // Note that sections may be split across directories differently for different CLDR versions.
38 // For more robust code, use SetSectionFilter.
39 func (d *Decoder) SetDirFilter(dir ...string) {
40         d.dirFilter = dir
41 }
42
43 // A Loader provides access to the files of a CLDR archive.
44 type Loader interface {
45         Len() int
46         Path(i int) string
47         Reader(i int) (io.ReadCloser, error)
48 }
49
50 var fileRe = regexp.MustCompile(`.*[/\\](.*)[/\\](.*)\.xml`)
51
52 // Decode loads and decodes the files represented by l.
53 func (d *Decoder) Decode(l Loader) (cldr *CLDR, err error) {
54         d.cldr = makeCLDR()
55         for i := 0; i < l.Len(); i++ {
56                 fname := l.Path(i)
57                 if m := fileRe.FindStringSubmatch(fname); m != nil {
58                         if len(d.dirFilter) > 0 && !in(d.dirFilter, m[1]) {
59                                 continue
60                         }
61                         var r io.ReadCloser
62                         if r, err = l.Reader(i); err == nil {
63                                 err = d.decode(m[1], m[2], r)
64                                 r.Close()
65                         }
66                         if err != nil {
67                                 return nil, err
68                         }
69                 }
70         }
71         d.cldr.finalize(d.sectionFilter)
72         return d.cldr, nil
73 }
74
75 func (d *Decoder) decode(dir, id string, r io.Reader) error {
76         var v interface{}
77         var l *LDML
78         cldr := d.cldr
79         switch {
80         case dir == "supplemental":
81                 v = cldr.supp
82         case dir == "transforms":
83                 return nil
84         case dir == "bcp47":
85                 v = cldr.bcp47
86         case dir == "validity":
87                 return nil
88         default:
89                 ok := false
90                 if v, ok = cldr.locale[id]; !ok {
91                         l = &LDML{}
92                         v, cldr.locale[id] = l, l
93                 }
94         }
95         x := xml.NewDecoder(r)
96         if err := x.Decode(v); err != nil {
97                 log.Printf("%s/%s: %v", dir, id, err)
98                 return err
99         }
100         if l != nil {
101                 if l.Identity == nil {
102                         return fmt.Errorf("%s/%s: missing identity element", dir, id)
103                 }
104                 // TODO: verify when CLDR bug https://unicode.org/cldr/trac/ticket/8970
105                 // is resolved.
106                 // path := strings.Split(id, "_")
107                 // if lang := l.Identity.Language.Type; lang != path[0] {
108                 //      return fmt.Errorf("%s/%s: language was %s; want %s", dir, id, lang, path[0])
109                 // }
110         }
111         return nil
112 }
113
114 type pathLoader []string
115
116 func makePathLoader(path string) (pl pathLoader, err error) {
117         err = filepath.Walk(path, func(path string, _ os.FileInfo, err error) error {
118                 pl = append(pl, path)
119                 return err
120         })
121         return pl, err
122 }
123
124 func (pl pathLoader) Len() int {
125         return len(pl)
126 }
127
128 func (pl pathLoader) Path(i int) string {
129         return pl[i]
130 }
131
132 func (pl pathLoader) Reader(i int) (io.ReadCloser, error) {
133         return os.Open(pl[i])
134 }
135
136 // DecodePath loads CLDR data from the given path.
137 func (d *Decoder) DecodePath(path string) (cldr *CLDR, err error) {
138         loader, err := makePathLoader(path)
139         if err != nil {
140                 return nil, err
141         }
142         return d.Decode(loader)
143 }
144
145 type zipLoader struct {
146         r *zip.Reader
147 }
148
149 func (zl zipLoader) Len() int {
150         return len(zl.r.File)
151 }
152
153 func (zl zipLoader) Path(i int) string {
154         return zl.r.File[i].Name
155 }
156
157 func (zl zipLoader) Reader(i int) (io.ReadCloser, error) {
158         return zl.r.File[i].Open()
159 }
160
161 // DecodeZip loads CLDR data from the zip archive for which r is the source.
162 func (d *Decoder) DecodeZip(r io.Reader) (cldr *CLDR, err error) {
163         buffer, err := ioutil.ReadAll(r)
164         if err != nil {
165                 return nil, err
166         }
167         archive, err := zip.NewReader(bytes.NewReader(buffer), int64(len(buffer)))
168         if err != nil {
169                 return nil, err
170         }
171         return d.Decode(zipLoader{archive})
172 }