github.com/go-xe2/third@v1.0.3/golang.org/x/text/unicode/cldr/decode.go (about) 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.Reader 62 if r, err = l.Reader(i); err == nil { 63 err = d.decode(m[1], m[2], r) 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 // TODO: verify when CLDR bug http://unicode.org/cldr/trac/ticket/8970 104 // is resolved. 105 // path := strings.Split(id, "_") 106 // if lang := l.Identity.Language.Type; lang != path[0] { 107 // return fmt.Errorf("%s/%s: language was %s; want %s", dir, id, lang, path[0]) 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 // DecodePath loads CLDR data from the given path. 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 // DecodeZip loads CLDR data from the zip archive for which r is the source. 161 func (d *Decoder) DecodeZip(r io.Reader) (cldr *CLDR, err error) { 162 buffer, err := ioutil.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 }