decode

package
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 30, 2026 License: MIT Imports: 2 Imported by: 0

Documentation

Overview

Package decode implements a binary unmarshaling engine for Protocol Buffers messages. It decodes protobuf messages by consuming tags, dispatching by wire type, decoding scalar values, reading length-delimited fields, preserving unknown fields, and enforcing depth/recursion limits.

All decoding methods follow the consume pattern: they accept a byte slice b, read from the front, and return decoded values plus the number of bytes consumed. Unlike the wire-level Consume functions (which return negative error codes), all Decoder-level methods return proper Go error values.

The Decoder type is a stateless struct following the same pattern as wire.Codec, scalar.Codec, and encode.Encoder. It does not own or manage buffers; the input slice is the caller's responsibility.

The FieldHandler callback type is invoked by DecodeMessage for each field encountered during decoding. The handler receives the field number, wire type, and the raw field data sub-slice, and is responsible for dispatching to the appropriate decode method (DecodeScalarField, DecodeBytesField, etc.).

UnknownFields accumulates the raw bytes of fields not recognized by the handler, enabling wire-format fidelity during re-encoding.

DecodeMessage is the top-level loop that iterates wire data by consuming tags and dispatching to the caller-provided FieldHandler. It enforces a configurable depth limit (DefaultMaxDecodeDepth) to prevent unbounded stack growth from adversarial nested messages.

This package depends on errors and fmt from the standard library, and on the wire/, scalar/, and proto/ packages from the module.

Index

Constants

View Source
const DefaultMaxAllocationSize = wire.MaxMessageSize

DefaultMaxAllocationSize is the maximum allocation size allowed for a single length-delimited field during decoding. It matches wire.MaxMessageSize (2 GiB - 1).

View Source
const DefaultMaxDecodeDepth = 10_000

DefaultMaxDecodeDepth is the maximum allowed nesting depth for recursive message decoding, matching the maxGroupDepth constant in wire/tag.go.

Variables

View Source
var ErrDepthLimitExceeded error = &decodeError{
	msg:    "decode: depth limit exceeded",
	parent: wire.ErrGroupDepthExceeded,
}

ErrDepthLimitExceeded indicates that message nesting depth has exceeded the maximum allowed limit during decoding. Use errors.Is to match this sentinel; the wrapping chain also matches wire.ErrGroupDepthExceeded.

View Source
var ErrInvalidFieldNumber error = &decodeError{
	msg:    "decode: invalid field number",
	parent: wire.ErrInvalidFieldNumber,
}

ErrInvalidFieldNumber indicates that a decoded field number is outside the valid range (1 to 536,870,911). Use errors.Is to match this sentinel; the wrapping chain also matches wire.ErrInvalidFieldNumber.

View Source
var ErrInvalidWireType error = &decodeError{
	msg:    "decode: invalid wire type",
	parent: wire.ErrInvalidWireType,
}

ErrInvalidWireType indicates that a decoded wire type is outside the valid range (0 to 5). Use errors.Is to match this sentinel; the wrapping chain also matches wire.ErrInvalidWireType.

View Source
var ErrMessageTooLarge error = &decodeError{
	msg:    "decode: message size exceeds 2 GiB limit",
	parent: wire.ErrMessageTooLarge,
}

ErrMessageTooLarge indicates that a length-delimited field exceeds the 2 GiB maximum message size. Use errors.Is to match this sentinel; the wrapping chain also matches wire.ErrMessageTooLarge.

View Source
var ErrOverflow error = &decodeError{
	msg:    "decode: varint overflow",
	parent: wire.ErrOverflow,
}

ErrOverflow indicates that a varint value overflows a uint64. Use errors.Is to match this sentinel; the wrapping chain also matches wire.ErrOverflow.

View Source
var ErrTruncated error = &decodeError{
	msg:    "decode: unexpected end of input",
	parent: wire.ErrTruncated,
}

ErrTruncated indicates that the input ended before a complete value could be decoded. Use errors.Is to match this sentinel; the wrapping chain also matches wire.ErrTruncated.

Functions

func ValidateAllocationSize

func ValidateAllocationSize(fieldData []byte, maxAlloc int) error

ValidateAllocationSize checks that the length prefix in a length-delimited field does not exceed maxAlloc bytes or the remaining input buffer. It returns ErrMessageTooLarge when the claimed size is invalid.

Types

type Decoder

type Decoder struct{}

Decoder provides methods for consuming individual tagged fields and for decoding complete messages from wire bytes. It is a stateless struct following the wire.Codec, scalar.Codec, and encode.Encoder pattern. All decoding methods follow the consume pattern: they accept a byte slice b, read from the front, and return decoded values plus the number of bytes consumed.

func NewDecoder

func NewDecoder() *Decoder

NewDecoder returns a pointer to a new zero-value Decoder instance.

func (*Decoder) ConsumeTag

func (d *Decoder) ConsumeTag(b []byte) (fieldNumber uint32, wireType wire.WireType, n int, err error)

ConsumeTag reads the next field tag from wire data, returning the field number, wire type, bytes consumed, and any error. It delegates to wire.ConsumeTag and converts negative error codes to decode-package sentinel errors via wireError.

