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 "RecordWriter.h" 18 : 19 : namespace mdns { 20 : namespace Minimal { 21 : 22 22197 : SerializedQNameIterator RecordWriter::PreviousName(size_t index) const 23 : { 24 22197 : if (index >= kMaxCachedReferences) 25 : { 26 0 : return SerializedQNameIterator(); 27 : } 28 : 29 22197 : uint16_t offset = mPreviousQNames[index]; 30 22197 : if (offset == kInvalidOffset) 31 : { 32 15761 : return SerializedQNameIterator(); 33 : } 34 : 35 6436 : return SerializedQNameIterator(BytesRange(mOutput->Buffer(), mOutput->Buffer() + mOutput->WritePos()), 36 12872 : mOutput->Buffer() + offset); 37 : } 38 : 39 1751 : RecordWriter & RecordWriter::WriteQName(const FullQName & qname) 40 : { 41 1751 : size_t qNameWriteStart = mOutput->WritePos(); 42 1751 : bool isFullyCompressed = true; 43 : 44 3037 : for (uint16_t i = 0; i < qname.nameCount; i++) 45 : { 46 : 47 : // find out if the record part remaining already is located somewhere 48 2821 : FullQName remaining; 49 2821 : remaining.names = qname.names + i; 50 2821 : remaining.nameCount = qname.nameCount - i; 51 : 52 : // Try to find a valid offset 53 2821 : chip::Optional<uint16_t> offset = FindPreviousName(remaining); 54 : 55 2821 : if (offset.HasValue()) 56 : { 57 : // Pointer to offset: set the highest 2 bits 58 1535 : mOutput->Put16(offset.Value() | 0xC000); 59 : 60 1535 : if (mOutput->Fit() && !isFullyCompressed) 61 : { 62 590 : RememberWrittenQnameOffset(qNameWriteStart); 63 : } 64 1535 : return *this; 65 : } 66 : 67 1286 : mOutput->Put8(static_cast<uint8_t>(strlen(qname.names[i]))); 68 1286 : mOutput->Put(qname.names[i]); 69 1286 : isFullyCompressed = false; 70 2821 : } 71 216 : mOutput->Put8(0); // end of qnames 72 : 73 216 : if (mOutput->Fit()) 74 : { 75 206 : RememberWrittenQnameOffset(qNameWriteStart); 76 : } 77 216 : return *this; 78 : } 79 : 80 143 : RecordWriter & RecordWriter::WriteQName(const SerializedQNameIterator & qname) 81 : { 82 143 : size_t qNameWriteStart = mOutput->WritePos(); 83 143 : bool isFullyCompressed = true; 84 : 85 143 : SerializedQNameIterator copy = qname; 86 : while (true) 87 : { 88 1016 : chip::Optional<uint16_t> offset = FindPreviousName(copy); 89 : 90 1016 : if (offset.HasValue()) 91 : { 92 : // Pointer to offset: set the highest 2 bits 93 : // We guarantee that offsets saved are <= kMaxReuseOffset 94 0 : mOutput->Put16(offset.Value() | 0xC000); 95 : 96 0 : if (mOutput->Fit() && !isFullyCompressed) 97 : { 98 0 : RememberWrittenQnameOffset(qNameWriteStart); 99 : } 100 0 : return *this; 101 : } 102 : 103 1016 : if (!copy.Next()) 104 : { 105 143 : break; 106 : } 107 : 108 873 : if (!copy.IsValid()) 109 : { 110 0 : break; 111 : } 112 : 113 873 : mOutput->Put8(static_cast<uint8_t>(strlen(copy.Value()))); 114 873 : mOutput->Put(copy.Value()); 115 873 : isFullyCompressed = false; 116 1889 : } 117 143 : mOutput->Put8(0); // end of qnames 118 : 119 143 : if (mOutput->Fit()) 120 : { 121 118 : RememberWrittenQnameOffset(qNameWriteStart); 122 : } 123 143 : return *this; 124 : } 125 : 126 914 : void RecordWriter::RememberWrittenQnameOffset(size_t offset) 127 : { 128 914 : if (offset > kMaxReuseOffset) 129 : { 130 : // cannot represent this offset properly 131 0 : return; 132 : } 133 : 134 3201 : for (unsigned short & previousName : mPreviousQNames) 135 : { 136 3139 : if (previousName == kInvalidOffset) 137 : { 138 852 : previousName = static_cast<unsigned short>(offset); 139 852 : return; 140 : } 141 : } 142 : } 143 : 144 : } // namespace Minimal 145 : } // namespace mdns