001 /*
002 * Copyright 2007-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2008-2014 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021 package com.unboundid.asn1;
022
023
024
025 import com.unboundid.util.NotMutable;
026 import com.unboundid.util.ThreadSafety;
027 import com.unboundid.util.ThreadSafetyLevel;
028
029 import static com.unboundid.asn1.ASN1Constants.*;
030 import static com.unboundid.asn1.ASN1Messages.*;
031 import static com.unboundid.util.Debug.*;
032
033
034
035 /**
036 * This class provides an ASN.1 integer element, whose value may be represented
037 * as an integer with up to a 32-bit representation.
038 */
039 @NotMutable()
040 @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
041 public final class ASN1Integer
042 extends ASN1Element
043 {
044 /**
045 * The serial version UID for this serializable class.
046 */
047 private static final long serialVersionUID = -733929804601994372L;
048
049
050
051 // The int value for this element.
052 private final int intValue;
053
054
055
056 /**
057 * Creates a new ASN.1 integer element with the default BER type and the
058 * provided int value.
059 *
060 * @param intValue The int value to use for this element.
061 */
062 public ASN1Integer(final int intValue)
063 {
064 super(UNIVERSAL_INTEGER_TYPE, encodeIntValue(intValue));
065
066 this.intValue = intValue;
067 }
068
069
070
071 /**
072 * Creates a new ASN.1 integer element with the specified BER type and the
073 * provided int value.
074 *
075 * @param type The BER type to use for this element.
076 * @param intValue The int value to use for this element.
077 */
078 public ASN1Integer(final byte type, final int intValue)
079 {
080 super(type, encodeIntValue(intValue));
081
082 this.intValue = intValue;
083 }
084
085
086
087 /**
088 * Creates a new ASN.1 integer element with the specified BER type and the
089 * provided int and pre-encoded values.
090 *
091 * @param type The BER type to use for this element.
092 * @param intValue The int value to use for this element.
093 * @param value The pre-encoded value to use for this element.
094 */
095 private ASN1Integer(final byte type, final int intValue, final byte[] value)
096 {
097 super(type, value);
098
099 this.intValue = intValue;
100 }
101
102
103
104 /**
105 * Encodes the provided int value to a byte array suitable for use as the
106 * value of an integer element.
107 *
108 * @param intValue The int value to be encoded.
109 *
110 * @return A byte array containing the encoded value.
111 */
112 static byte[] encodeIntValue(final int intValue)
113 {
114 if (intValue < 0)
115 {
116 if ((intValue & 0xFFFFFF80) == 0xFFFFFF80)
117 {
118 return new byte[]
119 {
120 (byte) (intValue & 0xFF)
121 };
122 }
123 else if ((intValue & 0xFFFF8000) == 0xFFFF8000)
124 {
125 return new byte[]
126 {
127 (byte) ((intValue >> 8) & 0xFF),
128 (byte) (intValue & 0xFF)
129 };
130 }
131 else if ((intValue & 0xFF800000) == 0xFF800000)
132 {
133 return new byte[]
134 {
135 (byte) ((intValue >> 16) & 0xFF),
136 (byte) ((intValue >> 8) & 0xFF),
137 (byte) (intValue & 0xFF)
138 };
139 }
140 else
141 {
142 return new byte[]
143 {
144 (byte) ((intValue >> 24) & 0xFF),
145 (byte) ((intValue >> 16) & 0xFF),
146 (byte) ((intValue >> 8) & 0xFF),
147 (byte) (intValue & 0xFF)
148 };
149 }
150 }
151 else
152 {
153 if ((intValue & 0x0000007F) == intValue)
154 {
155 return new byte[]
156 {
157 (byte) (intValue & 0x7F)
158 };
159 }
160 else if ((intValue & 0x00007FFF) == intValue)
161 {
162 return new byte[]
163 {
164 (byte) ((intValue >> 8) & 0x7F),
165 (byte) (intValue & 0xFF)
166 };
167 }
168 else if ((intValue & 0x007FFFFF) == intValue)
169 {
170 return new byte[]
171 {
172 (byte) ((intValue >> 16) & 0x7F),
173 (byte) ((intValue >> 8) & 0xFF),
174 (byte) (intValue & 0xFF)
175 };
176 }
177 else
178 {
179 return new byte[]
180 {
181 (byte) ((intValue >> 24) & 0x7F),
182 (byte) ((intValue >> 16) & 0xFF),
183 (byte) ((intValue >> 8) & 0xFF),
184 (byte) (intValue & 0xFF)
185 };
186 }
187 }
188 }
189
190
191
192 /**
193 * Retrieves the int value for this element.
194 *
195 * @return The int value for this element.
196 */
197 public int intValue()
198 {
199 return intValue;
200 }
201
202
203
204 /**
205 * Decodes the contents of the provided byte array as an integer element.
206 *
207 * @param elementBytes The byte array to decode as an ASN.1 integer element.
208 *
209 * @return The decoded ASN.1 integer element.
210 *
211 * @throws ASN1Exception If the provided array cannot be decoded as an
212 * integer element.
213 */
214 public static ASN1Integer decodeAsInteger(final byte[] elementBytes)
215 throws ASN1Exception
216 {
217 try
218 {
219 int valueStartPos = 2;
220 int length = (elementBytes[1] & 0x7F);
221 if (length != elementBytes[1])
222 {
223 final int numLengthBytes = length;
224
225 length = 0;
226 for (int i=0; i < numLengthBytes; i++)
227 {
228 length <<= 8;
229 length |= (elementBytes[valueStartPos++] & 0xFF);
230 }
231 }
232
233 if ((elementBytes.length - valueStartPos) != length)
234 {
235 throw new ASN1Exception(ERR_ELEMENT_LENGTH_MISMATCH.get(length,
236 (elementBytes.length - valueStartPos)));
237 }
238
239 final byte[] value = new byte[length];
240 System.arraycopy(elementBytes, valueStartPos, value, 0, length);
241
242 int intValue;
243 switch (value.length)
244 {
245 case 1:
246 intValue = (value[0] & 0xFF);
247 if ((value[0] & 0x80) != 0x00)
248 {
249 intValue |= 0xFFFFFF00;
250 }
251 break;
252
253 case 2:
254 intValue = ((value[0] & 0xFF) << 8) | (value[1] & 0xFF);
255 if ((value[0] & 0x80) != 0x00)
256 {
257 intValue |= 0xFFFF0000;
258 }
259 break;
260
261 case 3:
262 intValue = ((value[0] & 0xFF) << 16) | ((value[1] & 0xFF) << 8) |
263 (value[2] & 0xFF);
264 if ((value[0] & 0x80) != 0x00)
265 {
266 intValue |= 0xFF000000;
267 }
268 break;
269
270 case 4:
271 intValue = ((value[0] & 0xFF) << 24) | ((value[1] & 0xFF) << 16) |
272 ((value[2] & 0xFF) << 8) | (value[3] & 0xFF);
273 break;
274
275 default:
276 throw new ASN1Exception(ERR_ENUMERATED_INVALID_LENGTH.get(
277 value.length));
278 }
279
280 return new ASN1Integer(elementBytes[0], intValue, value);
281 }
282 catch (final ASN1Exception ae)
283 {
284 debugException(ae);
285 throw ae;
286 }
287 catch (final Exception e)
288 {
289 debugException(e);
290 throw new ASN1Exception(ERR_ELEMENT_DECODE_EXCEPTION.get(e), e);
291 }
292 }
293
294
295
296 /**
297 * Decodes the provided ASN.1 element as an integer element.
298 *
299 * @param element The ASN.1 element to be decoded.
300 *
301 * @return The decoded ASN.1 integer element.
302 *
303 * @throws ASN1Exception If the provided element cannot be decoded as an
304 * integer element.
305 */
306 public static ASN1Integer decodeAsInteger(final ASN1Element element)
307 throws ASN1Exception
308 {
309 int intValue;
310 final byte[] value = element.getValue();
311 switch (value.length)
312 {
313 case 1:
314 intValue = (value[0] & 0xFF);
315 if ((value[0] & 0x80) != 0x00)
316 {
317 intValue |= 0xFFFFFF00;
318 }
319 break;
320
321 case 2:
322 intValue = ((value[0] & 0xFF) << 8) | (value[1] & 0xFF);
323 if ((value[0] & 0x80) != 0x00)
324 {
325 intValue |= 0xFFFF0000;
326 }
327 break;
328
329 case 3:
330 intValue = ((value[0] & 0xFF) << 16) | ((value[1] & 0xFF) << 8) |
331 (value[2] & 0xFF);
332 if ((value[0] & 0x80) != 0x00)
333 {
334 intValue |= 0xFF000000;
335 }
336 break;
337
338 case 4:
339 intValue = ((value[0] & 0xFF) << 24) | ((value[1] & 0xFF) << 16) |
340 ((value[2] & 0xFF) << 8) | (value[3] & 0xFF);
341 break;
342
343 default:
344 throw new ASN1Exception(ERR_INTEGER_INVALID_LENGTH.get(value.length));
345 }
346
347 return new ASN1Integer(element.getType(), intValue, value);
348 }
349
350
351
352 /**
353 * Appends a string representation of this ASN.1 element to the provided
354 * buffer.
355 *
356 * @param buffer The buffer to which to append the information.
357 */
358 @Override()
359 public void toString(final StringBuilder buffer)
360 {
361 buffer.append(intValue);
362 }
363 }