123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- /* 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 <https://www.gnu.org/licenses/>.
- */
- #ifndef VarInt_H
- #define VarInt_H
- #include "util/Bits.h"
- #include "util/Gcc.h"
- #include <stdint.h>
- // 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
|