1 // NAME
2 // $RCSfile: AsnOctets.java,v $
3 // DESCRIPTION
4 // [given below in javadoc format]
5 // DELTA
6 // $Revision: 3.39 $
7 // CREATED
8 // $Date: 2006/03/23 14:54:10 $
9 // COPYRIGHT
10 // Westhawk Ltd
11 // TO DO
12 //
13
14 /*
15 * Copyright (C) 1995, 1996 by West Consulting BV
16 *
17 * Permission to use, copy, modify, and distribute this software
18 * for any purpose and without fee is hereby granted, provided
19 * that the above copyright notices appear in all copies and that
20 * both the copyright notice and this permission notice appear in
21 * supporting documentation.
22 * This software is provided "as is" without express or implied
23 * warranty.
24 * author <a href="mailto:snmp@westhawk.co.uk">Tim Panton</a>
25 * original version by hargrave@dellgate.us.dell.com (Jordan Hargrave)
26 */
27
28 /*
29 * Copyright (C) 1996 - 2006 by Westhawk Ltd
30 * <a href="www.westhawk.co.uk">www.westhawk.co.uk</a>
31 *
32 * Permission to use, copy, modify, and distribute this software
33 * for any purpose and without fee is hereby granted, provided
34 * that the above copyright notices appear in all copies and that
35 * both the copyright notice and this permission notice appear in
36 * supporting documentation.
37 * This software is provided "as is" without express or implied
38 * warranty.
39 * author <a href="mailto:snmp@westhawk.co.uk">Tim Panton</a>
40 */
41
42 package uk.co.westhawk.snmp.stack;
43
44 /*-
45 * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
46 * SNMP Java Client
47 * ჻჻჻჻჻჻
48 * Copyright 2023 MetricsHub, Westhawk
49 * ჻჻჻჻჻჻
50 * This program is free software: you can redistribute it and/or modify
51 * it under the terms of the GNU Lesser General Public License as
52 * published by the Free Software Foundation, either version 3 of the
53 * License, or (at your option) any later version.
54 *
55 * This program is distributed in the hope that it will be useful,
56 * but WITHOUT ANY WARRANTY; without even the implied warranty of
57 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
58 * GNU General Lesser Public License for more details.
59 *
60 * You should have received a copy of the GNU General Lesser Public
61 * License along with this program. If not, see
62 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
63 * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
64 */
65
66 import uk.co.westhawk.snmp.util.*;
67 import java.io.*;
68 import java.util.*;
69 import java.net.InetAddress;
70 import java.text.SimpleDateFormat;
71
72 /**
73 * This class represents the ASN.1 Octet class.
74 * It can be used for Octets, Ip Addresses and Opaque primitive types.
75 *
76 * The Octets type (ASN_OCTET_STR) is used for some text convensions.
77 * This class supports the DateAndTime, DisplayString and
78 * InternationalDisplayString and Ipv6Address text convensions.
79 * <br/>
80 * Note, the SNMP representation of IPv4 and IPv6 is different:
81 * <ul>
82 * <li>IPv4: IPADDRESS (or ASN_OCTET_STR, see rfc 4001)</li>
83 * <li>IPv6: ASN_OCTET_STR</li>
84 * </ul>
85 * See also
86 * <a href="http://www.ietf.org/rfc/rfc2465.txt">IPV6-TC</a>,
87 * <a href="http://www.ietf.org/rfc/rfc3416.txt">SNMPv2-PDU</a>,
88 * <a href="http://www.ietf.org/rfc/rfc4001.txt">INET-ADDRESS-MIB</a>.
89 *
90 * @see SnmpConstants#ASN_OCTET_STR
91 * @see SnmpConstants#IPADDRESS
92 * @see SnmpConstants#OPAQUE
93 *
94 * @author <a href="mailto:snmp@westhawk.co.uk">Tim Panton</a>
95 * @version $Revision: 3.39 $ $Date: 2006/03/23 14:54:10 $
96 */
97 public class AsnOctets extends AsnObject {
98 private static final String version_id = "@(#)$Id: AsnOctets.java,v 3.39 2006/03/23 14:54:10 birgit Exp $ Copyright Westhawk Ltd";
99
100 /**
101 * The hexadecimal prefix that is used when printing a hexadecimal
102 * number in toString(). By default this is "0x".
103 */
104 public static String HEX_PREFIX = "0x";
105
106 /**
107 * The object that is used in toCalendar() to format the calendar
108 * representation of the Octets according to the DateAndTime text
109 * convension.
110 * The pattern is "yyyy-M-d,HH:mm:ss.SS,z".
111 *
112 * @see #getCalendar()
113 * @see #toCalendar()
114 * @see SimpleDateFormat
115 */
116 public static SimpleDateFormat CALFORMAT = new SimpleDateFormat("yyyy-M-d,HH:mm:ss.SS,z");
117
118 /**
119 * The default AsnOctetsPrintableFace object.
120 *
121 * @see #setPrintable
122 * @see DefaultAsnOctetsPrintable
123 */
124 public static AsnOctetsPrintableFace printableObject = new DefaultAsnOctetsPrintable();
125
126 byte value[];
127
128 /** Cache the hash code for the OID */
129 private int hash = 0;
130
131 /**
132 * Constructor. The type of the AsnOctets defaults to ASN_OCTET_STR.
133 *
134 * @param s The byte array representing the AsnOctets
135 * @see SnmpConstants#ASN_OCTET_STR
136 */
137 public AsnOctets(byte s[])
138 throws IllegalArgumentException {
139 this(s, ASN_OCTET_STR);
140 }
141
142 /**
143 * Constructor to create a specific type of AsnOctets.
144 *
145 * @param s The byte array representing the AsnOctets
146 * @param t The type of the AsnOctets
147 * @see SnmpConstants#ASN_OCTET_STR
148 * @see SnmpConstants#IPADDRESS
149 * @see SnmpConstants#OPAQUE
150 */
151 public AsnOctets(byte s[], byte t)
152 throws IllegalArgumentException {
153 value = s;
154 type = t;
155 if (value == null) {
156 throw new IllegalArgumentException("Value is null");
157 }
158 }
159
160 /**
161 * Constructor. The type of the AsnOctets defaults to ASN_OCTET_STR.
162 *
163 * @param s The character array representing the AsnOctets
164 * @see SnmpConstants#ASN_OCTET_STR
165 */
166 public AsnOctets(char s[]) {
167 int idx;
168
169 value = new byte[s.length];
170 type = ASN_OCTET_STR;
171 for (idx = 0; idx < s.length; idx++) {
172 value[idx] = (byte) s[idx];
173 }
174 }
175
176 /**
177 * Constructor. The type of the AsnOctets defaults to ASN_OCTET_STR.
178 *
179 * @param s The string representing the AsnOctets
180 * @see SnmpConstants#ASN_OCTET_STR
181 */
182 public AsnOctets(String s) {
183 this(s.toCharArray());
184 }
185
186 /**
187 * Constructor to create an ASN IP Address.
188 * If the address represents an IPv4 address, the asn type will be
189 * set to IPADDRESS. If it represents an IPv6 address, the asn type
190 * will be set to ASN_OCTET_STR.
191 *
192 * <br/>
193 * Note, the SNMP representation of IPv4 and IPv6 is different:
194 * <ul>
195 * <li>IPv4: IPADDRESS (or ASN_OCTET_STR, see rfc 4001)</li>
196 * <li>IPv6: ASN_OCTET_STR</li>
197 * </ul>
198 * See also
199 * <a href="http://www.ietf.org/rfc/rfc2465.txt">IPV6-TC</a>,
200 * <a href="http://www.ietf.org/rfc/rfc3416.txt">SNMPv2-PDU</a>,
201 * <a href="http://www.ietf.org/rfc/rfc4001.txt">INET-ADDRESS-MIB</a>.
202 *
203 * @param iad The Inet Address
204 *
205 * @see #AsnOctets(Inet4Address, byte)
206 */
207 public AsnOctets(InetAddress iad)
208 throws IllegalArgumentException {
209 this(iad.getAddress(), ASN_OCTET_STR);
210 if (iad instanceof java.net.Inet4Address) {
211 // IPv4
212 type = IPADDRESS;
213 } else {
214 // IPv6 is ASN_OCTET_STR, so do nothing
215 }
216 }
217
218 /**
219 * Constructor to create an ASN IPv4 Address.
220 * If the address is an IPv4 address, it can either be represented
221 * by IPADDRESS or as ASN_OCTET_STR.
222 *
223 * See also
224 * <a href="http://www.ietf.org/rfc/rfc2465.txt">IPV6-TC</a>,
225 * <a href="http://www.ietf.org/rfc/rfc3416.txt">SNMPv2-PDU</a>,
226 * <a href="http://www.ietf.org/rfc/rfc4001.txt">INET-ADDRESS-MIB</a>.
227 *
228 * @param iad The IPv4 Inet Address
229 * @param t The type of the AsnOctets
230 *
231 * @see #AsnOctets(InetAddress)
232 * @see SnmpConstants#IPADDRESS
233 * @see SnmpConstants#ASN_OCTET_STR
234 * @since 4_14
235 */
236 public AsnOctets(java.net.Inet4Address iad, byte t)
237 throws IllegalArgumentException {
238 this(iad.getAddress(), t);
239 }
240
241 /**
242 * Constructor for DateAndTime text convension.
243 * See
244 * <a href="http://www.ietf.org/rfc/rfc2579.txt">SNMPv2-TC</a>
245 *
246 * <pre>
247 * field octets contents range
248 * ----- ------ -------- -----
249 * 1 1-2 year* 0..65536
250 * 2 3 month 1..12
251 * 3 4 day 1..31
252 * 4 5 hour 0..23
253 * 5 6 minutes 0..59
254 * 6 7 seconds 0..60
255 * (use 60 for leap-second)
256 * 7 8 deci-seconds 0..9
257 *
258 * 8 9 direction from UTC '+' / '-'
259 * 9 10 hours from UTC* 0..13
260 * 10 11 minutes from UTC 0..59
261 *
262 * SYNTAX OCTET STRING (SIZE (8 | 11))
263 * </pre>
264 *
265 * @since 4_14
266 */
267 public AsnOctets(Calendar cal) {
268 value = new byte[11];
269 type = ASN_OCTET_STR;
270
271 int year = cal.get(Calendar.YEAR);
272 // Calendar: 0=January
273 int month = cal.get(Calendar.MONTH) + 1;
274 int day = cal.get(Calendar.DAY_OF_MONTH);
275 int hour = cal.get(Calendar.HOUR_OF_DAY);
276 int min = cal.get(Calendar.MINUTE);
277 int sec = cal.get(Calendar.SECOND);
278 int msec = cal.get(Calendar.MILLISECOND);
279 int msecGMT = cal.get(Calendar.ZONE_OFFSET);
280
281 // The value of year is in network-byte order
282 // Is this correct?
283 value[0] = (byte) ((year / 256) % 256);
284 value[1] = (byte) (year % 256);
285
286 value[2] = (byte) (month & 0xFF);
287 value[3] = (byte) (day & 0xFF);
288 value[4] = (byte) (hour & 0xFF);
289 value[5] = (byte) (min & 0xFF);
290 value[6] = (byte) (sec & 0xFF);
291 value[7] = (byte) ((msec / 100) & 0xFF);
292
293 char dir = '\0';
294 if (msecGMT < 0) {
295 dir = '-';
296 msecGMT = msecGMT * -1;
297 } else {
298 dir = '+';
299 }
300 value[8] = (byte) dir;
301
302 if (msecGMT == 0) {
303 value[9] = 0x00;
304 value[10] = 0x00;
305 } else {
306 int minGMT = (int) (((double) msecGMT) / 1000.0 / 60.0);
307 if (minGMT == 0) {
308 value[9] = 0x00;
309 value[10] = 0x00;
310 } else {
311 int hourGMT = (int) (minGMT / 60.0);
312 minGMT = minGMT - (hourGMT * 60);
313 value[9] = (byte) (hourGMT & 0xFF);
314 value[10] = (byte) (minGMT & 0xFF);
315 }
316 }
317 }
318
319 /**
320 * Constructor.
321 *
322 * @param in The input stream from which the value should be read
323 * @param len The length of the AsnOctets
324 */
325 public AsnOctets(InputStream in, int len) throws IOException {
326 value = new byte[len];
327 if (len != 0) {
328 if (len == in.read(value, 0, len)) {
329 String str = "";
330 // str = new String(value);
331 } else {
332 throw new IOException("AsnOctets(): Not enough data");
333 }
334 } else {
335 // if len is zero, the in.read will return -1
336 // a length of zero is a valid case.
337 ;
338 }
339 }
340
341 /**
342 * Sets the global hexadecimal prefix. This prefix will be used in
343 * toString() when it prints out a hexadecimal number. It is not
344 * used in toHex(). The default is "0x".
345 *
346 * @see #toString()
347 * @see #toHex()
348 * @see #HEX_PREFIX
349 */
350 public static void setHexPrefix(String newPrefix) {
351 HEX_PREFIX = newPrefix;
352 }
353
354 /**
355 * Sets the global AsnOctetsPrintableFace printableObject. This
356 * object will be used in the toString() and the
357 * toInternationalDisplayString() methods.
358 *
359 * @see #toString
360 * @see #toInternationalDisplayString
361 * @since 4_14
362 */
363 public static void setPrintable(AsnOctetsPrintableFace obj) {
364 if (obj != null) {
365 printableObject = obj;
366 }
367 }
368
369 /**
370 * Returns the String value. Calls toString().
371 *
372 * @return The value of the AsnOctets
373 * @see #toString()
374 */
375 public String getValue() {
376 return toString();
377 }
378
379 /**
380 * Returns the bytes. This returns a copy of the internal byte array.
381 *
382 * @return The bytes of the AsnOctets
383 */
384 public byte[] getBytes() {
385 int len = value.length;
386 byte[] bytea = new byte[len];
387 System.arraycopy(value, 0, bytea, 0, len);
388 return bytea;
389 }
390
391 /**
392 * Returns the string representation of the AsnOctets.
393 * <p>
394 * The string will have one of the following formats:
395 * </p>
396 * <ul>
397 * <li>if this class represents an IP Address (v4), it will call
398 * toIpAddress()</li>
399 * <li><prefix>aa[:bb]*, if this class represents a non-printable
400 * string or has type OPAQUE.
401 * The output will be in hexadecimal numbers (see toHex()). It will be prefixed
402 * according to the hex. prefix value</li>
403 * <li>a printable string, if this class seems printable</li>
404 * </ul>
405 *
406 * <p>
407 * When the type is ASN_OCTET_STR, this method uses the
408 * AsnOctetsPrintableFace.isPrintable() to determine whether or not
409 * the string is printable. If it is printable, it will use
410 * AsnOctetsPrintableFace.toInternationalDisplayString() to
411 * transform the Octets to a String.
412 * </p>
413 *
414 * <br/>
415 * Note, the SNMP representation of IPv4 and IPv6 is different:
416 * <ul>
417 * <li>IPv4: IPADDRESS (or ASN_OCTET_STR, see rfc 4001)</li>
418 * <li>IPv6: ASN_OCTET_STR</li>
419 * </ul>
420 * See also
421 * <a href="http://www.ietf.org/rfc/rfc2465.txt">IPV6-TC</a>,
422 * <a href="http://www.ietf.org/rfc/rfc3416.txt">SNMPv2-PDU</a>,
423 * <a href="http://www.ietf.org/rfc/rfc4001.txt">INET-ADDRESS-MIB</a>.
424 *
425 * @see #HEX_PREFIX
426 * @see #setHexPrefix(String)
427 * @see #toHex
428 * @see #toIpAddress
429 * @see AsnOctetsPrintableFace#isPrintable
430 * @see AsnOctetsPrintableFace#toInternationalDisplayString
431 * @return The string representation of the AsnOctets
432 */
433 public String toString() {
434 return toString(printableObject);
435 }
436
437 /**
438 * As toString(), but this methods will use this specific, one-off
439 * AsnOctetsPrintableFace object.
440 *
441 * @see #toString()
442 * @since 4_14
443 */
444 public String toString(AsnOctetsPrintableFace face) {
445 String str = "";
446
447 if (type == IPADDRESS) {
448 // for IPv4 only
449 str = toIpAddress();
450 } else if (type == OPAQUE) {
451 str = HEX_PREFIX + toHex();
452 } else {
453 boolean isPrintable = face.isPrintable(value);
454 if (isPrintable) {
455 str = face.toInternationalDisplayString(value);
456 } else {
457 str = HEX_PREFIX + toHex();
458 }
459 }
460 return str;
461 }
462
463 int size() {
464 return value.length;
465 }
466
467 void write(OutputStream out, int pos) throws IOException {
468 int idx;
469
470 // Output header
471 AsnBuildHeader(out, type, value.length);
472 if (debug > 10) {
473 System.out.println("\tAsnOctets(): value = " + toString()
474 + ", pos = " + pos);
475 }
476
477 // Output data
478 for (idx = 0; idx < value.length; idx++) {
479 out.write(value[idx]);
480 }
481 }
482
483 /**
484 * Returns this Octet as an IP Address string. The format is
485 * aaa.bbb.ccc.ddd (IPv4) or a:b:c:d:e:f:g:h (IPv6).
486 *
487 * Note, the SNMP representation of IPv4 and IPv6 is different:
488 * <ul>
489 * <li>IPv4: IPADDRESS (or ASN_OCTET_STR, see rfc 4001)</li>
490 * <li>IPv6: ASN_OCTET_STR</li>
491 * </ul>
492 * See also
493 * <a href="http://www.ietf.org/rfc/rfc2465.txt">IPV6-TC</a>,
494 * <a href="http://www.ietf.org/rfc/rfc3416.txt">SNMPv2-PDU</a>,
495 * <a href="http://www.ietf.org/rfc/rfc4001.txt">INET-ADDRESS-MIB</a>.
496 *
497 * @return The IP Address representation.
498 * @see #toString
499 * @see #getIpAddress
500 * @see SnmpConstants#ASN_OCTET_STR
501 * @see SnmpConstants#IPADDRESS
502 */
503 /*
504 * TODO: use Java's java.net.InetAddress, so it can be used for IPv4, and IPv6.
505 */
506 public String toIpAddress() {
507 /*
508 * TODO: Does this work? Yes, but will not compile in jdk 1.2.X, and
509 * in order to load (a part of) the stack in Oracle, I need
510 * 1.2.X
511 */
512 /*
513 * String str = "";
514 * try
515 * {
516 * InetAddress iad = InetAddress.getByAddress(value);
517 * str = iad.getHostAddress();
518 * }
519 * catch (java.net.UnknownHostException exc) { }
520 */
521
522 /*
523 */
524 StringBuffer sb = new StringBuffer(39);
525 int length;
526 long val;
527 length = value.length;
528 if (length > 0) {
529 if (length > 4) {
530 // IPv6
531 // Nicked this code from Inet6Address.numericToTextFormat
532 for (int i = 0; i < length / 2; i++) {
533 sb.append(Integer.toHexString(((value[i << 1] << 8) & 0xff00)
534 | (value[(i << 1) + 1] & 0xff)));
535 if (i < ((length / 2) - 1)) {
536 sb.append(":");
537 }
538 }
539 } else {
540 // IPv4
541 for (int i = 0; i < length - 1; i++) {
542 val = getPositiveValue(i);
543 sb.append(String.valueOf(val)).append(".");
544 }
545 val = getPositiveValue(length - 1);
546 sb.append(String.valueOf(val));
547 }
548 }
549 return sb.toString();
550 }
551
552 /**
553 * Returns this Octet as an IP Address.
554 *
555 * Note, the SNMP representation of IPv4 and IPv6 is different:
556 * <ul>
557 * <li>IPv4: IPADDRESS (or ASN_OCTET_STR, see rfc 4001)</li>
558 * <li>IPv6: ASN_OCTET_STR</li>
559 * </ul>
560 * See also
561 * <a href="http://www.ietf.org/rfc/rfc2465.txt">IPV6-TC</a>,
562 * <a href="http://www.ietf.org/rfc/rfc3416.txt">SNMPv2-PDU</a>,
563 * <a href="http://www.ietf.org/rfc/rfc4001.txt">INET-ADDRESS-MIB</a>.
564 *
565 * @return The IP Address representation.
566 * @exception RuntimeException Thrown when the Octets does
567 * not represent an InetAddress or when the method
568 * internally throws
569 * an java.net.UnknownHostException
570 *
571 * @see #toString
572 * @see #toIpAddress
573 * @see SnmpConstants#ASN_OCTET_STR
574 * @see SnmpConstants#IPADDRESS
575 * @since 4_14
576 */
577 public InetAddress getIpAddress()
578 throws RuntimeException {
579 InetAddress iad = null;
580 try {
581 iad = InetAddress.getByAddress(value);
582 } catch (java.net.UnknownHostException exc) {
583 throw new RuntimeException(exc);
584 }
585 return iad;
586 }
587
588 /**
589 * Returns the positive long for an octet. Only if type is IPADDRESS
590 * can the value be negative anyway.
591 */
592 private long getPositiveValue(int index) {
593 long val = (long) value[index];
594 if (val < 0) {
595 val += 256;
596 }
597 return val;
598 }
599
600 /**
601 * Returns this Octet as an hexadecimal String, without any prefix.
602 *
603 * @return The hex representation.
604 * @see #toString
605 */
606 public String toHex() {
607 int length;
608 StringBuffer buffer = new StringBuffer("");
609
610 length = value.length;
611 if (length > 0) {
612 for (int i = 0; i < length - 1; i++) {
613 buffer.append(SnmpUtilities.toHex(value[i])).append(":");
614 }
615 buffer.append(SnmpUtilities.toHex(value[length - 1]));
616 }
617
618 return buffer.toString();
619 }
620
621 /**
622 * Returns this Octet as a display string (text convension). In contrast to the
623 * method toString(), this method does not try to guess whether or
624 * not this string is printable, it just converts it to a
625 * String, using "US-ASCII" character set.
626 *
627 * <p>
628 * DisplayString
629 * represents textual information taken from the NVT
630 * ASCII character set, as defined in pages 4, 10-11
631 * of <a href="http://www.ietf.org/rfc/rfc854.txt">RFC 854</a>.
632 * Any object defined using this syntax
633 * may not exceed 255 characters in length.
634 * Basicly it is US-ASCII with some changes.
635 * </p>
636 *
637 * @return The string representation.
638 * @see #toString
639 */
640 public String toDisplayString() {
641 String str = "";
642 int length;
643
644 length = value.length;
645 if (length > 0) {
646 try {
647 str = new String(value, "US-ASCII");
648 } catch (UnsupportedEncodingException exc) {
649 str = new String(value);
650 }
651 str = str.trim();
652 }
653
654 return str;
655 }
656
657 /**
658 * Returns this Octet as an international display string (text
659 * convension).
660 * It calls AsnOctetsPrintableFace.toInternationalDisplayString().
661 *
662 * See
663 * <a href="http://www.ietf.org/rfc/rfc2790.txt">HOST-RESOURCES-MIB</a>
664 *
665 * @see AsnOctetsPrintableFace#toInternationalDisplayString
666 * @since 4_14
667 */
668 public String toInternationalDisplayString() {
669 return toInternationalDisplayString(printableObject);
670 }
671
672 /**
673 * As toInternationalDisplayString(), but this methods will use this
674 * specific, one-off AsnOctetsPrintableFace object.
675 *
676 * @see #toInternationalDisplayString
677 * @since 4_14
678 */
679 public String toInternationalDisplayString(AsnOctetsPrintableFace face) {
680 return face.toInternationalDisplayString(value);
681 }
682
683 /**
684 * Returns the String representation according to the DateAndTime
685 * convension.
686 * This string it returns is not exactly the same as the
687 * DISPLAY-HINT indicates.
688 * See
689 * <a href="http://www.ietf.org/rfc/rfc2579.txt">SNMPv2-TC</a>
690 *
691 * @since 4_14
692 * @exception RuntimeException Thrown when the number of
693 * Octets does not represent the DateAndTime length.
694 * @see #CALFORMAT
695 */
696 public String toCalendar()
697 throws RuntimeException {
698 Calendar cal = this.getCalendar();
699 Date date = cal.getTime();
700 return CALFORMAT.format(date);
701 }
702
703 /**
704 * Returns the Octets as Calendar according to the DateAndTime text
705 * convension. You can only call this method if
706 * the syntax of this Octet is the DateAndTime text convension.
707 *
708 * @exception RuntimeException Thrown when the number of
709 * Octets does not represent the DateAndTime length.
710 *
711 * @since 4_14
712 * @see #AsnOctets(Calendar)
713 */
714 public Calendar getCalendar()
715 throws RuntimeException {
716 Calendar cal = Calendar.getInstance();
717 if (value.length == 8 || value.length == 11) {
718 int year = (int) ((getPositiveValue(0) * 256) + getPositiveValue(1));
719 // Calendar: 0=January
720 int month = value[2] - 1;
721 int day = value[3];
722 int hour = value[4];
723 int min = value[5];
724 int sec = value[6];
725 int msec = value[7] * 100;
726 cal.set(year, month, day, hour, min, sec);
727 cal.set(Calendar.MILLISECOND, msec);
728
729 if (value.length == 11) {
730 char dir = (char) value[8];
731 int hourUTC = value[9];
732 int minUTC = value[10];
733 int secUTC = (hourUTC * 60) * 60;
734
735 int msecGMT = secUTC * 1000;
736 if (dir == '-') {
737 msecGMT = msecGMT * -1;
738 }
739
740 cal.set(Calendar.ZONE_OFFSET, msecGMT);
741 }
742 } else {
743 throw new RuntimeException("AsnOctets is not DateAndTime");
744 }
745 return cal;
746 }
747
748 /**
749 * Converts this Octet to its corresponding sub-identifiers.
750 * Each octet will be encoded in a separate sub-identifier, by
751 * converting the octet into a positive long.
752 *
753 * <p>
754 * Use this method when building an OID when this Octet specifies a
755 * conceptual row. For example ipNetToMediaEntry, see
756 * <a href="http://www.ietf.org/rfc/rfc2011.txt">IP-MIB</a>
757 * or SnmpCommunityEntry, see
758 * <a href="http://www.ietf.org/rfc/rfc3584.txt">SNMP-COMMUNITY-MIB</a>
759 * </p>
760 *
761 * <p>
762 * The variable <code>length_implied</code> indicates that this MIB variable
763 * is preceded by the IMPLIED keyword:
764 * </p>
765 * <ul>
766 * <li>
767 * The IMPLIED keyword can only be present for an Octet having
768 * a variable-length syntax (e.g., variable-length strings or object
769 * identifier-valued objects).
770 * </li>
771 * <li>
772 * The IMPLIED keyword can only be associated with the last
773 * object in the INDEX clause.
774 * </li>
775 * <li>
776 * The IMPLIED keyword may not be used on a variable-length
777 * string Octet if that string might have a value of zero-length.
778 * </li>
779 * </ul>
780 *
781 * <p>
782 * If the length is implied, no extra sub-identifier will be created to
783 * indicate its length. <br/>
784 * If the length is not implied, the first
785 * sub-identifier will be the length of the Octet.
786 * </p>
787 *
788 * <p>
789 * If this Octet is of type IPADDRESS, length_implied should be false.
790 * </p>
791 *
792 * <p>
793 * The mapping of the INDEX clause is
794 * explained in <a href="http://www.ietf.org/rfc/rfc2578.txt">SNMPv2-SMI</a>,
795 * section 7.7.
796 * </p>
797 *
798 * @param length_implied Indicates if the length of this octet is
799 * implied.
800 *
801 * @see AsnObjectId#add(long[])
802 */
803 public long[] toSubOid(boolean length_implied) {
804 long sub_oid[];
805 int index = 0;
806 int length = value.length;
807
808 if (length_implied) {
809 sub_oid = new long[length];
810 } else {
811 sub_oid = new long[length + 1];
812 sub_oid[0] = length;
813 index++;
814 }
815
816 for (int i = 0; i < length; i++) {
817 sub_oid[index] = getPositiveValue(i);
818 index++;
819 }
820 return sub_oid;
821 }
822
823 /**
824 * Compares this Octet to the specified object.
825 * The result is <code>true</code> if and only if the argument is not
826 * <code>null</code> and is an <code>AsnOctets</code> object that represents
827 * the same sequence of octets as this Octet.
828 *
829 * @param anObject the object to compare this <code>AsnOctets</code>
830 * against.
831 * @return <code>true</code> if the <code>AsnOctets </code>are equal;
832 * <code>false</code> otherwise.
833 */
834 public boolean equals(Object anObject) {
835 if (this == anObject) {
836 return true;
837 }
838 if (anObject instanceof AsnOctets) {
839 AsnOctets anotherOctet = (AsnOctets) anObject;
840 int n = value.length;
841 if (n == anotherOctet.value.length) {
842 byte v1[] = value;
843 byte v2[] = anotherOctet.value;
844 int i = 0;
845 int j = 0;
846 while (n-- != 0) {
847 if (v1[i++] != v2[j++]) {
848 return false;
849 }
850 }
851 return true;
852 }
853 }
854 return false;
855 }
856
857 /**
858 * Returns a hash code for this Octet. The hash code for a
859 * <code>AsnOctets</code> object is computed as
860 * <blockquote>
861 *
862 * <pre>
863 * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
864 * </pre>
865 *
866 * </blockquote>
867 * using <code>int</code> arithmetic, where <code>s[i]</code> is the
868 * <i>i</i>th character of the Octet, <code>n</code> is the length of
869 * the Octet, and <code>^</code> indicates exponentiation.
870 * (The hash value of the empty Octet is zero.)
871 *
872 * @return a hash code value for this Octet.
873 */
874 public int hashCode() {
875 int h = hash;
876 if (h == 0) {
877 int off = 0;
878 byte val[] = value;
879 int len = value.length;
880
881 for (int i = 0; i < len; i++) {
882 h = 31 * h + val[off++];
883 }
884 hash = h;
885 }
886 return h;
887 }
888
889 }