1 /* 2 * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 27 package com.sun.jmx.snmp; 28 29 30 /** 31 * The <CODE>BerEncoder</CODE> class is used for encoding data using BER. 32 * 33 * A <CODE>BerEncoder</CODE> needs to be set up with a byte buffer. The encoded 34 * data are stored in this byte buffer. 35 * <P> 36 * NOTE : the buffer is filled from end to start. This means the caller 37 * needs to encode its data in the reverse order. 38 * 39 * 40 * <p><b>This API is a Sun Microsystems internal API and is subject 41 * to change without notice.</b></p> 42 * 43 * @since 1.5 44 */ 45 46 public class BerEncoder { 47 48 /** 49 * Constructs a new encoder and attaches it to the specified byte string. 50 * 51 * @param b The byte string containing the encoded data. 52 */ 53 54 public BerEncoder(byte b[]) { 55 bytes = b ; 56 start = b.length ; 57 stackTop = 0 ; 58 } 59 60 61 /** 62 * Trim the encoding data and returns the length of the encoding. 63 * 64 * The encoder does backward encoding : so the bytes buffer is 65 * filled from end to start. The encoded data must be shift before 66 * the buffer can be used. This is the purpose of the <CODE>trim</CODE> method. 67 * 68 * After a call to the <CODE>trim</CODE> method, the encoder is reinitialized and <CODE>putXXX</CODE> 69 * overwrite any existing encoded data. 70 * 71 * @return The length of the encoded data. 72 */ 73 74 public int trim() { 75 final int result = bytes.length - start ; 76 77 // for (int i = start ; i < bytes.length ; i++) { 78 // bytes[i-start] = bytes[i] ; 79 // } 80 if (result > 0) 81 java.lang.System.arraycopy(bytes,start,bytes,0,result); 82 83 start = bytes.length ; 84 stackTop = 0 ; 85 86 return result ; 87 } 88 89 /** 90 * Put an integer. 91 * 92 * @param v The integer to encode. 93 */ 94 95 public void putInteger(int v) { 96 putInteger(v, IntegerTag) ; 97 } 98 99 100 /** 101 * Put an integer with the specified tag. 102 * 103 * @param v The integer to encode. 104 * @param tag The tag to encode. 105 */ 106 107 public void putInteger(int v, int tag) { 108 putIntegerValue(v) ; 109 putTag(tag) ; 110 } 111 112 113 114 /** 115 * Put an integer expressed as a long. 116 * 117 * @param v The long to encode. 118 */ 119 120 public void putInteger(long v) { 121 putInteger(v, IntegerTag) ; 122 } 123 124 125 /** 126 * Put an integer expressed as a long with the specified tag. 127 * 128 * @param v The long to encode 129 * @param tag The tag to encode. 130 */ 131 132 public void putInteger(long v, int tag) { 133 putIntegerValue(v) ; 134 putTag(tag) ; 135 } 136 137 138 139 /** 140 * Put an octet string. 141 * 142 * @param s The bytes to encode 143 */ 144 145 public void putOctetString(byte[] s) { 146 putOctetString(s, OctetStringTag) ; 147 } 148 149 150 /** 151 * Put an octet string with a specified tag. 152 * 153 * @param s The bytes to encode 154 * @param tag The tag to encode. 155 */ 156 157 public void putOctetString(byte[] s, int tag) { 158 putStringValue(s) ; 159 putTag(tag) ; 160 } 161 162 163 /** 164 * Put an object identifier. 165 * 166 * @param s The oid to encode. 167 */ 168 169 public void putOid(long[] s) { 170 putOid(s, OidTag) ; 171 } 172 173 174 /** 175 * Put an object identifier with a specified tag. 176 * 177 * @param s The integer to encode. 178 * @param tag The tag to encode. 179 */ 180 181 public void putOid(long[] s, int tag) { 182 putOidValue(s) ; 183 putTag(tag) ; 184 } 185 186 187 /** 188 * Put a <CODE>NULL</CODE> value. 189 */ 190 191 public void putNull() { 192 putNull(NullTag) ; 193 } 194 195 196 /** 197 * Put a <CODE>NULL</CODE> value with a specified tag. 198 * 199 * @param tag The tag to encode. 200 */ 201 202 public void putNull(int tag) { 203 putLength(0) ; 204 putTag(tag) ; 205 } 206 207 208 209 /** 210 * Put an <CODE>ANY</CODE> value. In fact, this method does not encode anything. 211 * It simply copies the specified bytes into the encoding. 212 * 213 * @param s The encoding of the <CODE>ANY</CODE> value. 214 */ 215 216 public void putAny(byte[] s) { 217 putAny(s, s.length) ; 218 } 219 220 221 /** 222 * Put an <CODE>ANY</CODE> value. Only the first <CODE>byteCount</CODE> are considered. 223 * 224 * @param s The encoding of the <CODE>ANY</CODE> value. 225 * @param byteCount The number of bytes of the encoding. 226 */ 227 228 public void putAny(byte[] s, int byteCount) { 229 java.lang.System.arraycopy(s,0,bytes,start-byteCount,byteCount); 230 start -= byteCount; 231 // for (int i = byteCount - 1 ; i >= 0 ; i--) { 232 // bytes[--start] = s[i] ; 233 // } 234 } 235 236 237 /** 238 * Open a sequence. 239 * The encoder push the current position on its stack. 240 */ 241 242 public void openSequence() { 243 stackBuf[stackTop++] = start ; 244 } 245 246 247 /** 248 * Close a sequence. 249 * The decode pull the stack to know the end of the current sequence. 250 */ 251 252 public void closeSequence() { 253 closeSequence(SequenceTag) ; 254 } 255 256 257 /** 258 * Close a sequence with the specified tag. 259 */ 260 261 public void closeSequence(int tag) { 262 final int end = stackBuf[--stackTop] ; 263 putLength(end - start) ; 264 putTag(tag) ; 265 } 266 267 268 // 269 // Some standard tags 270 // 271 public final static int BooleanTag = 1 ; 272 public final static int IntegerTag = 2 ; 273 public final static int OctetStringTag = 4 ; 274 public final static int NullTag = 5 ; 275 public final static int OidTag = 6 ; 276 public final static int SequenceTag = 0x30 ; 277 278 279 280 281 ////////////////////////// PROTECTED /////////////////////////////// 282 283 284 285 /** 286 * Put a tag and move the current position backward. 287 * 288 * @param tag The tag to encode. 289 */ 290 291 protected final void putTag(int tag) { 292 if (tag < 256) { 293 bytes[--start] = (byte)tag ; 294 } 295 else { 296 while (tag != 0) { 297 bytes[--start] = (byte)(tag & 127) ; 298 tag = tag << 7 ; 299 } 300 } 301 } 302 303 304 /** 305 * Put a length and move the current position backward. 306 * 307 * @param length The length to encode. 308 */ 309 310 protected final void putLength(final int length) { 311 if (length < 0) { 312 throw new IllegalArgumentException() ; 313 } 314 else if (length < 128) { 315 bytes[--start] = (byte)length ; 316 } 317 else if (length < 256) { 318 bytes[--start] = (byte)length ; 319 bytes[--start] = (byte)0x81 ; 320 } 321 else if (length < 65536) { 322 bytes[--start] = (byte)(length) ; 323 bytes[--start] = (byte)(length >> 8) ; 324 bytes[--start] = (byte)0x82 ; 325 } 326 else if (length < 16777126) { 327 bytes[--start] = (byte)(length) ; 328 bytes[--start] = (byte)(length >> 8) ; 329 bytes[--start] = (byte)(length >> 16) ; 330 bytes[--start] = (byte)0x83 ; 331 } 332 else { 333 bytes[--start] = (byte)(length) ; 334 bytes[--start] = (byte)(length >> 8) ; 335 bytes[--start] = (byte)(length >> 16) ; 336 bytes[--start] = (byte)(length >> 24) ; 337 bytes[--start] = (byte)0x84 ; 338 } 339 } 340 341 342 /** 343 * Put an integer value and move the current position backward. 344 * 345 * @param v The integer to encode. 346 */ 347 348 protected final void putIntegerValue(int v) { 349 final int end = start ; 350 int mask = 0x7f800000 ; 351 int byteNeeded = 4 ; 352 if (v < 0) { 353 while (((mask & v) == mask) && (byteNeeded > 1)) { 354 mask = mask >> 8 ; 355 byteNeeded-- ; 356 } 357 } 358 else { 359 while (((mask & v) == 0) && (byteNeeded > 1)) { 360 mask = mask >> 8 ; 361 byteNeeded-- ; 362 } 363 } 364 for (int i = 0 ; i < byteNeeded ; i++) { 365 bytes[--start] = (byte)v ; 366 v = v >> 8 ; 367 } 368 putLength(end - start) ; 369 } 370 371 372 /** 373 * Put an integer value expressed as a long. 374 * 375 * @param v The integer to encode. 376 */ 377 378 protected final void putIntegerValue(long v) { 379 final int end = start ; 380 long mask = 0x7f80000000000000L ; 381 int byteNeeded = 8 ; 382 if (v < 0) { 383 while (((mask & v) == mask) && (byteNeeded > 1)) { 384 mask = mask >> 8 ; 385 byteNeeded-- ; 386 } 387 } 388 else { 389 while (((mask & v) == 0) && (byteNeeded > 1)) { 390 mask = mask >> 8 ; 391 byteNeeded-- ; 392 } 393 } 394 for (int i = 0 ; i < byteNeeded ; i++) { 395 bytes[--start] = (byte)v ; 396 v = v >> 8 ; 397 } 398 putLength(end - start) ; 399 } 400 401 402 /** 403 * Put a byte string and move the current position backward. 404 * 405 * @param s The byte string to encode. 406 */ 407 408 protected final void putStringValue(byte[] s) { 409 final int datalen = s.length; 410 java.lang.System.arraycopy(s,0,bytes,start-datalen,datalen); 411 start -= datalen; 412 // for (int i = s.length - 1 ; i >= 0 ; i--) { 413 // bytes[--start] = s[i] ; 414 // } 415 putLength(datalen) ; 416 } 417 418 419 420 /** 421 * Put an oid and move the current position backward. 422 * 423 * @param s The oid to encode. 424 */ 425 426 protected final void putOidValue(final long[] s) { 427 final int end = start ; 428 final int slength = s.length; 429 430 // bugId 4641746: 0, 1, and 2 are legal values. 431 if ((slength < 2) || (s[0] > 2) || (s[1] >= 40)) { 432 throw new IllegalArgumentException() ; 433 } 434 for (int i = slength - 1 ; i >= 2 ; i--) { 435 long c = s[i] ; 436 if (c < 0) { 437 throw new IllegalArgumentException() ; 438 } 439 else if (c < 128) { 440 bytes[--start] = (byte)c ; 441 } 442 else { 443 bytes[--start] = (byte)(c & 127) ; 444 c = c >> 7 ; 445 while (c != 0) { 446 bytes[--start] = (byte)(c | 128) ; 447 c = c >> 7 ; 448 } 449 } 450 } 451 bytes[--start] = (byte)(s[0] * 40 + s[1]) ; 452 putLength(end - start) ; 453 } 454 455 456 // 457 // This is the byte array containing the encoding. 458 // 459 protected final byte bytes[]; 460 461 // 462 // This is the index of the first byte of the encoding. 463 // It is initialized to <CODE>bytes.length</CODE> and decrease each time 464 // an value is put in the encoder. 465 // 466 protected int start = -1 ; 467 468 // 469 // This is the stack where end of sequences are kept. 470 // A value is computed and pushed in it each time the <CODE>openSequence</CODE> method 471 // is invoked. 472 // A value is pulled and checked each time the <CODE>closeSequence</CODE> method is called. 473 // 474 protected final int stackBuf[] = new int[200] ; 475 protected int stackTop = 0 ; 476 477 }