KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > jmx > snmp > BerDecoder


1 /*
2  * @(#)file BerDecoder.java
3  * @(#)author Sun Microsystems, Inc.
4  * @(#)version 4.20
5  * @(#)date 08/02/09
6  *
7  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
8  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
9  *
10  */

11
12
13 package com.sun.jmx.snmp;
14
15
16
17
18 /**
19  * The <CODE>BerDecoder</CODE> class is used for decoding
20  * BER-encoded data.
21  *
22  * A <CODE>BerDecoder</CODE> needs to be set up with the byte string containing
23  * the encoding. It maintains a current position in the byte string.
24  *
25  * Methods allows to fetch integer, string, OID, etc., from the current
26  * position. After a fetch the current position is moved forward.
27  *
28  * A fetch throws a <CODE>BerException</CODE> if the encoding is not of the
29  * expected type.
30  *
31  * <p><b>This API is a Sun Microsystems internal API and is subject
32  * to change without notice.</b></p>
33  * @version 4.20 12/19/03
34  * @author Sun Microsystems, Inc
35  *
36  * @since 1.5
37  */

38
39 public class BerDecoder {
40
41   /**
42   * Constructs a new decoder and attaches it to the specified byte string.
43   *
44   * @param b The byte string containing the encoded data.
45   */

46
47   public BerDecoder(byte b[]) {
48     bytes = b ;
49     reset() ;
50   }
51
52   public void reset() {
53     next = 0 ;
54     stackTop = 0 ;
55   }
56
57   /**
58   * Fetch an integer.
59   *
60   * @return The decoded integer.
61   *
62   * @exception BerException Current position does not point to an integer.
63   */

64
65   public int fetchInteger() throws BerException {
66     return fetchInteger(IntegerTag) ;
67   }
68
69
70   /**
71   * Fetch an integer with the specified tag.
72   *
73   * @param tag The expected tag.
74   *
75   * @return The decoded integer.
76   *
77   * @exception BerException Current position does not point to an integer
78   * or the tag is not the expected one.
79   */

80
81   public int fetchInteger(int tag) throws BerException {
82     int result = 0 ;
83     final int backup = next ;
84     try {
85       if (fetchTag() != tag) {
86         throw new BerException() ;
87       }
88       result = fetchIntegerValue() ;
89     }
90     catch(BerException e) {
91       next = backup ;
92       throw e ;
93     }
94     
95     return result ;
96   }
97
98
99
100   /**
101   * Fetch an integer and return a long value.
102   *
103   * @return The decoded integer.
104   *
105   * @exception BerException Current position does not point to an integer.
106   */

107
108   public long fetchIntegerAsLong() throws BerException {
109     return fetchIntegerAsLong(IntegerTag) ;
110   }
111
112
113   /**
114   * Fetch an integer with the specified tag and return a long value.
115   *
116   * @param tag The expected tag.
117   *
118   * @return The decoded integer.
119   *
120   * @exception BerException Current position does not point to an integer
121   * or the tag is not the expected one.
122   */

123
124   public long fetchIntegerAsLong(int tag) throws BerException {
125     long result = 0 ;
126     final int backup = next ;
127     try {
128       if (fetchTag() != tag) {
129         throw new BerException() ;
130       }
131       result = fetchIntegerValueAsLong() ;
132     }
133     catch(BerException e) {
134       next = backup ;
135       throw e ;
136     }
137     
138     return result ;
139   }
140
141
142
143   /**
144   * Fetch an octet string.
145   *
146   * @return The decoded string.
147   *
148   * @exception BerException Current position does not point to an octet string.
149   */

150
151   public byte[] fetchOctetString() throws BerException {
152     return fetchOctetString(OctetStringTag) ;
153   }
154   
155
156   /**
157   * Fetch an octet string with a specified tag.
158   *
159   * @param tag The expected tag.
160   *
161   * @return The decoded string.
162   *
163   * @exception BerException Current position does not point to an octet string
164   * or the tag is not the expected one.
165   */

166
167   public byte[] fetchOctetString(int tag) throws BerException {
168     byte[] result = null ;
169     final int backup = next ;
170     try {
171       if (fetchTag() != tag) {
172         throw new BerException() ;
173       }
174       result = fetchStringValue() ;
175     }
176     catch(BerException e) {
177       next = backup ;
178       throw e ;
179     }
180     
181     return result ;
182   }
183
184
185   /**
186   * Fetch an object identifier.
187   *
188   * @return The decoded object identifier as an array of long.
189   */

190
191   public long[] fetchOid() throws BerException {
192     return fetchOid(OidTag) ;
193   }
194   
195
196   /**
197   * Fetch an object identifier with a specified tag.
198   *
199   * @param tag The expected tag.
200   *
201   * @return The decoded object identifier as an array of long.
202   *
203   * @exception BerException Current position does not point to an oid
204   * or the tag is not the expected one.
205   */

206
207   public long[] fetchOid(int tag) throws BerException {
208     long[] result = null ;
209     final int backup = next ;
210     try {
211       if (fetchTag() != tag) {
212         throw new BerException() ;
213       }
214       result = fetchOidValue() ;
215     }
216     catch(BerException e) {
217       next = backup ;
218       throw e ;
219     }
220     
221     return result ;
222   }
223
224
225   /**
226   * Fetch a <CODE>NULL</CODE> value.
227   *
228   * @exception BerException Current position does not point to <CODE>NULL</CODE> value.
229   */

230
231   public void fetchNull() throws BerException {
232     fetchNull(NullTag) ;
233   }
234
235
236   /**
237   * Fetch a <CODE>NULL</CODE> value with a specified tag.
238   *
239   * @param tag The expected tag.
240   *
241   * @exception BerException Current position does not point to
242   * <CODE>NULL</CODE> value or the tag is not the expected one.
243   */

244
245   public void fetchNull(int tag) throws BerException {
246     final int backup = next ;
247     try {
248       if (fetchTag() != tag) {
249         throw new BerException() ;
250       }
251       final int length = fetchLength();
252       if (length != 0) throw new BerException();
253     }
254     catch(BerException e) {
255       next = backup ;
256       throw e ;
257     }
258   }
259   
260   
261
262   /**
263   * Fetch an <CODE>ANY</CODE> value. In fact, this method does not decode anything
264   * it simply returns the next TLV as an array of bytes.
265   *
266   * @return The TLV as a byte array.
267   *
268   * @exception BerException The next TLV is really badly encoded...
269   */

270
271   public byte[] fetchAny() throws BerException {
272     byte[] result = null ;
273     final int backup = next ;
274     try {
275       final int tag = fetchTag() ;
276       final int contentLength = fetchLength() ;
277       if (contentLength < 0) throw new BerException() ;
278       final int tlvLength = next + contentLength - backup ;
279       if (contentLength > (bytes.length - next))
280       throw new IndexOutOfBoundsException JavaDoc("Decoded length exceeds buffer");
281       final byte[] data = new byte[tlvLength] ;
282       java.lang.System.arraycopy(bytes,backup,data,0,tlvLength);
283       // for (int i = 0 ; i < tlvLength ; i++) {
284
// data[i] = bytes[backup + i] ;
285
// }
286
next = next + contentLength ;
287       result = data;
288     }
289     catch(IndexOutOfBoundsException JavaDoc e) {
290       next = backup ;
291       throw new BerException() ;
292     }
293     // catch(Error e) {
294
// debug("fetchAny: Error decoding BER: " + e);
295
// throw e;
296
// }
297

298     return result ;
299   }
300
301
302   /**
303   * Fetch an <CODE>ANY</CODE> value with a specific tag.
304   *
305   * @param tag The expected tag.
306   *
307   * @return The TLV as a byte array.
308   *
309   * @exception BerException The next TLV is really badly encoded...
310   */

311
312   public byte[] fetchAny(int tag) throws BerException {
313     if (getTag() != tag) {
314       throw new BerException() ;
315     }
316     return fetchAny() ;
317   }
318   
319   
320
321   /**
322   * Fetch a sequence header.
323   * The decoder computes the end position of the sequence and push it
324   * on its stack.
325   *
326   * @exception BerException Current position does not point to a sequence header.
327   */

328
329   public void openSequence() throws BerException {
330     openSequence(SequenceTag) ;
331   }
332
333
334   /**
335   * Fetch a sequence header with a specific tag.
336   *
337   * @param tag The expected tag.
338   *
339   * @exception BerException Current position does not point to a sequence header
340   * or the tag is not the expected one.
341   */

342
343   public void openSequence(int tag) throws BerException {
344     final int backup = next ;
345     try {
346       if (fetchTag() != tag) {
347         throw new BerException() ;
348       }
349       final int l = fetchLength() ;
350       if (l < 0) throw new BerException();
351       if (l > (bytes.length - next)) throw new BerException();
352       stackBuf[stackTop++] = next + l ;
353     }
354     catch(BerException e) {
355       next = backup ;
356       throw e ;
357     }
358   }
359
360
361   /**
362   * Close a sequence.
363   * The decode pull the stack and verifies that the current position
364   * matches with the calculated end of the sequence. If not it throws
365   * an exception.
366   *
367   * @exception BerException The sequence is not expected to finish here.
368   */

369
370   public void closeSequence() throws BerException {
371     if (stackBuf[stackTop - 1] == next) {
372       stackTop-- ;
373     }
374     else {
375       throw new BerException() ;
376     }
377   }
378
379
380   /**
381   * Return <CODE>true</CODE> if the end of the current sequence is not reached.
382   * When this method returns <CODE>false</CODE>, <CODE>closeSequence</CODE> can (and must) be
383   * invoked.
384   *
385   * @return <CODE>true</CODE> if there is still some data in the sequence.
386   */

387
388   public boolean cannotCloseSequence() {
389     return (next < stackBuf[stackTop - 1]) ;
390   }
391
392
393   /**
394   * Get the tag of the data at the current position.
395   * Current position is unchanged.
396   *
397   * @return The next tag.
398   */

399
400   public int getTag() throws BerException {
401     int result = 0 ;
402     final int backup = next ;
403     try {
404       result = fetchTag() ;
405     }
406     finally {
407       next = backup ;
408     }
409     
410     return result ;
411   }
412
413
414
415   public String JavaDoc toString() {
416     final StringBuffer JavaDoc result = new StringBuffer JavaDoc(bytes.length * 2) ;
417     for (int i = 0 ; i < bytes.length ; i++) {
418       final int b = (bytes[i] > 0) ? bytes[i] : bytes[i] + 256 ;
419       if (i == next) {
420         result.append("(") ;
421       }
422       result.append(Character.forDigit(b / 16, 16)) ;
423       result.append(Character.forDigit(b % 16, 16)) ;
424       if (i == next) {
425         result.append(")") ;
426       }
427     }
428     if (bytes.length == next) {
429       result.append("()") ;
430     }
431     
432     return new String JavaDoc(result) ;
433   }
434   
435   
436   //
437
// Some standard tags
438
//
439
public final static int BooleanTag = 1 ;
440   public final static int IntegerTag = 2 ;
441   public final static int OctetStringTag = 4 ;
442   public final static int NullTag = 5 ;
443   public final static int OidTag = 6 ;
444   public final static int SequenceTag = 0x30 ;
445
446
447
448
449   ////////////////////////// PRIVATE ///////////////////////////////
450

451
452
453   /**
454   * Fetch a tag and move the current position forward.
455   *
456   * @return The tag
457   */

458
459   private final int fetchTag() throws BerException {
460     int result = 0 ;
461     final int backup = next ;
462     
463     try {
464       final byte b0 = bytes[next++] ;
465       result = (b0 >= 0) ? b0 : b0 + 256 ;
466       if ((result & 31) == 31) {
467         while ((bytes[next] & 128) != 0) {
468           result = result << 7 ;
469           result = result | (bytes[next++] & 127);
470         }
471       }
472     }
473     catch(IndexOutOfBoundsException JavaDoc e) {
474       next = backup ;
475       throw new BerException() ;
476     }
477     
478     return result ;
479   }
480
481
482   /**
483   * Fetch a length and move the current position forward.
484   *
485   * @return The length
486   */

487
488   private final int fetchLength() throws BerException {
489     int result = 0 ;
490     final int backup = next ;
491     
492     try {
493       final byte b0 = bytes[next++] ;
494       if (b0 >= 0) {
495         result = b0 ;
496       }
497       else {
498         for (int c = 128 + b0 ; c > 0 ; c--) {
499           final byte bX = bytes[next++] ;
500           result = result << 8 ;
501           result = result | ((bX >= 0) ? bX : bX+256) ;
502         }
503       }
504     }
505     catch(IndexOutOfBoundsException JavaDoc e) {
506       next = backup ;
507       throw new BerException() ;
508     }
509
510     return result ;
511   }
512   
513
514   /**
515   * Fetch an integer value and move the current position forward.
516   *
517   * @return The integer
518   */

519
520   private int fetchIntegerValue() throws BerException {
521     int result = 0 ;
522     final int backup = next ;
523     
524     try {
525       final int length = fetchLength() ;
526       if (length <= 0) throw new BerException() ;
527       if (length > (bytes.length - next)) throw
528       new IndexOutOfBoundsException JavaDoc("Decoded length exceeds buffer");
529       final int end = next + length ;
530       result = bytes[next++] ;
531       while (next < end) {
532         final byte b = bytes[next++] ;
533         if (b < 0) {
534           result = (result << 8) | (256 + b) ;
535         }
536         else {
537           result = (result << 8) | b ;
538         }
539       }
540     }
541     catch(BerException e) {
542       next = backup ;
543       throw e ;
544     }
545     catch(IndexOutOfBoundsException JavaDoc e) {
546       next = backup ;
547       throw new BerException() ;
548     }
549     catch(ArithmeticException JavaDoc e) {
550       next = backup ;
551       throw new BerException() ;
552     }
553     return result ;
554   }
555   
556   
557   /**
558   * Fetch an integer value and return a long value.
559   * FIX ME: someday we could have only on fetchIntegerValue() which always
560   * returns a long value.
561   *
562   * @return The integer
563   */

564
565   private final long fetchIntegerValueAsLong() throws BerException {
566     long result = 0 ;
567     final int backup = next ;
568     
569     try {
570       final int length = fetchLength() ;
571       if (length <= 0) throw new BerException() ;
572       if (length > (bytes.length - next)) throw
573       new IndexOutOfBoundsException JavaDoc("Decoded length exceeds buffer");
574
575       final int end = next + length ;
576       result = bytes[next++] ;
577       while (next < end) {
578         final byte b = bytes[next++] ;
579         if (b < 0) {
580           result = (result << 8) | (256 + b) ;
581         }
582         else {
583           result = (result << 8) | b ;
584         }
585       }
586     }
587     catch(BerException e) {
588       next = backup ;
589       throw e ;
590     }
591     catch(IndexOutOfBoundsException JavaDoc e) {
592       next = backup ;
593       throw new BerException() ;
594     }
595     catch(ArithmeticException JavaDoc e) {
596       next = backup ;
597       throw new BerException() ;
598     }
599     return result ;
600   }
601   
602   
603   /**
604   * Fetch a byte string and move the current position forward.
605   *
606   * @return The byte string
607   */

608
609   private byte[] fetchStringValue() throws BerException {
610     byte[] result = null ;
611     final int backup = next ;
612     
613     try {
614       final int length = fetchLength() ;
615       if (length < 0) throw new BerException() ;
616       if (length > (bytes.length - next))
617       throw new IndexOutOfBoundsException JavaDoc("Decoded length exceeds buffer");
618       final byte data[] = new byte[length] ;
619       java.lang.System.arraycopy(bytes,next,data,0,length);
620       next += length;
621       // int i = 0 ;
622
// while (i < length) {
623
// result[i++] = bytes[next++] ;
624
// }
625
result = data;
626     }
627     catch(BerException e) {
628     next = backup ;
629       throw e ;
630     }
631     catch(IndexOutOfBoundsException JavaDoc e) {
632       next = backup ;
633       throw new BerException() ;
634     }
635     catch(ArithmeticException JavaDoc e) {
636       next = backup ;
637       throw new BerException() ;
638     }
639     // catch(Error e) {
640
// debug("fetchStringValue: Error decoding BER: " + e);
641
// throw e;
642
// }
643

644     return result ;
645   }
646
647
648
649   /**
650   * Fetch an oid and move the current position forward.
651   *
652   * @return The oid
653   */

654
655   private final long[] fetchOidValue() throws BerException {
656     long[] result = null ;
657     final int backup = next ;
658     
659     try {
660       final int length = fetchLength() ;
661       if (length <= 0) throw new BerException() ;
662       if (length > (bytes.length - next))
663       throw new IndexOutOfBoundsException JavaDoc("Decoded length exceeds buffer");
664       // Count how many bytes have their 8th bit to 0
665
// -> this gives the number of components in the oid
666
int subidCount = 2 ;
667       for (int i = 1 ; i < length ; i++) {
668         if ((bytes[next + i] & 0x80) == 0) {
669           subidCount++ ;
670         }
671       }
672       final int datalen = subidCount;
673       final long[] data = new long[datalen];
674       final byte b0 = bytes[next++] ;
675
676       // bugId 4641746
677
// The 8th bit of the first byte should always be set to 0
678
if (b0 < 0) throw new BerException();
679       
680       // bugId 4641746
681
// The first sub Id cannot be greater than 2
682
final long lb0 = b0 / 40 ;
683       if (lb0 > 2) throw new BerException();
684
685       final long lb1 = b0 % 40;
686       data[0] = lb0 ;
687       data[1] = lb1 ;
688       int i = 2 ;
689       while (i < datalen) {
690         long subid = 0 ;
691         byte b = bytes[next++] ;
692         while ((b & 0x80) != 0) {
693           subid = (subid << 7) | (b & 0x7f) ;
694       // bugId 4654674
695
if (subid < 0) throw new BerException();
696           b = bytes[next++] ;
697         }
698         subid = (subid << 7) | b ;
699     // bugId 4654674
700
if (subid < 0) throw new BerException();
701         data[i++] = subid ;
702       }
703       result = data;
704     }
705     catch(BerException e) {
706       next = backup ;
707       throw e ;
708     }
709     catch(IndexOutOfBoundsException JavaDoc e) {
710       next = backup ;
711       throw new BerException() ;
712     }
713     // catch(Error e) {
714
// debug("fetchOidValue: Error decoding BER: " + e);
715
// throw e;
716
// }
717

718     return result ;
719   }
720   
721     // private static final void debug(String str) {
722
// System.out.println(str);
723
// }
724

725   //
726
// This is the byte array containing the encoding.
727
//
728
private final byte bytes[];
729   
730   //
731
// This is the current location. It is the next byte
732
// to be decoded. It's an index in bytes[].
733
//
734
private int next = 0 ;
735   
736   //
737
// This is the stack where end of sequences are kept.
738
// A value is computed and pushed in it each time openSequence()
739
// is invoked.
740
// A value is pulled and checked each time closeSequence() is called.
741
//
742
private final int stackBuf[] = new int[200] ;
743   private int stackTop = 0 ;
744   
745 }
746
747
748
Popular Tags