1<?php declare(strict_types = 1);
2/*
3** Zabbix
4** Copyright (C) 2001-2021 Zabbix SIA
5**
6** This program is free software; you can redistribute it and/or modify
7** it under the terms of the GNU General Public License as published by
8** the Free Software Foundation; either version 2 of the License, or
9** (at your option) any later version.
10**
11** This program is distributed in the hope that it will be useful,
12** but WITHOUT ANY WARRANTY; without even the implied warranty of
13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14** GNU General Public License for more details.
15**
16** You should have received a copy of the GNU General Public License
17** along with this program; if not, write to the Free Software
18** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19**/
20
21
22/**
23 * A parser for numbers with optional time or byte suffix.
24 */
25class CNumberParser extends CParser {
26
27	/**
28	* Parser options.
29	*
30	* @var array
31	*/
32	private $options = [
33		'with_minus' => true,
34		'with_suffix' => false
35	];
36
37	/**
38	 * Parsed number without time or byte suffix.
39	 *
40	 * @var string
41	 */
42	private $number;
43
44	/**
45	 * Parsed time or byte suffix, or null, if wasn't found.
46	 *
47	 * @var string|null
48	 */
49	private $suffix;
50
51	/**
52	 * Acceptable time and byte suffixes.
53	 *
54	 * @var string
55	 */
56	private static $suffixes = ZBX_TIME_SUFFIXES.ZBX_BYTE_SUFFIXES;
57
58	/**
59	 * Suffix multiplier table for value calculation.
60	 *
61	 * @var array
62	 */
63	private static $suffix_multipliers = ZBX_BYTE_SUFFIX_MULTIPLIERS + ZBX_TIME_SUFFIX_MULTIPLIERS;
64
65	public function __construct(array $options = []) {
66		$this->options = array_replace($this->options, array_intersect_key($options, $this->options));
67	}
68
69	/**
70	 * Parse number with optional time or byte suffix.
71	 *
72	 * !!! Don't forget sync code with C !!!
73	 *
74	 * @param string $source  string to parse
75	 * @param int    $pos     position to start from
76	 *
77	 * @return int
78	 */
79	public function parse($source, $pos = 0): int {
80		$this->length = 0;
81		$this->match = '';
82		$this->number = null;
83		$this->suffix = null;
84
85		$fragment = substr($source, $pos);
86
87		$pattern = $this->options['with_suffix']
88			? '/^'.ZBX_PREG_NUMBER.'(?<suffix>['.self::$suffixes.'])?/'
89			: '/^'.ZBX_PREG_NUMBER.'/';
90
91		if (!preg_match($pattern, $fragment, $matches)) {
92			return self::PARSE_FAIL;
93		}
94
95		if ($matches['number'][0] === '-' && !$this->options['with_minus']) {
96			return self::PARSE_FAIL;
97		}
98
99		$this->length = strlen($matches[0]);
100		$this->match = $matches[0];
101
102		$this->number = $matches['number'];
103		$this->suffix = array_key_exists('suffix', $matches) ? $matches['suffix'] : null;
104
105		return ($pos + $this->length < strlen($source)) ? self::PARSE_SUCCESS_CONT : self::PARSE_SUCCESS;
106	}
107
108	/**
109	 * Calculate value of parsed number in a decimal notation.
110	 *
111	 * @return float
112	 */
113	public function calcValue(): float {
114		$number = (float) $this->number;
115
116		if ($this->suffix !== null) {
117			$number *= self::$suffix_multipliers[$this->suffix];
118		}
119
120		return $number;
121	}
122
123	/**
124	 * Get suffix of parsed number.
125	 *
126	 * @return string|null
127	 */
128	public function getSuffix(): ?string {
129		return $this->suffix;
130	}
131}
132