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 }