blob: c03bb32990506fb89546f4116306458538e464bf [file] [log] [blame]
/*
*
* 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 "RecordWriter.h"
namespace mdns {
namespace Minimal {
SerializedQNameIterator RecordWriter::PreviousName(size_t index) const
{
if (index >= kMaxCachedReferences)
{
return SerializedQNameIterator();
}
uint16_t offset = mPreviousQNames[index];
if (offset == kInvalidOffset)
{
return SerializedQNameIterator();
}
return SerializedQNameIterator(BytesRange(mOutput->Buffer(), mOutput->Buffer() + mOutput->WritePos()),
mOutput->Buffer() + offset);
}
RecordWriter & RecordWriter::WriteQName(const FullQName & qname)
{
size_t qNameWriteStart = mOutput->WritePos();
bool isFullyCompressed = true;
for (uint16_t i = 0; i < qname.nameCount; i++)
{
// find out if the record part remaining already is located somewhere
FullQName remaining;
remaining.names = qname.names + i;
remaining.nameCount = qname.nameCount - i;
// Try to find a valid offset
chip::Optional<uint16_t> offset = FindPreviousName(remaining);
if (offset.HasValue())
{
// Pointer to offset: set the highest 2 bits
mOutput->Put16(offset.Value() | 0xC000);
if (mOutput->Fit() && !isFullyCompressed)
{
RememberWrittenQnameOffset(qNameWriteStart);
}
return *this;
}
mOutput->Put8(static_cast<uint8_t>(strlen(qname.names[i])));
mOutput->Put(qname.names[i]);
isFullyCompressed = false;
}
mOutput->Put8(0); // end of qnames
if (mOutput->Fit())
{
RememberWrittenQnameOffset(qNameWriteStart);
}
return *this;
}
RecordWriter & RecordWriter::WriteQName(const SerializedQNameIterator & qname)
{
size_t qNameWriteStart = mOutput->WritePos();
bool isFullyCompressed = true;
SerializedQNameIterator copy = qname;
while (true)
{
chip::Optional<uint16_t> offset = FindPreviousName(copy);
if (offset.HasValue())
{
// Pointer to offset: set the highest 2 bits
// We guarantee that offsets saved are <= kMaxReuseOffset
mOutput->Put16(offset.Value() | 0xC000);
if (mOutput->Fit() && !isFullyCompressed)
{
RememberWrittenQnameOffset(qNameWriteStart);
}
return *this;
}
if (!copy.Next())
{
break;
}
if (!copy.IsValid())
{
break;
}
mOutput->Put8(static_cast<uint8_t>(strlen(copy.Value())));
mOutput->Put(copy.Value());
isFullyCompressed = false;
}
mOutput->Put8(0); // end of qnames
if (mOutput->Fit())
{
RememberWrittenQnameOffset(qNameWriteStart);
}
return *this;
}
void RecordWriter::RememberWrittenQnameOffset(size_t offset)
{
if (offset > kMaxReuseOffset)
{
// cannot represent this offset properly
return;
}
for (unsigned short & previousName : mPreviousQNames)
{
if (previousName == kInvalidOffset)
{
previousName = offset;
return;
}
}
}
} // namespace Minimal
} // namespace mdns