| /* |
| * |
| * Copyright (c) 2020 Project CHIP Authors |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #include <assert.h> |
| #include <strings.h> |
| |
| #include "QName.h" |
| |
| namespace mdns { |
| namespace Minimal { |
| |
| bool SerializedQNameIterator::Next() |
| { |
| return mIsValid && Next(true); |
| } |
| |
| bool SerializedQNameIterator::Next(bool followIndirectPointers) |
| { |
| if (!mIsValid) |
| { |
| return false; |
| } |
| |
| while (true) |
| { |
| assert(mValidData.Contains(mCurrentPosition)); |
| |
| const uint8_t length = *mCurrentPosition; |
| if (*mCurrentPosition == 0) |
| { |
| // Done with all items |
| return false; |
| } |
| |
| if ((length & kPtrMask) == kPtrMask) |
| { |
| if (!followIndirectPointers) |
| { |
| // Stop at first indirect pointer |
| return false; |
| } |
| |
| // PTR contains 2 bytes |
| if (!mValidData.Contains(mCurrentPosition + 1)) |
| { |
| mIsValid = false; |
| return false; |
| } |
| |
| size_t offset = ((*mCurrentPosition & 0x3F) << 8) | *(mCurrentPosition + 1); |
| if (offset > mLookBehindMax) |
| { |
| // Potential infinite recursion. |
| mIsValid = false; |
| return false; |
| } |
| if (offset > mValidData.Size()) |
| { |
| // offset too large |
| mIsValid = false; |
| return false; |
| } |
| |
| // Look behind has to keep going backwards, otherwise we may |
| // get into an infinite list |
| if (offset >= static_cast<size_t>(mCurrentPosition - mValidData.Start())) |
| { |
| mIsValid = false; |
| return false; |
| } |
| |
| mLookBehindMax = offset; |
| mCurrentPosition = mValidData.Start() + offset; |
| } |
| else |
| { |
| // This branch handles non-pointer data. This will be string of size [length]. |
| if (length > kMaxValueSize) |
| { |
| // value is too large (larger than RFC limit) |
| mIsValid = false; |
| return false; |
| } |
| |
| if (!mValidData.Contains(mCurrentPosition + 1 + length)) |
| { |
| // string outside valid data |
| mIsValid = false; |
| return false; |
| } |
| |
| memcpy(mValue, mCurrentPosition + 1, length); |
| mValue[length] = '\0'; |
| mCurrentPosition = mCurrentPosition + length + 1; |
| return true; |
| } |
| } |
| } |
| |
| const uint8_t * SerializedQNameIterator::FindDataEnd() |
| { |
| while (Next(false)) |
| { |
| // nothing to do, just advance |
| } |
| |
| if (!IsValid()) |
| { |
| return nullptr; |
| } |
| |
| // normal end |
| if (*mCurrentPosition == 0) |
| { |
| // mCurrentPosition MUST already be valid |
| return mCurrentPosition + 1; |
| } |
| |
| // ends with a dataptr |
| if ((*mCurrentPosition & kPtrMask) == kPtrMask) |
| { |
| if (!mValidData.Contains(mCurrentPosition + 1)) |
| { |
| return nullptr; |
| } |
| return mCurrentPosition + 2; |
| } |
| |
| // invalid data |
| return nullptr; |
| } |
| |
| bool SerializedQNameIterator::operator==(const FullQName & other) const |
| { |
| SerializedQNameIterator self = *this; // allow iteration |
| size_t idx = 0; |
| |
| while ((idx < other.nameCount) && self.Next()) |
| { |
| if (strcasecmp(self.Value(), other.names[idx]) != 0) |
| { |
| return false; |
| } |
| idx++; |
| } |
| |
| return ((idx == other.nameCount) && !self.Next()); |
| } |
| |
| bool SerializedQNameIterator::operator==(const SerializedQNameIterator & other) const |
| { |
| SerializedQNameIterator a = *this; // allow iteration |
| SerializedQNameIterator b = other; |
| |
| while (true) |
| { |
| bool hasA = a.Next(); |
| bool hasB = b.Next(); |
| |
| if (hasA ^ hasB) |
| { |
| return false; /// one is longer than the other |
| } |
| |
| if (!a.IsValid() || !b.IsValid()) |
| { |
| return false; // invalid data |
| } |
| |
| if (!hasA || !hasB) |
| { |
| break; |
| } |
| |
| if (strcasecmp(a.Value(), b.Value()) != 0) |
| { |
| return false; |
| } |
| } |
| |
| return a.IsValid() && b.IsValid(); |
| } |
| |
| bool FullQName::operator==(const FullQName & other) const |
| { |
| if (nameCount != other.nameCount) |
| { |
| return false; |
| } |
| for (size_t i = 0; i < nameCount; i++) |
| { |
| if (strcasecmp(names[i], other.names[i]) != 0) |
| { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| } // namespace Minimal |
| } // namespace mdns |