View Javadoc
1   /*
2     (C) Copyright IBM Corp. 2006, 2011
3   
4     THIS FILE IS PROVIDED UNDER THE TERMS OF THE ECLIPSE PUBLIC LICENSE
5     ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE
6     CONSTITUTES RECIPIENTS ACCEPTANCE OF THE AGREEMENT.
7   
8     You can obtain a current copy of the Eclipse Public License from
9     http://www.opensource.org/licenses/eclipse-1.0.php
10  
11    @author : Endre Bak, ebak@de.ibm.com
12   * 
13   * Flag       Date        Prog         Description
14   * -------------------------------------------------------------------------------
15   * 1565892    2006-11-05  ebak         Make SBLIM client JSR48 compliant
16   * 2003590    2008-06-30  blaschke-oss Change licensing from CPL to EPL
17   * 2524131    2009-01-21  raman_arora  Upgrade client to JDK 1.5 (Phase 1)
18   * 2763216    2009-04-14  blaschke-oss Code cleanup: visible spelling/grammar errors
19   * 3194680    2011-02-28  blaschke-oss Error in numeric keys
20   */
21  
22  package org.metricshub.wbem.sblim.cimclient.internal.uri;
23  
24  /*-
25   * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
26   * WBEM Java Client
27   * ჻჻჻჻჻჻
28   * Copyright 2023 - 2025 MetricsHub
29   * ჻჻჻჻჻჻
30   * Licensed under the Apache License, Version 2.0 (the "License");
31   * you may not use this file except in compliance with the License.
32   * You may obtain a copy of the License at
33   *
34   *      http://www.apache.org/licenses/LICENSE-2.0
35   *
36   * Unless required by applicable law or agreed to in writing, software
37   * distributed under the License is distributed on an "AS IS" BASIS,
38   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
39   * See the License for the specific language governing permissions and
40   * limitations under the License.
41   * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
42   */
43  
44  import java.math.BigInteger;
45  import java.util.regex.Matcher;
46  import java.util.regex.Pattern;
47  
48  /**
49   * Class IntegerValue parses and encapsulates an integer value.
50   *
51   */
52  public class IntegerValue extends Value {
53  	private BigInteger iBigValue;
54  
55  	private boolean iTyped;
56  
57  	private int iBitWidth;
58  
59  	private boolean iSigned;
60  
61  	/**
62  	 * <pre>
63  	 *      integerValue 		=	binaryValue | octalValue | decimalValue | hexValue
64  	 *      binaryValue		=	[ &quot;+&quot; | &quot;-&quot; ] 1*binaryDigit ( &quot;b&quot; | &quot;B&quot; )
65  	 *      octalValue		=	[ &quot;+&quot; | &quot;-&quot; ] &quot;0&quot; 1*octalDigit
66  	 *      decimalValue		=	[ &quot;+&quot; | &quot;-&quot; ] ( positiveDecimalDigit *decimalDigit | &quot;0&quot; )
67  	 *      hexValue			=	[ &quot;+&quot; | &quot;-&quot; ] ( &quot;0x&quot; | &quot;0X&quot; ) 1*hexDigit
68  	 * </pre>
69  	 *
70  	 * @param pUriStr
71  	 * @param pTyped
72  	 *            - if <code>true</code> pSigned and pBitWidth will be
73  	 *            considered otherwise not
74  	 * @param pSigned
75  	 * @param pBitWidth
76  	 * @param pThrow
77  	 * @return a <code>Value</code> or null if parsing is failed and pThrow is
78  	 *         false
79  	 * @throws IllegalArgumentException
80  	 *             if parsing is failed and pThrow is true
81  	 */
82  	private static Value parse(URIString pUriStr, boolean pTyped, boolean pSigned, int pBitWidth, boolean pThrow)
83  		throws IllegalArgumentException {
84  		URIString savedUriStr = pUriStr.deepCopy();
85  		// get the substring till the next ',' or end of uriStr
86  		String valStr = pUriStr.removeTill(',');
87  		if (valStr == null) {
88  			pUriStr.set(savedUriStr);
89  			if (pThrow) {
90  				String msg = "Empty value!\n" + pUriStr.markPosition();
91  				pUriStr.set(savedUriStr);
92  				throw new IllegalArgumentException(msg);
93  			}
94  			return null;
95  		}
96  
97  		if (valStr.compareTo("0") == 0) {
98  			// Special case "0" to avoid changing patterns below ("0" does not
99  			// match any of the patterns, so produces null IntegerValue)
100 			return make(valStr, 10, pTyped, pSigned, pBitWidth);
101 		}
102 		IntegerValue val;
103 		Matcher m = DEC_PAT.matcher(valStr);
104 		if (m.matches()) {
105 			val = make(valStr, 10, pTyped, pSigned, pBitWidth);
106 			if (val != null) return val;
107 			pUriStr.set(savedUriStr);
108 			if (pThrow) {
109 				String msg = "Failed to parse decimal value!\n" + pUriStr.markPosition();
110 				throw new IllegalArgumentException(msg);
111 			}
112 			return null;
113 		}
114 		m = HEX_PAT.matcher(valStr);
115 		if (m.matches()) {
116 			String sign = m.group(1);
117 			String str = sign == null ? m.group(2) : sign + m.group(2);
118 			val = make(str, 16, pTyped, pSigned, pBitWidth);
119 			if (val != null) return val;
120 			pUriStr.set(savedUriStr);
121 			if (pThrow) {
122 				String msg = "Failed to parse hexadecimal value!\n" + pUriStr.markPosition();
123 				throw new IllegalArgumentException(msg);
124 			}
125 			return null;
126 		}
127 		m = OCT_PAT.matcher(valStr);
128 		if (m.matches()) {
129 			val = make(valStr, 8, pTyped, pSigned, pBitWidth);
130 			if (val != null) return val;
131 			pUriStr.set(savedUriStr);
132 			if (pThrow) {
133 				String msg = "Failed to parse octal value!\n" + pUriStr.markPosition();
134 				throw new IllegalArgumentException(msg);
135 			}
136 			return null;
137 		}
138 		m = BIN_PAT.matcher(valStr);
139 		if (m.matches()) {
140 			val = make(m.group(1), 2, pTyped, pSigned, pBitWidth);
141 			if (val != null) return val;
142 			pUriStr.set(savedUriStr);
143 			if (pThrow) {
144 				String msg = "Failed to parse binary value!\n" + pUriStr.markPosition();
145 				throw new IllegalArgumentException(msg);
146 			}
147 			return null;
148 		}
149 		pUriStr.set(savedUriStr);
150 		if (pThrow) {
151 			String msg = "Failed to parse integer value!\n" + pUriStr.markPosition();
152 			throw new IllegalArgumentException(msg);
153 		}
154 		return null;
155 	}
156 
157 	/**
158 	 * Parses an untyped integer value.
159 	 *
160 	 * @param pUriStr
161 	 * @return a <code>Value</code>
162 	 */
163 	public static Value parse(URIString pUriStr) {
164 		return parse(pUriStr, false, false, 0, false);
165 	}
166 
167 	/**
168 	 * parseUnsigned
169 	 *
170 	 * @param pUriStr
171 	 * @param pBitWidth
172 	 * @return Value
173 	 * @throws IllegalArgumentException
174 	 *             if parsing failed.
175 	 */
176 	public static Value parseUnsigned(URIString pUriStr, int pBitWidth) throws IllegalArgumentException {
177 		return parse(pUriStr, true, false, pBitWidth, true);
178 	}
179 
180 	/**
181 	 * parseSigned
182 	 *
183 	 * @param pUriStr
184 	 * @param pBitWidth
185 	 * @return Value
186 	 * @throws IllegalArgumentException
187 	 *             if parsing failed.
188 	 */
189 	public static Value parseSigned(URIString pUriStr, int pBitWidth) throws IllegalArgumentException {
190 		return parse(pUriStr, true, true, pBitWidth, true);
191 	}
192 
193 	private static final Pattern BIN_PAT = Pattern.compile("^((?:\\+|-)?[01]+)[bB]$"), OCT_PAT = Pattern.compile(
194 		"^(?:\\+|-)?0[0-7]+$"
195 	), DEC_PAT = Pattern.compile("^(?:\\+|-)?[1-9][0-9]*$"), HEX_PAT = Pattern.compile("^(\\+|-)?0[xX]([0-9a-fA-F]+)$");
196 
197 	private IntegerValue(String pStrVal, int pRadix, boolean pTyped, boolean pSigned, int pBitWidth) {
198 		this.iBigValue = new BigInteger(pStrVal, pRadix);
199 		this.iTyped = pTyped;
200 		this.iSigned = pSigned;
201 		this.iBitWidth = pBitWidth;
202 	}
203 
204 	private static IntegerValue make(String pStrVal, int pRadix, boolean pTyped, boolean pSigned, int pBitWidth) {
205 		IntegerValue val = new IntegerValue(pStrVal, pRadix, pTyped, pSigned, pBitWidth);
206 		if (pTyped) {
207 			if (!pSigned && val.isNegative()) {
208 				// TODO: tracing!
209 				// parsed integer is negative but it should be an unsigned
210 				// integer!
211 				return null;
212 			}
213 			if (val.bitLength() > val.getBitWidth()) {
214 				// TODO: tracing!
215 				// parsed integer cannot be fitted to the passed bitWidth!
216 				return null;
217 			}
218 		}
219 		return val;
220 	}
221 
222 	/**
223 	 * byteValue
224 	 *
225 	 * @return byte
226 	 */
227 	public byte byteValue() {
228 		return this.iBigValue.byteValue();
229 	}
230 
231 	/**
232 	 * shortValue
233 	 *
234 	 * @return short
235 	 */
236 	public short shortValue() {
237 		return this.iBigValue.shortValue();
238 	}
239 
240 	/**
241 	 * intValue
242 	 *
243 	 * @return int
244 	 */
245 	public int intValue() {
246 		return this.iBigValue.intValue();
247 	}
248 
249 	/**
250 	 * longValue
251 	 *
252 	 * @return long
253 	 */
254 	public long longValue() {
255 		return this.iBigValue.longValue();
256 	}
257 
258 	/**
259 	 * bigIntValue
260 	 *
261 	 * @return BigInteger
262 	 */
263 	public BigInteger bigIntValue() {
264 		return this.iBigValue;
265 	}
266 
267 	/**
268 	 * isNegative
269 	 *
270 	 * @return <code>true</code> if the number is negative
271 	 */
272 	public boolean isNegative() {
273 		return this.iBigValue.compareTo(BigInteger.ZERO) < 0;
274 	}
275 
276 	/**
277 	 * isSigned
278 	 *
279 	 * @return <code>true</code> if the number is signed integer
280 	 */
281 	public boolean isSigned() {
282 		if (this.iTyped) return this.iSigned;
283 		return isNegative();
284 	}
285 
286 	/**
287 	 * bitLength
288 	 *
289 	 * @return the number of bits which is required for storing this integer
290 	 *         value.
291 	 */
292 	public int bitLength() {
293 		int len = this.iBigValue.bitLength();
294 		if (isSigned()) ++len;
295 		return len;
296 	}
297 
298 	/**
299 	 * getBitWidth
300 	 *
301 	 * @return 8, 16, 32 or 64
302 	 */
303 	public int getBitWidth() {
304 		if (this.iTyped) return this.iBitWidth;
305 		int rawWidth = bitLength();
306 		if (rawWidth <= 8) return 8;
307 		if (rawWidth <= 16) return 16;
308 		if (rawWidth <= 32) return 32;
309 		return 64;
310 	}
311 
312 	/**
313 	 * @see java.lang.Object#toString()
314 	 */
315 	@Override
316 	public String toString() {
317 		return this.iBigValue.toString();
318 	}
319 
320 	/**
321 	 * @see Value#getTypeInfo()
322 	 */
323 	@Override
324 	public String getTypeInfo() {
325 		return isSigned() ? "sint" : "uint" + getBitWidth();
326 	}
327 }