decodeTag function
Decodes a protobuf field tag from buffer starting at offset.
Returns a map with three entries:
'fieldNumber': the field number extracted from the tag.'wireType': the wire type (lowest 3 bits of the tag value).'bytesRead': the number of bytes consumed (the varint length).
The varint decoding is inlined here to avoid cross-file imports.
Throws a FormatException if the varint exceeds 10 bytes or the buffer ends before the varint is complete.
Implementation
Map<String, int> decodeTag(List<int> buffer, int offset) {
// Inline varint decoding.
int result = 0;
int shift = 0;
int bytesRead = 0;
while (true) {
if (offset + bytesRead >= buffer.length) {
throw FormatException(
'Unexpected end of buffer while decoding tag varint at offset $offset',
);
}
int byte = buffer[offset + bytesRead];
bytesRead++;
result = result | ((byte & 0x7F) << shift);
shift += 7;
if ((byte & 0x80) == 0) {
// Reject a non-minimal (overlong) tag: a multi-byte varint whose final
// byte is 0x00 carries no bits and is redundant. A minimal encoding never
// ends in a zero continuation (the sole exception, value 0, is one byte).
if (bytesRead > 1 && byte == 0) {
throw FormatException('Overlong (non-minimal) tag at offset $offset');
}
break;
}
if (bytesRead >= 10) {
throw FormatException(
'Tag varint exceeds maximum length of 10 bytes at offset $offset',
);
}
}
int wireType = result & 0x07;
int fieldNumber = result >>> 3;
// Reject structurally illegal tags so malformed input is a parse error rather
// than silently-skipped unknown fields: field 0 is never valid, and field
// numbers must fit in 29 bits (max 2^29 - 1 = 536870911).
if (fieldNumber == 0) {
throw FormatException('Illegal field number 0 in tag at offset $offset');
}
if (fieldNumber > 536870911) {
throw FormatException(
'Field number $fieldNumber exceeds the maximum 2^29-1 at offset $offset',
);
}
return {
'fieldNumber': fieldNumber,
'wireType': wireType,
'bytesRead': bytesRead,
};
}