/* vim: set expandtab ts=4 sw=4: */ /* * You may redistribute this program and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef VarInt_H #define VarInt_H #include "util/Bits.h" #include "util/Gcc.h" #include // Thank you Satoshi struct VarInt_Iter { uint8_t* ptr; uint8_t* end; uint8_t* start; }; static inline void VarInt_clone(struct VarInt_Iter* out, const struct VarInt_Iter* in) { out->ptr = in->ptr; out->start = in->start; out->end = in->end; } static inline void VarInt_mk(struct VarInt_Iter* out, uint8_t* ptr, int length) { out->ptr = ptr; out->end = ptr + length; out->start = ptr; } static inline void VarInt_toStart(struct VarInt_Iter* iter) { iter->ptr = iter->start; } static inline void VarInt_toEnd(struct VarInt_Iter* iter) { iter->ptr = iter->end; } static inline int VarInt_hasMore(struct VarInt_Iter* iter) { return iter->end > iter->ptr; } static inline int VarInt_sizeOf(uint64_t val) { return (!!(val >> 32)) * 4 + (!!(val >> 16)) * 2 + (!!((val + 3) >> 8)) + 1; } static inline int VarInt_pop(struct VarInt_Iter* iter, uint64_t* _out) { uint64_t out = 0; uint8_t* bytes = iter->ptr; int len = iter->end - bytes; if (len < 9) { if (len < 5) { if (len < 3) { if (len < 1) { return -1; } if (*bytes >= 0xfd) { return -1; } } else if (*bytes >= 0xfe) { return -1; } } else if (*bytes >= 0xff) { return -1; } } switch (*bytes) { case 0xff: out |= *++bytes; out <<= 8; out |= *++bytes; out <<= 8; out |= *++bytes; out <<= 8; out |= *++bytes; out <<= 8; Gcc_FALLTHRU case 0xfe: out |= *++bytes; out <<= 8; out |= *++bytes; out <<= 8; Gcc_FALLTHRU case 0xfd: out |= *++bytes; out <<= 8; bytes++; Gcc_FALLTHRU default: out |= *bytes++; } iter->ptr = bytes; if (_out) { *_out = out; } return 0; } static inline int VarInt_push(struct VarInt_Iter* iter, uint64_t val) { uint8_t* ptr = iter->ptr; int padding = ptr - iter->start; if (padding < 9) { if (padding < 5) { if (padding < 3) { if (padding < 1) { return -1; } if (val > 0xfc) { return -1; } } else if (val > 0xffff) { return -1; } } else if (val > 0xffffffff) { return -1; } } int i = VarInt_sizeOf(val); for (int j = 0; j < i; j++) { *--ptr = val & 0xff; val >>= 8; } switch (i) { case 8: *--ptr = 0xff; break; case 4: *--ptr = 0xfe; break; case 2: *--ptr = 0xfd; break; } iter->ptr = ptr; return 0; } #endif