<commit_before><?php

namespace Bitcoin\Util;

use Bitcoin\Util\Buffer;
use Bitcoin\Bitcoin;
use Bitcoin\Exceptions\ParserOutOfRange;

/**
 * Class Parser - mainly for decoding transactions..
 *
 * @package Bitcoin
 */
class Parser
{
    /**
     * @var string
     */
    protected $string;

    /**
     * @var \Bitcoin\Math\MathAdapter
     */
    protected $math;

    /**
     * @var int
     */
    protected $position = 0;

    /**
     * Instantiate class, optionally taking a given hex string or Buffer.
     *
     * @param null $input
     * @throws \Exception
     */
    public function __construct($input = null)
    {
        if (!$input instanceof Buffer) {
            $input = Buffer::hex($input);
        }

        $this->string   = $input->serialize();
        $this->position = 0;
        $this->math     = Bitcoin::getMath();
        return $this;
    }

    /**
     * Convert a decimal number into a VarInt Buffer
     *
     * @param $decimal
     * @return Buffer
     * @throws \Exception
     */
    public static function numToVarInt($decimal)
    {
        if ($decimal < 0xfd) {
            $bin = chr($decimal);
        } else if ($decimal <= 0xffff) {
            // Uint16
            $bin = pack("Cv", 0xfd, $decimal);
        } else if ($decimal <= 0xffffffff) {
            // Uint32
            $bin = pack("CV", 0xfe, $decimal);
        } else {
            // Todo, support for 64bit integers
            throw new \Exception('numToVarInt(): Integer too large');
        }

        return new Buffer($bin);
    }

    /**
     * Flip byte order of this binary string
     *
     * @param $hex
     * @return string
     */
    public static function flipBytes($hex)
    {
        return implode('', array_reverse(str_split($hex, 1)));
    }

    /**
     * Get the position pointer of the parser - ie, how many bytes from 0
     *
     * @return int
     */
    public function getPosition()
    {
        return $this->position;
    }

    /**
     * Parse a vector from a string of data. Vectors are arrays, prefixed
     * by the number of items in the list.
     *
     * @param $array
     * @param callable $callback
     * @return array
     */
    public function getArray(callable $callback)
    {
        $results = array();
        $varInt  = $this->getVarInt();
        $txCount = $varInt->serialize('int');

        for ($i = 0; $i < $txCount; $i++) {
            $results[] = $callback($this);
        }

        return $results;
    }

    /**
     * Parse a variable length integer
     *
     * @return Buffer
     * @throws \Exception
     */
    public function getVarInt()
    {
        // Return the length encoded in this var int
        $byte   = $this->readBytes(1);
        $int    = $byte->serialize('int');

        if ($this->math->cmp($int, 0xfd) < 0) {
            return $byte;
        } else if ($this->math->cmp($int, 0xfd) == 0) {
            return $this->readBytes(2, true);
        } else if ($this->math->cmp($int, 0xfe) == 0) {
            return $this->readBytes(4, true);
        } else if ($this->math->cmp($int, 0xff) == 0) {
            return $this->readBytes(8, true);
        }
    }

    /**
     * Return a variable length string. This is a variable length string,
     * prefixed with it's length encoded as a VarInt.
     *
     * @return Buffer
     * @throws \Exception
     */
    public function getVarString()
    {
        $varInt = $this->getVarInt()->serialize('int');
        $string = $this->readBytes($varInt);
        return $string;
    }

