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