/* ** Copyright (C) 2001-2024 Zabbix SIA ** ** 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 along with this program. ** If not, see <https://www.gnu.org/licenses/>. **/ package asn1 import ( "errors" "io" "golang.zabbix.com/sdk/errs" ) // Read reads the next glow data block of the appropriate type, it checks the glow tag against the provided compare // function and if they match it reads the glow data block and returns it as it's own decoded, original decoder might // have more data left, THIS DOES NOT READ ALL THE DATA. // If no length byte is found in data returns ALL remaining bytes. // Returns True if next element length is unknown. func (c *Decoder) Read(tag uint8, compareByte func(num uint8) uint8) (*Decoder, bool, error) { b, err := c.data.ReadByte() if err != nil { return nil, false, errs.Wrap(err, "failed to read tag byte") } if b != compareByte(tag) { return nil, false, errs.Errorf("is not correct byte: %x got %x", compareByte(tag), b) } lenB, _, err := c.ReadLength() if err != nil { if !errors.Is(err, ErrNoLenByte) { return nil, false, errs.Wrap(err, "failed to read length byte") } var out []byte out, err = c.readWithOutLength() if err != nil { return nil, false, errs.Wrap(err, "failed to read with out provided length") } return NewDecoder(out), true, nil } out, err := c.readWithLength(lenB) if err != nil { return nil, false, errs.Wrap(err, "failed to read with provided length") } return NewDecoder(out), false, nil } // ReadLength reads next in line data blocks length and returns it as well as how many bytes the data // length was written in. func (c *Decoder) ReadLength() (int, int, error) { lenB, err := c.data.ReadByte() if err != nil { return 0, 0, errs.Wrap(err, "incorrect length byte") } if lenB&contextByte != contextByte { return int(lenB), 1, nil } lenB &= lenByte if lenB == 0 { return 0, 1, ErrNoLenByte } if lenB > maxLengthBytes { return 0, 0, errs.New("length higher than 4") } var ( out int offset = 1 ) for i := 0; i < int(lenB); i++ { val, err := c.data.ReadByte() if err != nil { return 0, 0, errs.Wrap(err, "incorrect additional length bytes") } out = out<<8 + int(val) offset++ } return out, offset, nil } // ReadEnd checks if decoder is currently at the end of element and moves the reader over it, if at end. func (c *Decoder) ReadEnd() (bool, error) { if c.data.Len() == 0 { return true, nil } if c.data.Len() < 2 { return false, errs.New("not enough bytes") } b := c.data.Bytes() if b[0] != closingByte || b[1] != closingByte { return false, nil } for i := 0; i < closingOffset; i++ { _, err := c.data.ReadByte() if err != nil { return false, errs.Wrapf(err, "failed to read end bytes") } } return true, nil } // Peek returns the next byte, but does not remove it from the buffer. func (c *Decoder) Peek() (byte, error) { b, err := c.data.ReadByte() if err != nil { return 0, errs.Wrap(err, "failed to read a byte") } err = c.data.UnreadByte() if err != nil { return 0, errs.Wrap(err, "failed to unread a byte") } return b, nil } // DecodeUniversal decoded the following universal data type of glow, currently only used for universal path decoding, // witch is an array of integers. func (c *Decoder) DecodeUniversal() ([]int, error) { b, err := c.data.ReadByte() if err != nil { return nil, errs.Wrap(err, "failed to read tag byte") } if b != UniversalObjectTag { return nil, errs.New("incorrect universal byte") } lenB, _, err := c.ReadLength() if err != nil { return nil, errs.Wrap(err, "failed to read len byte") } var out []int for i := 1; i <= lenB; i++ { b, err := c.data.ReadByte() if err != nil { return nil, errs.Wrap(err, "failed to read extra len bytes") } out = append(out, int(b)) } return out, nil } // DecodeInteger decodes the following integer. func (c *Decoder) DecodeInteger() (int, error) { t, err := c.data.ReadByte() if err != nil { return 0, errs.Wrap(err, "failed to read tag byte") } if t != emberIntTag { return 0, errs.New("incorrect integer byte") } lenB, _, err := c.ReadLength() if err != nil { return 0, errs.Wrap(err, "failed to read len byte") } var out int for ; lenB > 0; lenB-- { b, err := c.data.ReadByte() if err != nil { return 0, errs.Wrap(err, "failed to read extra len bytes") } out = (out << 8) | int(b) } return out, nil } // ReadByte reads one byte from the underlining bytes buffer in decoder. func (c *Decoder) ReadByte() (byte, error) { b, err := c.data.ReadByte() if err != nil { return 0, errs.Wrap(err, "failed to read byte") } return b, nil } func (c *Decoder) readWithOutLength() ([]byte, error) { out, err := io.ReadAll(c.data) if err != nil { return nil, errs.Wrap(err, "failed to read all data") } return out, nil } func (c *Decoder) readWithLength(length int) ([]byte, error) { //nolint:makezero out := make([]byte, length) n, err := c.data.Read(out) if err != nil { return nil, errs.Wrap(err, "failed to read bytes with set length") } if n != length { return nil, errs.Errorf( "failed to read bytes with set length, length %d does not match actual read length %d", length, n, ) } return out, nil }