File indexing completed on 2024-12-29 04:51:01

0001 /*
0002     SPDX-FileCopyrightText: 2023 Volker Krause <vkrause@kde.org>
0003     SPDX-License-Identifier: LGPL-2.0-or-later
0004 */
0005 
0006 #include "protobufstreamreader.h"
0007 
0008 #include <QDebug>
0009 
0010 using namespace KItinerary;
0011 
0012 ProtobufStreamReader::ProtobufStreamReader() = default;
0013 
0014 ProtobufStreamReader::ProtobufStreamReader(std::string_view data)
0015     : m_data(data)
0016 {
0017 }
0018 
0019 ProtobufStreamReader::ProtobufStreamReader(const QByteArray &data)
0020     : m_ownedData(data)
0021     , m_data(std::string_view(data.constData(), data.size()))
0022 {
0023 }
0024 
0025 ProtobufStreamReader::~ProtobufStreamReader() = default;
0026 
0027 uint64_t ProtobufStreamReader::readVarint()
0028 {
0029     uint64_t result = 0;
0030     int shift = 0;
0031     while (m_cursor < m_data.size()) {
0032         const uint64_t b = m_data[m_cursor++];
0033         result |= (b & 0b0111'1111) << shift;
0034         if ((b & 0b1000'0000) == 0) {
0035             break;
0036         }
0037         shift += 7;
0038     }
0039 
0040     return result;
0041 }
0042 
0043 uint64_t ProtobufStreamReader::peekVarint()
0044 {
0045     auto prevCursor = m_cursor;
0046     const auto result = readVarint();
0047     m_cursor = prevCursor;
0048     return result;
0049 }
0050 
0051 quint64 ProtobufStreamReader::fieldNumber()
0052 {
0053     return peekVarint() >> 3;
0054 }
0055 
0056 ProtobufStreamReader::WireType ProtobufStreamReader::wireType()
0057 {
0058     return static_cast<WireType>(peekVarint() & 0b111);
0059 }
0060 
0061 quint64 ProtobufStreamReader::readVarintField()
0062 {
0063     readVarint(); // skip field number and wire type
0064     return readVarint();
0065 }
0066 
0067 std::string_view ProtobufStreamReader::readLengthDelimitedRecord()
0068 {
0069     if (wireType() != LEN) {
0070         return {};
0071     }
0072     readVarint(); // skip field number and wire type
0073     const auto len = readVarint();
0074     if (m_cursor + len <= m_data.size()) {
0075         auto data = m_data.substr(m_cursor, len);
0076         m_cursor += len;
0077         return data;
0078     }
0079     return {};
0080 }
0081 
0082 QString ProtobufStreamReader::readString()
0083 {
0084     const auto data = readLengthDelimitedRecord();
0085     return QString::fromUtf8(data.data(), data.size());
0086 }
0087 
0088 ProtobufStreamReader ProtobufStreamReader::readSubMessage()
0089 {
0090     return ProtobufStreamReader(readLengthDelimitedRecord());
0091 }
0092 
0093 bool ProtobufStreamReader::atEnd() const
0094 {
0095     return m_cursor >= m_data.size();
0096 }
0097 
0098 void ProtobufStreamReader::skip()
0099 {
0100     switch (wireType()) {
0101         case VARINT:
0102             readVarintField();
0103             break;
0104         case LEN:
0105             readLengthDelimitedRecord();
0106             break;
0107         case I64:
0108         case I32:
0109         case SGROUP:
0110         case EGROUP:
0111             qWarning() << "encountered deprecated or unsupported protobuf wire type!" << wireType();
0112             m_cursor = m_data.size();
0113             break;
0114     }
0115 }
0116 
0117 #include "moc_protobufstreamreader.cpp"