// Copyright 2022, FOSS-VG Developers and Contributers // // Author(s): // BodgeMaster, Shwoomple // // This program is free software: you can redistribute it and/or modify it // under the terms of the GNU Affero General Public License as published // by the Free Software Foundation, version 3. // // 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 Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // version 3 along with this program. // If not, see https://www.gnu.org/licenses/agpl-3.0.en.html #pragma once #include #include #include "../../error.hpp" namespace VarInt { // up to 5 bytes, least significant byte first, most significant bit // indicates whether the next byte is still part of the number ErrorOr fromVar32(std::vector data, uint64_t initialPosition=0, uint8_t* processedBytes=nullptr) { if (initialPosition >= data.size()) { return ErrorOr(true, ErrorCodes::OUT_OF_RANGE); } int32_t returnValue = 0; uint64_t currentPosition = initialPosition; uint8_t bits = 0; while (data[currentPosition] & 0b10000000 && currentPosition < initialPosition+4) { returnValue = returnValue + (((int32_t) 0b01111111 & data[currentPosition]) << bits); (*processedBytes)++; bits += 7; currentPosition++; // check after increasing so we don't need to check outside the loop if (currentPosition >= data.size()) { return ErrorOr(true, ErrorCodes::OVERRUN); } } if (data[currentPosition] & 0b10000000) { return ErrorOr(true, ErrorCodes::OVERFLOW); } returnValue = returnValue + (((int32_t) 0b01111111 & data[currentPosition]) << bits); (*processedBytes)++; return ErrorOr(returnValue); } // up to 10 bytes, least significant byte first, most significant bit // indicates whether the next byte is still part of the number ErrorOr fromVar64(std::vector data, uint64_t initialPosition=0, uint8_t* processedBytes=nullptr) { if (initialPosition >= data.size()) { return ErrorOr(true, ErrorCodes::OUT_OF_RANGE); } int64_t returnValue = 0; uint64_t currentPosition = initialPosition; uint8_t bits = 0; while (data[currentPosition] & 0b10000000 && currentPosition < initialPosition+9) { returnValue = returnValue + (((int64_t) 0b01111111 & data[currentPosition]) << bits); (*processedBytes)++; bits += 7; currentPosition++; // check after increasing so we don't need to check outside the loop if (currentPosition >= data.size()) { return ErrorOr(true, ErrorCodes::OVERRUN); } } if (data[currentPosition] & 0b10000000) { return ErrorOr(true, ErrorCodes::OVERFLOW); } returnValue = returnValue + (((int64_t) 0b01111111 & data[currentPosition]) << bits); (*processedBytes)++; return ErrorOr(returnValue); } // appends to the vector void toVar32(int32_t value, std::vector &data) { uint8_t nextByte; uint8_t shift = 0; // do something else after the 4th shift while (shift < 4) { if (shift>0 && value==0) { return; } nextByte = value & 0b01111111; value = (value >> 7) & 0x01FFFFFF; shift++; if (value>0) { nextByte = nextByte + 0b10000000; } data.push_back(nextByte); } if (value>0) { data.push_back(value & 0b00001111); } } // appends to the vector void toVar64(int64_t value, std::vector &data) { uint8_t nextByte; uint8_t shift = 0; // do something else after the 4th shift while (shift < 9) { if (shift>0 && value==0) { return; } nextByte = value & 0b01111111; value = (value >> 7) & 0x01FFFFFFFFFFFFFF; shift++; if (value>0) { nextByte = nextByte + 0b10000000; } data.push_back(nextByte); } if (value>0) { data.push_back(value & 0b00000001); } } }