OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / github.com / miekg / dns / labels.go
1 package dns
2
3 // Holds a bunch of helper functions for dealing with labels.
4
5 // SplitDomainName splits a name string into it's labels.
6 // www.miek.nl. returns []string{"www", "miek", "nl"}
7 // .www.miek.nl. returns []string{"", "www", "miek", "nl"},
8 // The root label (.) returns nil. Note that using
9 // strings.Split(s) will work in most cases, but does not handle
10 // escaped dots (\.) for instance.
11 // s must be a syntactically valid domain name, see IsDomainName.
12 func SplitDomainName(s string) (labels []string) {
13         if len(s) == 0 {
14                 return nil
15         }
16         fqdnEnd := 0 // offset of the final '.' or the length of the name
17         idx := Split(s)
18         begin := 0
19         if IsFqdn(s) {
20                 fqdnEnd = len(s) - 1
21         } else {
22                 fqdnEnd = len(s)
23         }
24
25         switch len(idx) {
26         case 0:
27                 return nil
28         case 1:
29                 // no-op
30         default:
31                 end := 0
32                 for i := 1; i < len(idx); i++ {
33                         end = idx[i]
34                         labels = append(labels, s[begin:end-1])
35                         begin = end
36                 }
37         }
38
39         return append(labels, s[begin:fqdnEnd])
40 }
41
42 // CompareDomainName compares the names s1 and s2 and
43 // returns how many labels they have in common starting from the *right*.
44 // The comparison stops at the first inequality. The names are downcased
45 // before the comparison.
46 //
47 // www.miek.nl. and miek.nl. have two labels in common: miek and nl
48 // www.miek.nl. and www.bla.nl. have one label in common: nl
49 //
50 // s1 and s2 must be syntactically valid domain names.
51 func CompareDomainName(s1, s2 string) (n int) {
52         // the first check: root label
53         if s1 == "." || s2 == "." {
54                 return 0
55         }
56
57         l1 := Split(s1)
58         l2 := Split(s2)
59
60         j1 := len(l1) - 1 // end
61         i1 := len(l1) - 2 // start
62         j2 := len(l2) - 1
63         i2 := len(l2) - 2
64         // the second check can be done here: last/only label
65         // before we fall through into the for-loop below
66         if equal(s1[l1[j1]:], s2[l2[j2]:]) {
67                 n++
68         } else {
69                 return
70         }
71         for {
72                 if i1 < 0 || i2 < 0 {
73                         break
74                 }
75                 if equal(s1[l1[i1]:l1[j1]], s2[l2[i2]:l2[j2]]) {
76                         n++
77                 } else {
78                         break
79                 }
80                 j1--
81                 i1--
82                 j2--
83                 i2--
84         }
85         return
86 }
87
88 // CountLabel counts the the number of labels in the string s.
89 // s must be a syntactically valid domain name.
90 func CountLabel(s string) (labels int) {
91         if s == "." {
92                 return
93         }
94         off := 0
95         end := false
96         for {
97                 off, end = NextLabel(s, off)
98                 labels++
99                 if end {
100                         return
101                 }
102         }
103 }
104
105 // Split splits a name s into its label indexes.
106 // www.miek.nl. returns []int{0, 4, 9}, www.miek.nl also returns []int{0, 4, 9}.
107 // The root name (.) returns nil. Also see SplitDomainName.
108 // s must be a syntactically valid domain name.
109 func Split(s string) []int {
110         if s == "." {
111                 return nil
112         }
113         idx := make([]int, 1, 3)
114         off := 0
115         end := false
116
117         for {
118                 off, end = NextLabel(s, off)
119                 if end {
120                         return idx
121                 }
122                 idx = append(idx, off)
123         }
124 }
125
126 // NextLabel returns the index of the start of the next label in the
127 // string s starting at offset.
128 // The bool end is true when the end of the string has been reached.
129 // Also see PrevLabel.
130 func NextLabel(s string, offset int) (i int, end bool) {
131         quote := false
132         for i = offset; i < len(s)-1; i++ {
133                 switch s[i] {
134                 case '\\':
135                         quote = !quote
136                 default:
137                         quote = false
138                 case '.':
139                         if quote {
140                                 quote = !quote
141                                 continue
142                         }
143                         return i + 1, false
144                 }
145         }
146         return i + 1, true
147 }
148
149 // PrevLabel returns the index of the label when starting from the right and
150 // jumping n labels to the left.
151 // The bool start is true when the start of the string has been overshot.
152 // Also see NextLabel.
153 func PrevLabel(s string, n int) (i int, start bool) {
154         if n == 0 {
155                 return len(s), false
156         }
157         lab := Split(s)
158         if lab == nil {
159                 return 0, true
160         }
161         if n > len(lab) {
162                 return 0, true
163         }
164         return lab[len(lab)-n], false
165 }
166
167 // equal compares a and b while ignoring case. It returns true when equal otherwise false.
168 func equal(a, b string) bool {
169         // might be lifted into API function.
170         la := len(a)
171         lb := len(b)
172         if la != lb {
173                 return false
174         }
175
176         for i := la - 1; i >= 0; i-- {
177                 ai := a[i]
178                 bi := b[i]
179                 if ai >= 'A' && ai <= 'Z' {
180                         ai |= 'a' - 'A'
181                 }
182                 if bi >= 'A' && bi <= 'Z' {
183                         bi |= 'a' - 'A'
184                 }
185                 if ai != bi {
186                         return false
187                 }
188         }
189         return true
190 }