1. /*
  2. * @(#)file BerEncoder.java
  3. * @(#)author Sun Microsystems, Inc.
  4. * @(#)version 4.16
  5. * @(#)date 04/09/15
  6. *
  7. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  8. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  9. *
  10. */
  11. package com.sun.jmx.snmp;
  12. /**
  13. * The <CODE>BerEncoder</CODE> class is used for encoding data using BER.
  14. *
  15. * A <CODE>BerEncoder</CODE> needs to be set up with a byte buffer. The encoded
  16. * data are stored in this byte buffer.
  17. * <P>
  18. * NOTE : the buffer is filled from end to start. This means the caller
  19. * needs to encode its data in the reverse order.
  20. *
  21. *
  22. * <p><b>This API is a Sun Microsystems internal API and is subject
  23. * to change without notice.</b></p>
  24. * @version 4.16 12/19/03
  25. * @author Sun Microsystems, Inc
  26. *
  27. * @since 1.5
  28. */
  29. public class BerEncoder {
  30. /**
  31. * Constructs a new encoder and attaches it to the specified byte string.
  32. *
  33. * @param b The byte string containing the encoded data.
  34. */
  35. public BerEncoder(byte b[]) {
  36. bytes = b ;
  37. start = b.length ;
  38. stackTop = 0 ;
  39. }
  40. /**
  41. * Trim the encoding data and returns the length of the encoding.
  42. *
  43. * The encoder does backward encoding : so the bytes buffer is
  44. * filled from end to start. The encoded data must be shift before
  45. * the buffer can be used. This is the purpose of the <CODE>trim</CODE> method.
  46. *
  47. * After a call to the <CODE>trim</CODE> method, the encoder is reinitialized and <CODE>putXXX</CODE>
  48. * overwrite any existing encoded data.
  49. *
  50. * @return The length of the encoded data.
  51. */
  52. public int trim() {
  53. final int result = bytes.length - start ;
  54. // for (int i = start ; i < bytes.length ; i++) {
  55. // bytes[i-start] = bytes[i] ;
  56. // }
  57. if (result > 0)
  58. java.lang.System.arraycopy(bytes,start,bytes,0,result);
  59. start = bytes.length ;
  60. stackTop = 0 ;
  61. return result ;
  62. }
  63. /**
  64. * Put an integer.
  65. *
  66. * @param v The integer to encode.
  67. */
  68. public void putInteger(int v) {
  69. putInteger(v, IntegerTag) ;
  70. }
  71. /**
  72. * Put an integer with the specified tag.
  73. *
  74. * @param v The integer to encode.
  75. * @param tag The tag to encode.
  76. */
  77. public void putInteger(int v, int tag) {
  78. putIntegerValue(v) ;
  79. putTag(tag) ;
  80. }
  81. /**
  82. * Put an integer expressed as a long.
  83. *
  84. * @param v The long to encode.
  85. */
  86. public void putInteger(long v) {
  87. putInteger(v, IntegerTag) ;
  88. }
  89. /**
  90. * Put an integer expressed as a long with the specified tag.
  91. *
  92. * @param v The long to encode
  93. * @param tag The tag to encode.
  94. */
  95. public void putInteger(long v, int tag) {
  96. putIntegerValue(v) ;
  97. putTag(tag) ;
  98. }
  99. /**
  100. * Put an octet string.
  101. *
  102. * @param s The bytes to encode
  103. */
  104. public void putOctetString(byte[] s) {
  105. putOctetString(s, OctetStringTag) ;
  106. }
  107. /**
  108. * Put an octet string with a specified tag.
  109. *
  110. * @param s The bytes to encode
  111. * @param tag The tag to encode.
  112. */
  113. public void putOctetString(byte[] s, int tag) {
  114. putStringValue(s) ;
  115. putTag(tag) ;
  116. }
  117. /**
  118. * Put an object identifier.
  119. *
  120. * @param s The oid to encode.
  121. */
  122. public void putOid(long[] s) {
  123. putOid(s, OidTag) ;
  124. }
  125. /**
  126. * Put an object identifier with a specified tag.
  127. *
  128. * @param s The integer to encode.
  129. * @param tag The tag to encode.
  130. */
  131. public void putOid(long[] s, int tag) {
  132. putOidValue(s) ;
  133. putTag(tag) ;
  134. }
  135. /**
  136. * Put a <CODE>NULL</CODE> value.
  137. */
  138. public void putNull() {
  139. putNull(NullTag) ;
  140. }
  141. /**
  142. * Put a <CODE>NULL</CODE> value with a specified tag.
  143. *
  144. * @param tag The tag to encode.
  145. */
  146. public void putNull(int tag) {
  147. putLength(0) ;
  148. putTag(tag) ;
  149. }
  150. /**
  151. * Put an <CODE>ANY</CODE> value. In fact, this method does not encode anything.
  152. * It simply copies the specified bytes into the encoding.
  153. *
  154. * @param s The encoding of the <CODE>ANY</CODE> value.
  155. */
  156. public void putAny(byte[] s) {
  157. putAny(s, s.length) ;
  158. }
  159. /**
  160. * Put an <CODE>ANY</CODE> value. Only the first <CODE>byteCount</CODE> are considered.
  161. *
  162. * @param s The encoding of the <CODE>ANY</CODE> value.
  163. * @param byteCount The number of bytes of the encoding.
  164. */
  165. public void putAny(byte[] s, int byteCount) {
  166. java.lang.System.arraycopy(s,0,bytes,start-byteCount,byteCount);
  167. start -= byteCount;
  168. // for (int i = byteCount - 1 ; i >= 0 ; i--) {
  169. // bytes[--start] = s[i] ;
  170. // }
  171. }
  172. /**
  173. * Open a sequence.
  174. * The encoder push the current position on its stack.
  175. */
  176. public void openSequence() {
  177. stackBuf[stackTop++] = start ;
  178. }
  179. /**
  180. * Close a sequence.
  181. * The decode pull the stack to know the end of the current sequence.
  182. */
  183. public void closeSequence() {
  184. closeSequence(SequenceTag) ;
  185. }
  186. /**
  187. * Close a sequence with the specified tag.
  188. */
  189. public void closeSequence(int tag) {
  190. final int end = stackBuf[--stackTop] ;
  191. putLength(end - start) ;
  192. putTag(tag) ;
  193. }
  194. //
  195. // Some standard tags
  196. //
  197. public final static int BooleanTag = 1 ;
  198. public final static int IntegerTag = 2 ;
  199. public final static int OctetStringTag = 4 ;
  200. public final static int NullTag = 5 ;
  201. public final static int OidTag = 6 ;
  202. public final static int SequenceTag = 0x30 ;
  203. ////////////////////////// PROTECTED ///////////////////////////////
  204. /**
  205. * Put a tag and move the current position backward.
  206. *
  207. * @param tag The tag to encode.
  208. */
  209. protected final void putTag(int tag) {
  210. if (tag < 256) {
  211. bytes[--start] = (byte)tag ;
  212. }
  213. else {
  214. while (tag != 0) {
  215. bytes[--start] = (byte)(tag & 127) ;
  216. tag = tag << 7 ;
  217. }
  218. }
  219. }
  220. /**
  221. * Put a length and move the current position backward.
  222. *
  223. * @param length The length to encode.
  224. */
  225. protected final void putLength(final int length) {
  226. if (length < 0) {
  227. throw new IllegalArgumentException() ;
  228. }
  229. else if (length < 128) {
  230. bytes[--start] = (byte)length ;
  231. }
  232. else if (length < 256) {
  233. bytes[--start] = (byte)length ;
  234. bytes[--start] = (byte)0x81 ;
  235. }
  236. else if (length < 65536) {
  237. bytes[--start] = (byte)(length) ;
  238. bytes[--start] = (byte)(length >> 8) ;
  239. bytes[--start] = (byte)0x82 ;
  240. }
  241. else if (length < 16777126) {
  242. bytes[--start] = (byte)(length) ;
  243. bytes[--start] = (byte)(length >> 8) ;
  244. bytes[--start] = (byte)(length >> 16) ;
  245. bytes[--start] = (byte)0x83 ;
  246. }
  247. else {
  248. bytes[--start] = (byte)(length) ;
  249. bytes[--start] = (byte)(length >> 8) ;
  250. bytes[--start] = (byte)(length >> 16) ;
  251. bytes[--start] = (byte)(length >> 24) ;
  252. bytes[--start] = (byte)0x84 ;
  253. }
  254. }
  255. /**
  256. * Put an integer value and move the current position backward.
  257. *
  258. * @param v The integer to encode.
  259. */
  260. protected final void putIntegerValue(int v) {
  261. final int end = start ;
  262. int mask = 0x7f800000 ;
  263. int byteNeeded = 4 ;
  264. if (v < 0) {
  265. while (((mask & v) == mask) && (byteNeeded > 1)) {
  266. mask = mask >> 8 ;
  267. byteNeeded-- ;
  268. }
  269. }
  270. else {
  271. while (((mask & v) == 0) && (byteNeeded > 1)) {
  272. mask = mask >> 8 ;
  273. byteNeeded-- ;
  274. }
  275. }
  276. for (int i = 0 ; i < byteNeeded ; i++) {
  277. bytes[--start] = (byte)v ;
  278. v = v >> 8 ;
  279. }
  280. putLength(end - start) ;
  281. }
  282. /**
  283. * Put an integer value expressed as a long.
  284. *
  285. * @param v The integer to encode.
  286. */
  287. protected final void putIntegerValue(long v) {
  288. final int end = start ;
  289. long mask = 0x7f80000000000000L ;
  290. int byteNeeded = 8 ;
  291. if (v < 0) {
  292. while (((mask & v) == mask) && (byteNeeded > 1)) {
  293. mask = mask >> 8 ;
  294. byteNeeded-- ;
  295. }
  296. }
  297. else {
  298. while (((mask & v) == 0) && (byteNeeded > 1)) {
  299. mask = mask >> 8 ;
  300. byteNeeded-- ;
  301. }
  302. }
  303. for (int i = 0 ; i < byteNeeded ; i++) {
  304. bytes[--start] = (byte)v ;
  305. v = v >> 8 ;
  306. }
  307. putLength(end - start) ;
  308. }
  309. /**
  310. * Put a byte string and move the current position backward.
  311. *
  312. * @param s The byte string to encode.
  313. */
  314. protected final void putStringValue(byte[] s) {
  315. final int datalen = s.length;
  316. java.lang.System.arraycopy(s,0,bytes,start-datalen,datalen);
  317. start -= datalen;
  318. // for (int i = s.length - 1 ; i >= 0 ; i--) {
  319. // bytes[--start] = s[i] ;
  320. // }
  321. putLength(datalen) ;
  322. }
  323. /**
  324. * Put an oid and move the current position backward.
  325. *
  326. * @param s The oid to encode.
  327. */
  328. protected final void putOidValue(final long[] s) {
  329. final int end = start ;
  330. final int slength = s.length;
  331. // bugId 4641746: 0, 1, and 2 are legal values.
  332. if ((slength < 2) || (s[0] > 2) || (s[1] >= 40)) {
  333. throw new IllegalArgumentException() ;
  334. }
  335. for (int i = slength - 1 ; i >= 2 ; i--) {
  336. long c = s[i] ;
  337. if (c < 0) {
  338. throw new IllegalArgumentException() ;
  339. }
  340. else if (c < 128) {
  341. bytes[--start] = (byte)c ;
  342. }
  343. else {
  344. bytes[--start] = (byte)(c & 127) ;
  345. c = c >> 7 ;
  346. while (c != 0) {
  347. bytes[--start] = (byte)(c | 128) ;
  348. c = c >> 7 ;
  349. }
  350. }
  351. }
  352. bytes[--start] = (byte)(s[0] * 40 + s[1]) ;
  353. putLength(end - start) ;
  354. }
  355. //
  356. // This is the byte array containing the encoding.
  357. //
  358. protected final byte bytes[];
  359. //
  360. // This is the index of the first byte of the encoding.
  361. // It is initialized to <CODE>bytes.length</CODE> and decrease each time
  362. // an value is put in the encoder.
  363. //
  364. protected int start = -1 ;
  365. //
  366. // This is the stack where end of sequences are kept.
  367. // A value is computed and pushed in it each time the <CODE>openSequence</CODE> method
  368. // is invoked.
  369. // A value is pulled and checked each time the <CODE>closeSequence</CODE> method is called.
  370. //
  371. protected final int stackBuf[] = new int[200] ;
  372. protected int stackTop = 0 ;
  373. }