Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020 Project CHIP Authors
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 : #include <assert.h>
18 : #include <strings.h>
19 :
20 : #include "QName.h"
21 :
22 : namespace mdns {
23 : namespace Minimal {
24 :
25 61586 : bool SerializedQNameIterator::Next()
26 : {
27 61586 : return mIsValid && Next(true);
28 : }
29 :
30 62262 : bool SerializedQNameIterator::Next(bool followIndirectPointers)
31 : {
32 62262 : if (!mIsValid)
33 : {
34 0 : return false;
35 : }
36 :
37 : while (true)
38 : {
39 72680 : assert(mValidData.Contains(mCurrentPosition));
40 :
41 72680 : const uint8_t length = *mCurrentPosition;
42 72680 : if (*mCurrentPosition == 0)
43 : {
44 : // Done with all items
45 12423 : return false;
46 : }
47 :
48 60257 : if ((length & kPtrMask) == kPtrMask)
49 : {
50 10631 : if (!followIndirectPointers)
51 : {
52 : // Stop at first indirect pointer
53 207 : return false;
54 : }
55 :
56 : // PTR contains 2 bytes
57 10424 : if (!mValidData.Contains(mCurrentPosition + 1))
58 : {
59 2 : mIsValid = false;
60 2 : return false;
61 : }
62 :
63 10422 : size_t offset = static_cast<size_t>(((*mCurrentPosition & 0x3F) << 8) | *(mCurrentPosition + 1));
64 : // Look behind has to keep going backwards to avoid potential infinite recursion.
65 : // mLookBehindMax starts out <= mValidData.Size() and only decreases;
66 : // mLookBehindMax <= mCurrentPosition - mValidData.Start() remains true throughout.
67 10422 : if (offset >= mLookBehindMax)
68 : {
69 4 : mIsValid = false;
70 4 : return false;
71 : }
72 :
73 10418 : mLookBehindMax = offset;
74 10418 : mCurrentPosition = mValidData.Start() + offset;
75 : }
76 : else
77 : {
78 : // This branch handles non-pointer data. This will be string of size [length].
79 49626 : if (length > kMaxValueSize)
80 : {
81 : // value is too large (larger than RFC limit)
82 0 : mIsValid = false;
83 0 : return false;
84 : }
85 :
86 49626 : if (!mValidData.Contains(mCurrentPosition + 1 + length))
87 : {
88 : // string outside valid data
89 7 : mIsValid = false;
90 7 : return false;
91 : }
92 :
93 49619 : memcpy(mValue, mCurrentPosition + 1, length);
94 49619 : mValue[length] = '\0';
95 49619 : mCurrentPosition = mCurrentPosition + length + 1;
96 49619 : return true;
97 : }
98 10418 : }
99 : }
100 :
101 297 : const uint8_t * SerializedQNameIterator::FindDataEnd()
102 : {
103 677 : while (Next(false))
104 : {
105 : // nothing to do, just advance
106 : }
107 :
108 297 : if (!IsValid())
109 : {
110 0 : return nullptr;
111 : }
112 :
113 : // normal end
114 297 : if (*mCurrentPosition == 0)
115 : {
116 : // mCurrentPosition MUST already be valid
117 90 : return mCurrentPosition + 1;
118 : }
119 :
120 : // ends with a dataptr
121 207 : if ((*mCurrentPosition & kPtrMask) == kPtrMask)
122 : {
123 207 : if (!mValidData.Contains(mCurrentPosition + 1))
124 : {
125 0 : return nullptr;
126 : }
127 207 : return mCurrentPosition + 2;
128 : }
129 :
130 : // invalid data
131 0 : return nullptr;
132 : }
133 :
134 28102 : bool SerializedQNameIterator::operator==(const FullQName & other) const
135 : {
136 28102 : SerializedQNameIterator self = *this; // allow iteration
137 28102 : size_t idx = 0;
138 :
139 34402 : while ((idx < other.nameCount) && self.Next())
140 : {
141 27378 : if (strcasecmp(self.Value(), other.names[idx]) != 0)
142 : {
143 21078 : return false;
144 : }
145 6300 : idx++;
146 : }
147 :
148 7024 : return ((idx == other.nameCount) && !self.Next());
149 : }
150 :
151 66 : bool SerializedQNameIterator::operator==(const SerializedQNameIterator & other) const
152 : {
153 66 : SerializedQNameIterator a = *this; // allow iteration
154 66 : SerializedQNameIterator b = other;
155 :
156 : while (true)
157 : {
158 216 : bool hasA = a.Next();
159 216 : bool hasB = b.Next();
160 :
161 216 : if (hasA ^ hasB)
162 : {
163 6 : return false; /// one is longer than the other
164 : }
165 :
166 210 : if (!a.IsValid() || !b.IsValid())
167 : {
168 0 : return false; // invalid data
169 : }
170 :
171 210 : if (!hasA || !hasB)
172 : {
173 : break;
174 : }
175 :
176 167 : if (strcasecmp(a.Value(), b.Value()) != 0)
177 : {
178 17 : return false;
179 : }
180 150 : }
181 :
182 43 : return a.IsValid() && b.IsValid();
183 : }
184 :
185 6687 : bool FullQName::operator==(const FullQName & other) const
186 : {
187 6687 : if (nameCount != other.nameCount)
188 : {
189 5181 : return false;
190 : }
191 4770 : for (size_t i = 0; i < nameCount; i++)
192 : {
193 3815 : if (strcasecmp(names[i], other.names[i]) != 0)
194 : {
195 551 : return false;
196 : }
197 : }
198 955 : return true;
199 : }
200 :
201 : } // namespace Minimal
202 : } // namespace mdns
|