func (*Decoder) DecodeBytesField

func (d *Decoder) DecodeBytesField(b []byte) (data []byte, n int, err error)

DecodeBytesField reads a length-prefixed bytes payload from the front of b, returning the data as a sub-slice of the input (zero-copy), the total number of bytes consumed (varint prefix + data), and any error. It delegates to wire.ConsumeBytes and converts negative error codes to decode-package sentinel errors via wireError.

func (*Decoder) DecodeMessage

func (d *Decoder) DecodeMessage(b []byte, depth int, handler FieldHandler) error

DecodeMessage iterates wire data by consuming tags, then dispatches to the caller-provided FieldHandler to process each field. It checks depth against DefaultMaxDecodeDepth at entry and returns ErrDepthLimitExceeded if exceeded. The loop continues until all bytes in b are consumed. For each iteration, the method reads the next tag, determines the field value length via wire.ConsumeField, passes the bounded field data sub-slice to the handler, and advances past the field. On handler error, DecodeMessage short-circuits and returns the handler's error immediately.

func (*Decoder) DecodeMessageField

func (d *Decoder) DecodeMessageField(b []byte) (payload []byte, n int, err error)

DecodeMessageField reads a length-prefixed message payload from the front of b, returning the raw inner bytes as a sub-slice of the input (zero-copy), the total number of bytes consumed (varint prefix + data), and any error. The caller uses the returned payload to decode the nested message by passing it to DecodeMessage or another decoding method. It delegates to wire.ConsumeBytes and converts negative error codes to decode-package sentinel errors via wireError.

func (*Decoder) DecodeScalarField

func (d *Decoder) DecodeScalarField(kind scalar.Kind, b []byte) (v uint64, n int, err error)

DecodeScalarField reads a scalar field value (without tag) for the given kind and returns the raw uint64 value, bytes consumed, and any error. It delegates to scalar.Codec.ConsumeScalar for the actual value decoding and converts negative bytes-consumed values into the appropriate decode-package sentinel error. For zigzag kinds, the raw varint value is returned; the caller applies wire.DecodeZigZag32 or wire.DecodeZigZag64 to recover the signed value. String, bytes, message, and group kinds are not supported by this method; passing them returns an error rather than panicking.

func (*Decoder) DecodeStringField

func (d *Decoder) DecodeStringField(b []byte) (s string, n int, err error)

DecodeStringField reads a length-prefixed string payload from the front of b, returning the decoded string, the total number of bytes consumed (varint prefix + data), and any error. It delegates to wire.ConsumeString and converts negative error codes to decode-package sentinel errors via wireError.

func (*Decoder) SkipField

func (d *Decoder) SkipField(wireType wire.WireType, b []byte) (n int, err error)

SkipField skips over one field value of the given wire type without decoding, returning the number of bytes consumed and any error. The byte slice b must contain the field value only (not the tag). It delegates to wire.ConsumeField and converts negative error codes to decode-package sentinel errors via wireError.

type FieldHandler

type FieldHandler func(fieldNumber uint32, wireType wire.WireType, fieldData []byte) error

FieldHandler is a callback invoked by DecodeMessage for each field encountered during decoding. The fieldNumber and wireType are extracted from the tag, and fieldData is the sub-slice after the tag containing the field value bytes (not yet consumed). The handler is responsible for calling DecodeScalarField, DecodeBytesField, DecodeStringField, or recursing into DecodeMessage as appropriate for the field number. For unknown fields, the handler calls SkipField and optionally preserves the bytes via UnknownFields.AppendField.

type UnknownFields

type UnknownFields struct {
	// contains filtered or unexported fields
}

UnknownFields accumulates the raw bytes of fields not recognized by a message's field handler during decoding. Message types create an UnknownFields value and call AppendField for each unrecognized field number; the accumulated bytes can be re-appended during marshaling to preserve wire-format fidelity.

func (*UnknownFields) AppendField

func (u *UnknownFields) AppendField(b []byte, fieldNumber uint32, wireType wire.WireType, fieldData []byte)

AppendField appends the complete raw encoding of an unknown field (tag + value bytes) to the internal buffer. It writes the tag encoded from fieldNumber and wireType using wire.AppendTag, then appends fieldData. The b parameter is unused and retained for spec compliance.

func (*UnknownFields) Bytes

func (u *UnknownFields) Bytes() []byte

Bytes returns the accumulated unknown field bytes. It returns nil if no unknown fields have been appended.

func (*UnknownFields) Reset

func (u *UnknownFields) Reset()

Reset clears the accumulated unknown field bytes, allowing the UnknownFields value to be reused for a new decoding pass.

type UnsupportedKindError

type UnsupportedKindError struct {
	KindName string
}

UnsupportedKindError indicates that DecodeScalarField was called with a kind it does not support (string, bytes, message, or group). It carries the kind name for diagnostic context.

func (*UnsupportedKindError) Error

func (e *UnsupportedKindError) Error() string

Error returns a human-readable message describing the unsupported kind.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL