Class Protobuf

java.lang.Object
org.microproxy.contentviews.Protobuf

public final class Protobuf extends Object
Decodes and encodes protobuf messages without generated code, and usually without a schema:

 ProtoMessage m = Protobuf.decode(bytes);          // fields by number, types guessed
 String yaml = m.render();                          // "1: 150  # !sint: 75\n2: hello\n"
 Map<Object, Object> plain = m.toPlain();           // {1=150, 2=hello}
 plain.put(2, "goodbye");
 byte[] changed = Protobuf.encode(plain);
 

Without a schema, varints, fixed-width values and groups are what the wire says; whether a length-delimited value is text, a nested message or bytes is guessed, as mitmproxy guesses it (see ProtoValue). With a ProtoSchema, declared fields are read as declared, with names, and the rest is guessed.

Decoding never throws anything but DecodeException for bad input, whatever the bytes: nesting is bounded (64 levels; deeper length-delimited values stay bytes), lengths are checked against the input, and nothing is allocated before it is known to fit. Encoding a decoded message gives back the same bytes, except where the input used non-minimal varints at the top level (nested messages are only recognized with minimal ones). Plain values (toPlain(org.microproxy.contentviews.ProtoMessage)) re-encode to the same bytes when each field's occurrences were together on the wire, as encoders write them.

  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static final int
    How deep messages and groups may nest before length-delimited values are left as bytes.
    static final int
    The largest field number protobuf allows, 229-1.
  • Method Summary

    Modifier and Type
    Method
    Description
    decode(byte[] data)
    Decodes a message without a schema.
    decode(byte[] data, ProtoSchema schema, String messageType)
    Decodes a message as messageType of schema; fields the type does not declare, or whose values do not match their declared type, are decoded without it.
    static byte[]
    encode(Map<?,?> fields)
    Encodes plain values, as toPlain(org.microproxy.contentviews.ProtoMessage) makes them, without a schema.
    static byte[]
    encode(Map<?,?> fields, ProtoSchema schema, String messageType)
    Encodes plain values as messageType: keys may be field names, and values are encoded as their fields are declared (enum values may be names, sint fields are zigzag-encoded, packed fields packed, map fields from maps).
    static byte[]
    Encodes a message, field by field in its order.
    static byte[]
    packVarints(List<? extends Number> values)
    Packs integers as varints, as a packed repeated integer field holds them (negative numbers take ten bytes, as for int32 and int64).
    static String
    render(byte[] data)
    Decodes a message without a schema and renders it as YAML with field numbers; see ProtoMessage.render().
    static Map<Object,Object>
    A message as plain Java values, for scripts and quick edits.
    static List<Long>
    unpackVarints(byte[] data)
    Reads bytes as packed varints, as a packed repeated integer field holds them.
    static long
    zigzagDecode(long n)
    Decodes a zigzag-encoded 64-bit value: 0, 1, 2, 3 become 0, -1, 1, -2.
    static int
    Decodes a zigzag-encoded 32-bit value.
    static long
    zigzagEncode(long n)
    Zigzag-encodes a signed 64-bit value, as sint64 fields are: 0, -1, 1, -2 become 0, 1, 2, 3.
    static int
    Zigzag-encodes a signed 32-bit value, as sint32 fields are.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

    • MAX_FIELD_NUMBER

      public static final int MAX_FIELD_NUMBER
      The largest field number protobuf allows, 229-1.
      See Also:
    • DEFAULT_MAX_DEPTH

      public static final int DEFAULT_MAX_DEPTH
      How deep messages and groups may nest before length-delimited values are left as bytes.
      See Also:
  • Method Details

    • decode

      public static ProtoMessage decode(byte[] data) throws DecodeException
      Decodes a message without a schema.
      Parameters:
      data - the serialized message
      Returns:
      the message, with every field keyed by number
      Throws:
      DecodeException - if data is not a protobuf message
    • decode

      public static ProtoMessage decode(byte[] data, ProtoSchema schema, String messageType) throws DecodeException
      Decodes a message as messageType of schema; fields the type does not declare, or whose values do not match their declared type, are decoded without it.
      Parameters:
      data - the serialized message
      schema - the schema, or null to decode without one
      messageType - the full name of the message's type, or null to decode without one
      Returns:
      the message
      Throws:
      DecodeException - if data is not a protobuf message
      IllegalArgumentException - if the schema has no type messageType
    • render

      public static String render(byte[] data) throws DecodeException
      Decodes a message without a schema and renders it as YAML with field numbers; see ProtoMessage.render().
      Parameters:
      data - the serialized message
      Returns:
      the text, or {} # empty protobuf message for no bytes
      Throws:
      DecodeException - if data is not a protobuf message
    • encode

      public static byte[] encode(ProtoMessage message)
      Encodes a message, field by field in its order.
      Parameters:
      message - the message
      Returns:
      the serialized message
    • encode

      public static byte[] encode(Map<?,?> fields)
      Encodes plain values, as toPlain(org.microproxy.contentviews.ProtoMessage) makes them, without a schema. Keys are field numbers (integers, or strings of digits). Values:
      • integers (Integer, Long, BigInteger up to 264-1) and booleans: varints; negative numbers take ten bytes, as int32 and int64 do;
      • String: UTF-8; byte[]: bytes; Map: a nested message;
      • List: a repeated field, one occurrence per element (not packed);
      • Double: a fixed64 double; Float: a fixed32 float;
      • a ProtoValue (such as ProtoValue.Fixed32 or ProtoValue.Group): as it is; null: nothing.
      Parameters:
      fields - the fields
      Returns:
      the serialized message
      Throws:
      IllegalArgumentException - if a key or value cannot be encoded
    • encode

      public static byte[] encode(Map<?,?> fields, ProtoSchema schema, String messageType)
      Encodes plain values as messageType: keys may be field names, and values are encoded as their fields are declared (enum values may be names, sint fields are zigzag-encoded, packed fields packed, map fields from maps). Undeclared fields are encoded as encode(Map) does.
      Parameters:
      fields - the fields
      schema - the schema
      messageType - the full name of the message's type
      Returns:
      the serialized message
      Throws:
      IllegalArgumentException - if the schema has no such type, or a key or value cannot be encoded
    • toPlain

      public static Map<Object,Object> toPlain(ProtoMessage message)
      A message as plain Java values, for scripts and quick edits. Keys are field numbers ( Integer), or names for declared fields; a field that occurs more than once, or is declared repeated, is a List. Values:
      • without a declaration: varints as Long (negative when the top bit is set), text as String, bytes as byte[], nested messages as Map; fixed-width values and groups stay ProtoValue.Fixed32, ProtoValue.Fixed64 and ProtoValue.Group, so that they encode back as they were;
      • with one, as declared: Long (or BigInteger for uint64 and fixed64 values above Long.MAX_VALUE), Boolean, Double for float and double, enum value names (or numbers, when unknown), String, byte[], and Maps for messages, groups and map fields.
      Parameters:
      message - the message
      Returns:
      a mutable, ordered map
    • zigzagEncode

      public static long zigzagEncode(long n)
      Zigzag-encodes a signed 64-bit value, as sint64 fields are: 0, -1, 1, -2 become 0, 1, 2, 3.
      Parameters:
      n - the signed value
      Returns:
      the encoded value
    • zigzagDecode

      public static long zigzagDecode(long n)
      Decodes a zigzag-encoded 64-bit value: 0, 1, 2, 3 become 0, -1, 1, -2.
      Parameters:
      n - the encoded value
      Returns:
      the signed value
    • zigzagEncode32

      public static int zigzagEncode32(int n)
      Zigzag-encodes a signed 32-bit value, as sint32 fields are.
      Parameters:
      n - the signed value
      Returns:
      the encoded value, as 32 unsigned bits
    • zigzagDecode32

      public static int zigzagDecode32(int n)
      Decodes a zigzag-encoded 32-bit value.
      Parameters:
      n - the encoded value
      Returns:
      the signed value
    • unpackVarints

      public static List<Long> unpackVarints(byte[] data) throws DecodeException
      Reads bytes as packed varints, as a packed repeated integer field holds them.
      Parameters:
      data - the field's bytes
      Returns:
      the values, as 64-bit varint values
      Throws:
      DecodeException - if the bytes are not a sequence of varints
    • packVarints

      public static byte[] packVarints(List<? extends Number> values)
      Packs integers as varints, as a packed repeated integer field holds them (negative numbers take ten bytes, as for int32 and int64).
      Parameters:
      values - the values
      Returns:
      the field's bytes