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