    /**
     * Parse $bytes bytes from the string, and return the obtained buffer
     *
     * @param $bytes
     * @param bool $flipBytes
     * @return Buffer
     * @throws \Exception
     */
    public function readBytes($bytes, $flipBytes = false)
    {<commit_msg>If varstring length is 0, return an empty buffer<commit_after><?php

namespace Bitcoin\Util;

use Bitcoin\Util\Buffer;
use Bitcoin\Bitcoin;
use Bitcoin\Exceptions\ParserOutOfRange;

/**
 * Class Parser - mainly for decoding transactions..
 *
 * @package Bitcoin
 */
class Parser
{
    /**
     * @var string
     */
    protected $string;

    /**
     * @var \Bitcoin\Math\MathAdapter
     */
    protected $math;

    /**
     * @var int
     */
    protected $position = 0;

    /**
     * Instantiate class, optionally taking a given hex string or Buffer.
     *
     * @param null $input
     * @throws \Exception
     */
    public function __construct($input = null)
    {
        if (!$input instanceof Buffer) {
            $input = Buffer::hex($input);
        }

        $this->string   = $input->serialize();
        $this->position = 0;
        $this->math     = Bitcoin::getMath();
        return $this;
    }

    /**
     * Convert a decimal number into a VarInt Buffer
     *
     * @param $decimal
     * @return Buffer
     * @throws \Exception
     */
    public static function numToVarInt($decimal)
    {
        if ($decimal < 0xfd) {
            $bin = chr($decimal);
        } else if ($decimal <= 0xffff) {
            // Uint16
            $bin = pack("Cv", 0xfd, $decimal);
        } else if ($decimal <= 0xffffffff) {
            // Uint32
            $bin = pack("CV", 0xfe, $decimal);
        } else {
            // Todo, support for 64bit integers
            throw new \Exception('numToVarInt(): Integer too large');
        }

        return new Buffer($bin);
    }

    /**
     * Flip byte order of this binary string
     *
     * @param $hex
     * @return string
     */
    public static function flipBytes($hex)
    {
        return implode('', array_reverse(str_split($hex, 1)));
    }

    /**
     * Get the position pointer of the parser - ie, how many bytes from 0
     *
     * @return int
     */
    public function getPosition()
    {
        return $this->position;
    }

    /**
     * Parse a vector from a string of data. Vectors are arrays, prefixed
     * by the number of items in the list.
     *
     * @param $array
     * @param callable $callback
     * @return array
     */
    public function getArray(callable $callback)
    {
        $results = array();
        $varInt  = $this->getVarInt();
        $txCount = $varInt->serialize('int');

        for ($i = 0; $i < $txCount; $i++) {
            $results[] = $callback($this);
        }

        return $results;
    }

    /**
     * Parse a variable length integer
     *
     * @return Buffer
     * @throws \Exception
     */
    public function getVarInt()
    {
        // Return the length encoded in this var int
        $byte   = $this->readBytes(1);
        $int    = $byte->serialize('int');

        if ($this->math->cmp($int, 0xfd) < 0) {
            return $byte;
        } else if ($this->math->cmp($int, 0xfd) == 0) {
            return $this->readBytes(2, true);
        } else if ($this->math->cmp($int, 0xfe) == 0) {
            return $this->readBytes(4, true);
        } else if ($this->math->cmp($int, 0xff) == 0) {
            return $this->readBytes(8, true);
        }
    }

    /**
     * Return a variable length string. This is a variable length string,
     * prefixed with it's length encoded as a VarInt.
     *
     * @return Buffer
     * @throws \Exception
     */
    public function getVarString()
    {
        $varInt = $this->getVarInt()->serialize('int');
        if ($this->math->cmp($varInt, 0) == 0) {
            return new Buffer();
        }
        $string = $this->readBytes($varInt);
        return $string;
    }

    /**
     * Parse $bytes bytes from the string, and return the obtained buffer
     *
     * @param $bytes
     * @param bool $flipBytes
     * @return Buffer
     * @throws \Exception
     */
    public function readBytes($bytes, $flipBytes = false)
    {
{'fraction_non_alphanumeric': 0.13622889547622116, 'fraction_numerical': 0.007604072689779611, 'mean_word_length': 1.776386404293381, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 51, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5353576', 'n_tokens_mistral': 2378, 'n_tokens_neox': 2288, 'n_words': 651}