Line data Source code
1 : /** 2 : * The MIT License (MIT) 3 : * 4 : * Copyright (c) 2021 RSK Labs Ltd 5 : * 6 : * Permission is hereby granted, free of charge, to any person obtaining a copy 7 : * of this software and associated documentation files (the "Software"), to 8 : * deal in the Software without restriction, including without limitation the 9 : * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 : * sell copies of the Software, and to permit persons to whom the Software is 11 : * furnished to do so, subject to the following conditions: 12 : * 13 : * The above copyright notice and this permission notice shall be included in 14 : * all copies or substantial portions of the Software. 15 : * 16 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 : * IN THE SOFTWARE. 23 : */ 24 : 25 : #include <stdint.h> 26 : #include <string.h> 27 : 28 : #include "svarint.h" 29 : 30 : // Context pointer 31 : static svarint_ctx_t* ctx; 32 : 33 : /* 34 : * Initialize the parser. 35 : * 36 : * @arg[in] ctx the context to be used for this session 37 : */ 38 28215 : void svarint_init(svarint_ctx_t* _ctx) { 39 28215 : ctx = _ctx; 40 28215 : memset(ctx, 0, sizeof(svarint_ctx_t)); 41 28215 : ctx->state = SVARINT_ST_HEADER; 42 28215 : } 43 : 44 : /* 45 : * Tells whether the parser has not yet consumed any bytes 46 : */ 47 28365 : int8_t svarint_notstarted() { 48 28365 : return ctx->state == SVARINT_ST_HEADER; 49 : } 50 : 51 : /* 52 : * Tell whether parsing is finished, and 53 : * whether it triggered an error (and which one) 54 : * This should be checked after every call to svarint_consume 55 : */ 56 28693 : int8_t svarint_result() { 57 28693 : if (ctx->state < 0 || ctx->state == SVARINT_ST_DONE) 58 28333 : return ctx->state; 59 360 : return SVARINT_ERR_NONE; 60 : } 61 : 62 : /* 63 : * Consume a chunk of bytes. 64 : * 65 : * @arg[in] buf: buffer holding bytes to be consumed 66 : * @arg[in] len: number of bytes to consume in buffer 67 : * 68 : * @return the number of bytes actually read and processed 69 : */ 70 28472 : uint8_t svarint_consume(const uint8_t* buf, const uint8_t len) { 71 29642 : for (uint8_t i = 0; i < len; i++) { 72 29434 : switch (ctx->state) { 73 28214 : case SVARINT_ST_HEADER: 74 28214 : if (buf[i] < 0xFD) { 75 27856 : ctx->value = buf[i]; 76 27856 : ctx->state = SVARINT_ST_DONE; 77 27856 : return 1; // Read one byte, done 78 : } else { 79 358 : ctx->size = 2 << (buf[i] - 0xFD); 80 358 : ctx->offset = 0; 81 358 : ctx->value = 0; 82 358 : ctx->state = SVARINT_ST_BODY; 83 : } 84 358 : break; 85 1170 : case SVARINT_ST_BODY: 86 : // We don't support values greater than 32 bits in practice 87 : // (we do support up to 32 bit values 88 : // represented as 64 bit values though) 89 1170 : if (ctx->offset > 3 && buf[i] > 0) { 90 52 : ctx->state = SVARINT_ERR_UNSUPPORTED; 91 52 : return i + 1; 92 : } 93 : // Read little endian varint value 94 1118 : ctx->value += buf[i] << (8 * ctx->offset++); 95 1118 : if (--ctx->size == 0) { 96 306 : ctx->state = SVARINT_ST_DONE; 97 306 : return i + 1; 98 : } 99 812 : break; 100 50 : default: 101 : // Trying to read in any other state triggers an invalid error 102 50 : ctx->state = SVARINT_ERR_INVALID; 103 50 : return 0; 104 : } 105 : } 106 : 107 208 : return len; 108 : } 109 : 110 : /* 111 : * Encode a varint into a buffer. 112 : * Values longer than a byte are encoded in little endian 113 : * as per the bitcoin varint spec. 114 : * 115 : * @arg[in] value: value to encode 116 : * @arg[in] buf: destination buffer 117 : * @arg[in] len: destination buffer size 118 : * 119 : * @return the number of bytes actually written 120 : */ 121 49 : uint8_t svarint_encode(uint32_t value, uint8_t* buf, const uint8_t len) { 122 49 : if (value < 0xFD) { 123 37 : if (len < 1) 124 0 : return 0; 125 37 : buf[0] = (uint8_t)value; 126 37 : return 1; 127 12 : } else if (value <= 0xFFFF) { 128 9 : if (len < 3) 129 0 : return 0; 130 9 : buf[0] = 0xFD; 131 9 : buf[1] = value & 0xFF; 132 9 : buf[2] = (value & 0xFF00) >> 8; 133 9 : return 3; 134 : } else if (value <= 0xFFFFFFFF) { 135 3 : buf[0] = 0xFE; 136 3 : buf[1] = value & 0xFF; 137 3 : buf[2] = (value & 0xFF00) >> 8; 138 3 : buf[3] = (value & 0xFF0000) >> 16; 139 3 : buf[4] = (value & 0xFF000000) >> 24; 140 3 : return 5; 141 : } else { 142 : // We do not support values greater than 2^32-1 143 : return 0; 144 : } 145 : }