// Sshwifty - A Web SSH client // // Copyright (C) 2019-2021 NI Rui // // 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, 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 Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . package commands import ( "errors" "github.com/nirui/sshwifty/application/rw" ) // Errors var ( ErrIntegerMarshalNotEnoughBuffer = errors.New( "Not enough buffer to marshal the integer") ErrIntegerMarshalTooLarge = errors.New( "Integer cannot be marshalled, because the vaule was too large") ) // Integer is a 16bit unsigned integer data // // Format: // +-------------------------------------+--------------+ // | 1 bit | 7 bits | // +-------------------------------------+--------------+ // | 1 when current byte is the end byte | Integer data | // +-------------------------------------+--------------+ // // Example: // - 00000000 00000000: 0 // - 01111111: 127 // - 11111111 01000000: 255 type Integer uint16 const ( integerHasNextBit = 0x80 integerValueCutter = 0x7f ) // Consts const ( MaxInteger = 0x3fff MaxIntegerBytes = 2 ) // ByteSize returns how many bytes current integer will be encoded into func (i *Integer) ByteSize() int { if *i > integerValueCutter { return 2 } return 1 } // Int returns a int of current Integer func (i *Integer) Int() int { return int(*i) } // Marshal build serialized data of the integer func (i *Integer) Marshal(b []byte) (int, error) { bLen := len(b) if *i > MaxInteger { return 0, ErrIntegerMarshalTooLarge } if bLen < i.ByteSize() { return 0, ErrIntegerMarshalNotEnoughBuffer } if *i <= integerValueCutter { b[0] = byte(*i & integerValueCutter) return 1, nil } b[0] = byte((*i >> 7) | integerHasNextBit) b[1] = byte(*i & integerValueCutter) return 2, nil } // Unmarshal read data and parse the integer func (i *Integer) Unmarshal(reader rw.ReaderFunc) error { buf := [1]byte{} for j := 0; j < MaxIntegerBytes; j++ { _, rErr := rw.ReadFull(reader, buf[:]) if rErr != nil { return rErr } *i |= Integer(buf[0] & integerValueCutter) if integerHasNextBit&buf[0] == 0 { return nil } *i <<= 7 } return nil }