1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc.  See LICENSE. */
25392f7a3SLiteSpeed Tech#ifndef LSQUIC_VARINT_H
35392f7a3SLiteSpeed Tech#define LSQUIC_VARINT_H 1
45392f7a3SLiteSpeed Tech
55392f7a3SLiteSpeed Tech#define VINT_MASK ((1 << 6) - 1)
65392f7a3SLiteSpeed Tech
75392f7a3SLiteSpeed Tech/* See [draft-ietf-quic-transport-11], section-7.1 */
85392f7a3SLiteSpeed Tech#define vint_val2bits(val) (    \
9bc520ef7SDmitri Tikhonov    ((val) >= (1 << 6)) + ((val) >= (1 << 14)) + ((val) >= (1 << 30)))
105392f7a3SLiteSpeed Tech
115392f7a3SLiteSpeed Tech#define vint_size(val) (1u << vint_val2bits(val))
125392f7a3SLiteSpeed Tech
135392f7a3SLiteSpeed Tech#define VINT_MAX_VALUE ((1ull << 62) - 1)
145392f7a3SLiteSpeed Tech
155392f7a3SLiteSpeed Tech/* Map
165392f7a3SLiteSpeed Tech *  0 -> 6
175392f7a3SLiteSpeed Tech *  1 -> 14
185392f7a3SLiteSpeed Tech *  2 -> 30
195392f7a3SLiteSpeed Tech *  3 -> 62
205392f7a3SLiteSpeed Tech */
215392f7a3SLiteSpeed Tech#define vint_bits2shift(bits) ((1 << (3 + (bits))) - 2)
225392f7a3SLiteSpeed Tech
235392f7a3SLiteSpeed Tech#define VINT_MAX_B(bits_) ((1ull << (vint_bits2shift(bits_))) - 1)
245392f7a3SLiteSpeed Tech
255392f7a3SLiteSpeed Tech/* Maximum value that can be encoded as one byte: */
265392f7a3SLiteSpeed Tech#define VINT_MAX_ONE_BYTE VINT_MAX_B(0)
275392f7a3SLiteSpeed Tech
285392f7a3SLiteSpeed Techint
295392f7a3SLiteSpeed Techlsquic_varint_read (const unsigned char *p, const unsigned char *end,
305392f7a3SLiteSpeed Tech                                                            uint64_t *valp);
315392f7a3SLiteSpeed Tech
325392f7a3SLiteSpeed Tech#define vint_read lsquic_varint_read
335392f7a3SLiteSpeed Tech
345392f7a3SLiteSpeed Techstruct varint_read_state
355392f7a3SLiteSpeed Tech{
365392f7a3SLiteSpeed Tech    uint64_t    val;
375392f7a3SLiteSpeed Tech    int         pos;
385392f7a3SLiteSpeed Tech};
395392f7a3SLiteSpeed Tech
405392f7a3SLiteSpeed Techint
415392f7a3SLiteSpeed Techlsquic_varint_read_nb (const unsigned char **p, const unsigned char *end,
425392f7a3SLiteSpeed Tech                            struct varint_read_state *);
435392f7a3SLiteSpeed Tech
445392f7a3SLiteSpeed Techstruct varint_read2_state
455392f7a3SLiteSpeed Tech{
465392f7a3SLiteSpeed Tech    uint64_t                    vr2s_one;
475392f7a3SLiteSpeed Tech    struct varint_read_state    vr2s_varint_state;
485392f7a3SLiteSpeed Tech#define vr2s_two vr2s_varint_state.val
495392f7a3SLiteSpeed Tech    enum {
505392f7a3SLiteSpeed Tech        VR2S_READ_ONE_BEGIN = 0,
515392f7a3SLiteSpeed Tech        VR2S_READ_ONE_CONTINUE,
525392f7a3SLiteSpeed Tech        VR2S_READ_TWO_BEGIN,
535392f7a3SLiteSpeed Tech        VR2S_READ_TWO_CONTINUE,
545392f7a3SLiteSpeed Tech    }                           vr2s_state;
555392f7a3SLiteSpeed Tech};
565392f7a3SLiteSpeed Tech
575392f7a3SLiteSpeed Tech/* When first called, vr2s_state must be set to 0.
585392f7a3SLiteSpeed Tech *
595392f7a3SLiteSpeed Tech * Returns 0 when both varint values have been read.  They are available
605392f7a3SLiteSpeed Tech * in vr2s_one and vr2s_two.
615392f7a3SLiteSpeed Tech *
625392f7a3SLiteSpeed Tech * Returns -1 when more input is needed.
635392f7a3SLiteSpeed Tech */
645392f7a3SLiteSpeed Techint
655392f7a3SLiteSpeed Techlsquic_varint_read_two (const unsigned char **p, const unsigned char *end,
665392f7a3SLiteSpeed Tech                            struct varint_read2_state *);
675392f7a3SLiteSpeed Tech
685392f7a3SLiteSpeed Tech#if __BYTE_ORDER == __LITTLE_ENDIAN
695392f7a3SLiteSpeed Tech#define vint_write(dst, val, bits, len) do {                                \
705392f7a3SLiteSpeed Tech    uint64_t buf_ = (val)                                                   \
715392f7a3SLiteSpeed Tech                  | (uint64_t) (bits) << vint_bits2shift(bits);             \
725392f7a3SLiteSpeed Tech    buf_ = bswap_64(buf_);                                                  \
735392f7a3SLiteSpeed Tech    memcpy(dst, (unsigned char *) &buf_ + 8 - (len), (len));                \
745392f7a3SLiteSpeed Tech} while (0)
755392f7a3SLiteSpeed Tech#else
765392f7a3SLiteSpeed Tech#define vint_write(dst, val, bits, len) do {                                \
775392f7a3SLiteSpeed Tech    uint64_t buf_ = (val)                                                   \
785392f7a3SLiteSpeed Tech                  | (uint64_t) (bits) << vint_bits2shift(bits);             \
795392f7a3SLiteSpeed Tech    memcpy(dst, (unsigned char *) &buf_ + 8 - (len), (len));                \
805392f7a3SLiteSpeed Tech} while (0)
815392f7a3SLiteSpeed Tech#endif
825392f7a3SLiteSpeed Tech
835392f7a3SLiteSpeed Tech#endif
84