1
2 /*
3 * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
4 *
5 * Use of this source code is governed by a BSD-style license
6 * that can be found in the LICENSE file in the root of the source
7 * tree. An additional intellectual property rights grant can be found
8 * in the file PATENTS. All contributing project authors may
9 * be found in the AUTHORS file in the root of the source tree.
10 */
11
12 #include "logging/rtc_event_log/events/rtc_event_field_encoding_parser.h"
13
14 #include "absl/strings/string_view.h"
15 #include "absl/types/optional.h"
16 #include "logging/rtc_event_log/encoder/var_int.h"
17 #include "logging/rtc_event_log/events/rtc_event_field_encoding.h"
18 #include "rtc_base/bitstream_reader.h"
19 #include "rtc_base/checks.h"
20
21 namespace {
ConvertFieldType(uint64_t value)22 absl::optional<webrtc::FieldType> ConvertFieldType(uint64_t value) {
23 switch (value) {
24 case static_cast<uint64_t>(webrtc::FieldType::kFixed8):
25 return webrtc::FieldType::kFixed8;
26 case static_cast<uint64_t>(webrtc::FieldType::kFixed32):
27 return webrtc::FieldType::kFixed32;
28 case static_cast<uint64_t>(webrtc::FieldType::kFixed64):
29 return webrtc::FieldType::kFixed64;
30 case static_cast<uint64_t>(webrtc::FieldType::kVarInt):
31 return webrtc::FieldType::kVarInt;
32 case static_cast<uint64_t>(webrtc::FieldType::kString):
33 return webrtc::FieldType::kString;
34 default:
35 return absl::nullopt;
36 }
37 }
38 } // namespace
39
40 namespace webrtc {
41
ReadLittleEndian(uint8_t bytes)42 uint64_t EventParser::ReadLittleEndian(uint8_t bytes) {
43 RTC_DCHECK_LE(bytes, sizeof(uint64_t));
44 RTC_DCHECK_GE(bytes, 1);
45
46 uint64_t value = 0;
47
48 if (bytes > pending_data_.length()) {
49 SetError();
50 return value;
51 }
52
53 const uint8_t* p = reinterpret_cast<const uint8_t*>(pending_data_.data());
54 unsigned int shift = 0;
55 uint8_t remaining = bytes;
56 while (remaining > 0) {
57 value += (static_cast<uint64_t>(*p) << shift);
58 shift += 8;
59 ++p;
60 --remaining;
61 }
62
63 pending_data_ = pending_data_.substr(bytes);
64 return value;
65 }
66
ReadVarInt()67 uint64_t EventParser::ReadVarInt() {
68 uint64_t output = 0;
69 bool success;
70 std::tie(success, pending_data_) = DecodeVarInt(pending_data_, &output);
71 if (!success) {
72 SetError();
73 }
74 return output;
75 }
76
ReadOptionalValuePositions()77 uint64_t EventParser::ReadOptionalValuePositions() {
78 RTC_DCHECK(positions_.empty());
79 size_t bits_to_read = NumEventsInBatch();
80 positions_.reserve(bits_to_read);
81 if (pending_data_.size() * 8 < bits_to_read) {
82 SetError();
83 return 0;
84 }
85
86 BitstreamReader reader(pending_data_);
87 for (size_t i = 0; i < bits_to_read; i++) {
88 positions_.push_back(reader.ReadBit());
89 }
90 if (!reader.Ok()) {
91 SetError();
92 return 0;
93 }
94
95 size_t num_existing_values =
96 std::count(positions_.begin(), positions_.end(), 1);
97 pending_data_ = pending_data_.substr((bits_to_read + 7) / 8);
98 return num_existing_values;
99 }
100
ReadSingleValue(FieldType field_type)101 uint64_t EventParser::ReadSingleValue(FieldType field_type) {
102 switch (field_type) {
103 case FieldType::kFixed8:
104 return ReadLittleEndian(/*bytes=*/1);
105 case FieldType::kFixed32:
106 return ReadLittleEndian(/*bytes=*/4);
107 case FieldType::kFixed64:
108 return ReadLittleEndian(/*bytes=*/8);
109 case FieldType::kVarInt:
110 return ReadVarInt();
111 case FieldType::kString:
112 RTC_DCHECK_NOTREACHED();
113 SetError();
114 return 0;
115 }
116 RTC_DCHECK_NOTREACHED();
117 SetError();
118 return 0;
119 }
120
ReadDeltasAndPopulateValues(FixedLengthEncodingParametersV3 params,uint64_t num_deltas,uint64_t base)121 void EventParser::ReadDeltasAndPopulateValues(
122 FixedLengthEncodingParametersV3 params,
123 uint64_t num_deltas,
124 uint64_t base) {
125 RTC_DCHECK(values_.empty());
126 values_.reserve(num_deltas + 1);
127 values_.push_back(base);
128
129 if (pending_data_.size() * 8 < num_deltas * params.delta_bit_width()) {
130 SetError();
131 return;
132 }
133
134 BitstreamReader reader(pending_data_);
135 const uint64_t top_bit = static_cast<uint64_t>(1)
136 << (params.delta_bit_width() - 1);
137
138 uint64_t value = base;
139 for (uint64_t i = 0; i < num_deltas; ++i) {
140 uint64_t delta = reader.ReadBits(params.delta_bit_width());
141 RTC_DCHECK_LE(value, webrtc_event_logging::MaxUnsignedValueOfBitWidth(
142 params.value_bit_width()));
143 RTC_DCHECK_LE(delta, webrtc_event_logging::MaxUnsignedValueOfBitWidth(
144 params.delta_bit_width()));
145 bool negative_delta = params.signed_deltas() && ((delta & top_bit) != 0);
146 if (negative_delta) {
147 uint64_t delta_abs = (~delta & params.delta_mask()) + 1;
148 value = (value - delta_abs) & params.value_mask();
149 } else {
150 value = (value + delta) & params.value_mask();
151 }
152 values_.push_back(value);
153 }
154
155 if (!reader.Ok()) {
156 SetError();
157 return;
158 }
159
160 pending_data_ =
161 pending_data_.substr((num_deltas * params.delta_bit_width() + 7) / 8);
162 }
163
Initialize(absl::string_view s,bool batched)164 RtcEventLogParseStatus EventParser::Initialize(absl::string_view s,
165 bool batched) {
166 pending_data_ = s;
167 num_events_ = 1;
168
169 if (batched) {
170 num_events_ = ReadVarInt();
171 if (!Ok()) {
172 return RtcEventLogParseStatus::Error(
173 "Failed to read number of events in batch.", __FILE__, __LINE__);
174 }
175 }
176 return RtcEventLogParseStatus::Success();
177 }
178
ParseNumericFieldInternal(uint64_t value_bit_width,FieldType field_type)179 RtcEventLogParseStatus EventParser::ParseNumericFieldInternal(
180 uint64_t value_bit_width,
181 FieldType field_type) {
182 RTC_DCHECK(values_.empty());
183 RTC_DCHECK(positions_.empty());
184
185 if (num_events_ == 1) {
186 // Just a single value in the batch.
187 uint64_t base = ReadSingleValue(field_type);
188 if (!Ok()) {
189 return RtcEventLogParseStatus::Error("Failed to read value", __FILE__,
190 __LINE__);
191 }
192 positions_.push_back(true);
193 values_.push_back(base);
194 } else {
195 // Delta compressed batch.
196 // Read delta header.
197 uint64_t header_value = ReadVarInt();
198 if (!Ok())
199 return RtcEventLogParseStatus::Error("Failed to read delta header",
200 __FILE__, __LINE__);
201 // NB: value_bit_width may be incorrect for the field, if this isn't the
202 // field we are looking for.
203 absl::optional<FixedLengthEncodingParametersV3> delta_header =
204 FixedLengthEncodingParametersV3::ParseDeltaHeader(header_value,
205 value_bit_width);
206 if (!delta_header.has_value()) {
207 return RtcEventLogParseStatus::Error("Failed to parse delta header",
208 __FILE__, __LINE__);
209 }
210
211 uint64_t num_existing_deltas = NumEventsInBatch() - 1;
212 if (delta_header->values_optional()) {
213 size_t num_nonempty_values = ReadOptionalValuePositions();
214 if (!Ok()) {
215 return RtcEventLogParseStatus::Error(
216 "Failed to read positions of optional values", __FILE__, __LINE__);
217 }
218 if (num_nonempty_values < 1 || NumEventsInBatch() < num_nonempty_values) {
219 return RtcEventLogParseStatus::Error(
220 "Expected at least one non_empty value", __FILE__, __LINE__);
221 }
222 num_existing_deltas = num_nonempty_values - 1;
223 } else {
224 // All elements in the batch have values.
225 positions_.assign(NumEventsInBatch(), 1u);
226 }
227
228 // Read base.
229 uint64_t base = ReadSingleValue(field_type);
230 if (!Ok()) {
231 return RtcEventLogParseStatus::Error("Failed to read value", __FILE__,
232 __LINE__);
233 }
234
235 if (delta_header->values_equal()) {
236 // Duplicate the base value num_existing_deltas times.
237 values_.assign(num_existing_deltas + 1, base);
238 } else {
239 // Read deltas; ceil(num_existing_deltas*delta_width/8) bits
240 ReadDeltasAndPopulateValues(delta_header.value(), num_existing_deltas,
241 base);
242 if (!Ok()) {
243 return RtcEventLogParseStatus::Error("Failed to decode deltas",
244 __FILE__, __LINE__);
245 }
246 }
247 }
248 return RtcEventLogParseStatus::Success();
249 }
250
ParseStringFieldInternal()251 RtcEventLogParseStatus EventParser::ParseStringFieldInternal() {
252 RTC_DCHECK(strings_.empty());
253 if (num_events_ > 1) {
254 // String encoding params reserved for future use.
255 uint64_t encoding_params = ReadVarInt();
256 if (!Ok()) {
257 return RtcEventLogParseStatus::Error("Failed to read string encoding",
258 __FILE__, __LINE__);
259 }
260 if (encoding_params != 0) {
261 return RtcEventLogParseStatus::Error(
262 "Unrecognized string encoding parameters", __FILE__, __LINE__);
263 }
264 }
265 strings_.reserve(num_events_);
266 for (uint64_t i = 0; i < num_events_; ++i) {
267 // Just a single value in the batch.
268 uint64_t size = ReadVarInt();
269 if (!Ok()) {
270 return RtcEventLogParseStatus::Error("Failed to read string size",
271 __FILE__, __LINE__);
272 }
273 if (size > pending_data_.size()) {
274 return RtcEventLogParseStatus::Error("String size exceeds remaining data",
275 __FILE__, __LINE__);
276 }
277 strings_.push_back(pending_data_.substr(0, size));
278 pending_data_ = pending_data_.substr(size);
279 }
280 return RtcEventLogParseStatus::Success();
281 }
282
ParseField(const FieldParameters & params)283 RtcEventLogParseStatus EventParser::ParseField(const FieldParameters& params) {
284 // Verify that the event parses fields in increasing order.
285 if (params.field_id == FieldParameters::kTimestampField) {
286 RTC_DCHECK_EQ(last_field_id_, FieldParameters::kTimestampField);
287 } else {
288 RTC_DCHECK_GT(params.field_id, last_field_id_);
289 }
290 last_field_id_ = params.field_id;
291
292 // Initialization for positional fields that don't encode field ID and type.
293 uint64_t field_id = params.field_id;
294 FieldType field_type = params.field_type;
295
296 // Fields are encoded in increasing field_id order.
297 // Skip unknown fields with field_id < params.field_id until we either
298 // find params.field_id or a field with higher id, in which case we know that
299 // params.field_id doesn't exist.
300 while (!pending_data_.empty()) {
301 absl::string_view field_start = pending_data_;
302 ClearTemporaries();
303
304 // Read tag for non-positional fields.
305 if (params.field_id != FieldParameters::kTimestampField) {
306 uint64_t field_tag = ReadVarInt();
307 if (!Ok())
308 return RtcEventLogParseStatus::Error("Failed to read field tag",
309 __FILE__, __LINE__);
310 // Split tag into field ID and field type.
311 field_id = field_tag >> 3;
312 absl::optional<FieldType> conversion = ConvertFieldType(field_tag & 7u);
313 if (!conversion.has_value())
314 return RtcEventLogParseStatus::Error("Failed to parse field type",
315 __FILE__, __LINE__);
316 field_type = conversion.value();
317 }
318
319 if (field_id > params.field_id) {
320 // We've passed all fields with ids less than or equal to what we are
321 // looking for. Reset pending_data_ to first field with id higher than
322 // params.field_id, since we didn't find the field we were looking for.
323 pending_data_ = field_start;
324 return RtcEventLogParseStatus::Success();
325 }
326
327 if (field_type == FieldType::kString) {
328 auto status = ParseStringFieldInternal();
329 if (!status.ok()) {
330 return status;
331 }
332 } else {
333 auto status = ParseNumericFieldInternal(params.value_width, field_type);
334 if (!status.ok()) {
335 return status;
336 }
337 }
338
339 if (field_id == params.field_id) {
340 // The field we're looking for has been found and values populated.
341 return RtcEventLogParseStatus::Success();
342 }
343 }
344
345 // Field not found because the event ended.
346 ClearTemporaries();
347 return RtcEventLogParseStatus::Success();
348 }
349
350 RtcEventLogParseStatusOr<rtc::ArrayView<absl::string_view>>
ParseStringField(const FieldParameters & params,bool required_field)351 EventParser::ParseStringField(const FieldParameters& params,
352 bool required_field) {
353 using StatusOr = RtcEventLogParseStatusOr<rtc::ArrayView<absl::string_view>>;
354 RTC_DCHECK_EQ(params.field_type, FieldType::kString);
355 auto status = ParseField(params);
356 if (!status.ok())
357 return StatusOr(status);
358 rtc::ArrayView<absl::string_view> strings = GetStrings();
359 if (required_field && strings.size() != NumEventsInBatch()) {
360 return StatusOr::Error("Required string field not found", __FILE__,
361 __LINE__);
362 }
363 return StatusOr(strings);
364 }
365
366 RtcEventLogParseStatusOr<rtc::ArrayView<uint64_t>>
ParseNumericField(const FieldParameters & params,bool required_field)367 EventParser::ParseNumericField(const FieldParameters& params,
368 bool required_field) {
369 using StatusOr = RtcEventLogParseStatusOr<rtc::ArrayView<uint64_t>>;
370 RTC_DCHECK_NE(params.field_type, FieldType::kString);
371 auto status = ParseField(params);
372 if (!status.ok())
373 return StatusOr(status);
374 rtc::ArrayView<uint64_t> values = GetValues();
375 if (required_field && values.size() != NumEventsInBatch()) {
376 return StatusOr::Error("Required numerical field not found", __FILE__,
377 __LINE__);
378 }
379 return StatusOr(values);
380 }
381
382 RtcEventLogParseStatusOr<EventParser::ValueAndPostionView>
ParseOptionalNumericField(const FieldParameters & params,bool required_field)383 EventParser::ParseOptionalNumericField(const FieldParameters& params,
384 bool required_field) {
385 using StatusOr = RtcEventLogParseStatusOr<ValueAndPostionView>;
386 RTC_DCHECK_NE(params.field_type, FieldType::kString);
387 auto status = ParseField(params);
388 if (!status.ok())
389 return StatusOr(status);
390 ValueAndPostionView view{GetValues(), GetPositions()};
391 if (required_field && view.positions.size() != NumEventsInBatch()) {
392 return StatusOr::Error("Required numerical field not found", __FILE__,
393 __LINE__);
394 }
395 return StatusOr(view);
396 }
397
398 } // namespace webrtc
399