/protocols/asn/asn-impl/src/main/java/org/mobicents/protocols/asn/AsnInputStream.java

http://mobicents.googlecode.com/ · Java · 1046 lines · 632 code · 189 blank · 225 comment · 194 complexity · 6668d8abcdf33164a2f3e8fbe157cb55 MD5 · raw file

  1. /*
  2. * JBoss, Home of Professional Open Source
  3. * Copyright 2011, Red Hat, Inc. and individual contributors
  4. * by the @authors tag. See the copyright.txt in the distribution for a
  5. * full listing of individual contributors.
  6. *
  7. * This is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU Lesser General Public License as
  9. * published by the Free Software Foundation; either version 2.1 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This software is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this software; if not, write to the Free
  19. * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  20. * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  21. */
  22. package org.mobicents.protocols.asn;
  23. import java.io.ByteArrayOutputStream;
  24. import java.io.EOFException;
  25. import java.io.IOException;
  26. import java.io.InputStream;
  27. import java.io.OutputStream;
  28. import java.nio.ByteBuffer;
  29. import java.util.BitSet;
  30. /**
  31. *
  32. * @author amit bhayani
  33. * @author baranowb
  34. * @author sergey vetyutnev
  35. */
  36. public class AsnInputStream extends InputStream {
  37. private static final String _REAL_BASE10_CHARSET = "US-ASCII";
  38. private static final int DATA_BUCKET_SIZE = 1024;
  39. private byte[] buffer;
  40. private int start;
  41. private int length;
  42. private int pos;
  43. private int tagClass = 0;
  44. private int pCBit = 0;
  45. private int tag;
  46. public AsnInputStream( byte[] buf ) {
  47. this.buffer = buf;
  48. this.length = buf.length;
  49. }
  50. public AsnInputStream( byte[] buf, int tagClass, boolean isPrimitive, int tag ) {
  51. this.buffer = buf;
  52. this.length = buf.length;
  53. this.tagClass = tagClass;
  54. if (isPrimitive)
  55. this.pCBit = 0;
  56. else
  57. this.pCBit = 1;
  58. this.tag = tag;
  59. }
  60. protected AsnInputStream( AsnInputStream buf, int start, int length ) throws IOException {
  61. this.buffer = buf.buffer;
  62. this.start = buf.start + start;
  63. this.length = length;
  64. if (start < 0 || start > buf.length || this.start < 0 || this.start > this.buffer.length || this.length < 0
  65. || this.start + this.length > this.buffer.length)
  66. throw new IOException("Bad start or length values when creating AsnInputStream");
  67. this.tagClass = buf.tagClass;
  68. this.pCBit = buf.pCBit;
  69. this.tag = buf.tag;
  70. }
  71. @Deprecated
  72. public AsnInputStream(InputStream in) {
  73. try {
  74. int av = in.available();
  75. byte[] buf = new byte[av];
  76. in.read(buf);
  77. this.buffer = buf;
  78. this.length = buf.length;
  79. } catch (IOException e) {
  80. e.printStackTrace();
  81. this.buffer = new byte[0];
  82. }
  83. }
  84. /**
  85. * Return the current position in the stream
  86. *
  87. * @return
  88. */
  89. public int position() {
  90. return this.pos;
  91. }
  92. /**
  93. * Set the new current position of the stream
  94. * If the new position is bad - throws IOException
  95. *
  96. * @param newPosition
  97. * @throws IOException
  98. */
  99. public void position( int newPosition ) throws IOException {
  100. if (newPosition < 0 || newPosition > this.length)
  101. throw new IOException("Bad newPosition value when setting the new position in the AsnInputStream");
  102. this.pos = newPosition;
  103. }
  104. /**
  105. * Return the count of available bytes to read
  106. *
  107. * @return
  108. */
  109. @Override
  110. public int available() {
  111. return this.length - this.pos;
  112. }
  113. /**
  114. * Advance the stream current position for byteCount bytes
  115. * If the new position is bad - throws IOException
  116. *
  117. * @param byteCount
  118. * @throws IOException
  119. */
  120. public void advance(int byteCount) throws IOException {
  121. this.position(this.pos + byteCount);
  122. }
  123. @Override
  124. public long skip(long n) throws IOException {
  125. if (n < 0)
  126. n = 0;
  127. int newPosition = this.pos + (int) n;
  128. if (newPosition < 0 || newPosition > this.length)
  129. newPosition = this.length;
  130. long skipCnt = newPosition - this.pos;
  131. this.pos = newPosition;
  132. return skipCnt;
  133. }
  134. @Override
  135. public boolean markSupported() {
  136. return false;
  137. }
  138. /**
  139. * Get a byte from stream and return it.
  140. * If end of stream - throws IOException
  141. *
  142. * @return
  143. */
  144. @Override
  145. public int read() throws IOException {
  146. if (this.available() == 0)
  147. throw new EOFException("AsnInputStream has reached the end");
  148. return this.buffer[this.start + this.pos++];
  149. }
  150. /**
  151. * Fill the byte with bytes from the stream. If stream contains not enough
  152. * data - only the part of array is filled
  153. *
  154. * @param b
  155. * The byte array to be filled by data
  156. * @param off
  157. * Offset of byte array from which fill the array
  158. * @param len
  159. * Bytes count to fill
  160. * @return Bytes count that have really read
  161. * @throws IOException
  162. */
  163. @Override
  164. public int read(byte[] b, int off, int len) throws IOException {
  165. if (len > b.length)
  166. len = b.length;
  167. int cnt = this.available();
  168. if (cnt > len)
  169. cnt = len;
  170. if (b == null || off < 0 || len < 0 || off + len > b.length)
  171. throw new EOFException("Target byte array is null or bad off or len values");
  172. System.arraycopy(this.buffer, this.start + this.pos, b, off, cnt);
  173. this.pos += cnt;
  174. return cnt;
  175. }
  176. /**
  177. * Fill the byte with bytes from the stream. If stream contains not enough
  178. * data - only the part of array is filled
  179. *
  180. * @param b
  181. * The byte array to be filled by data
  182. * @return Bytes count that have really read
  183. * @throws IOException
  184. */
  185. @Override
  186. public int read(byte[] b) throws IOException {
  187. if (b == null )
  188. throw new EOFException("Target byte array is null");
  189. return this.read(b, 0, b.length);
  190. }
  191. /**
  192. * Reads the tag field. Returns the tag value.
  193. * Tag class and primitive / constructive mark can be get then by getTagClass() and isTagPrimitive() methods
  194. *
  195. * @return
  196. * @throws IOException
  197. */
  198. public int readTag() throws IOException {
  199. byte b = (byte) this.read();
  200. this.tagClass = (b & Tag.CLASS_MASK) >> 6;
  201. this.pCBit = (b & Tag.PC_MASK) >> 5;
  202. this.tag = b & Tag.TAG_MASK;
  203. // For larger tag values, the first octet has all ones in bits 5 to 1,
  204. // and the tag value is then encoded in
  205. // as many following octets as are needed, using only the least
  206. // significant seven bits of each octet,
  207. // and using the minimum number of octets for the encoding. The most
  208. // significant bit (the "more"
  209. // bit) is set to 1 in the first following octet, and to zero in the
  210. // last.
  211. if (tag == Tag.TAG_MASK) {
  212. byte temp;
  213. tag = 0;
  214. do {
  215. temp = (byte) this.read();
  216. tag = (tag << 7) | (0x7F & temp);
  217. } while (0 != (0x80 & temp));
  218. }
  219. return tag;
  220. }
  221. public int getTagClass() {
  222. return tagClass;
  223. }
  224. public int getTag() {
  225. return tag;
  226. }
  227. public boolean isTagPrimitive() {
  228. return pCBit == Tag.PC_PRIMITIVITE;
  229. }
  230. /**
  231. * Reads and returns the length field.
  232. * In case of indefinite length returns Tag.Indefinite_Length value
  233. *
  234. * @return
  235. * @throws IOException
  236. */
  237. public int readLength() throws IOException {
  238. int length = 0;
  239. byte b = (byte) this.read();
  240. // This is short form. The short form can be used if the number of
  241. // octets in the Value part is less than or
  242. // equal to 127, and can be used whether the Value part is primitive or
  243. // constructed. This form is identified by
  244. // encoding bit 8 as zero, with the length count in bits 7 to 1 (as
  245. // usual, with bit 7 the most significant bit
  246. // of the length).
  247. if ((b & 0x80) == 0) {
  248. return b;
  249. }
  250. // This is indefinite form. The indefinite form of length can only be
  251. // used (but does not have to be) if the V
  252. // part is constructed, that
  253. // is to say, consists of a series of TLVs. In the indefinite form of
  254. // length the first bit of the first octet is
  255. // set to 1, as for the long form, but the value N is set to zero.
  256. b = (byte) (b & 0x7F);
  257. if (b == 0) {
  258. return Tag.Indefinite_Length;
  259. }
  260. // If bit 8 of the first length octet is set to 1, then we have the long
  261. // form of length. In long form, the first
  262. // octet encodes in its remaining seven bits a value N which is the
  263. // length of a series of octets that themselves
  264. // encode the length of the Value part.
  265. byte temp;
  266. for (int i = 0; i < b; i++) {
  267. temp = (byte) this.read();
  268. length = (length << 8) | (0x00FF & temp);
  269. }
  270. return length;
  271. }
  272. /**
  273. * This method can be invoked after the sequence tag has been read
  274. * Returns the AsnInputStream that contains the sequence data
  275. * The origin stream advances to the begin of the next record
  276. *
  277. * @return
  278. * @throws AsnException
  279. * @throws IOException
  280. */
  281. public AsnInputStream readSequenceStream() throws AsnException, IOException {
  282. int length = readLength();
  283. return this.readSequenceStreamData(length);
  284. }
  285. /**
  286. * This method can be invoked after the sequence tag has been read
  287. * Returns the byte array that contains the sequence data
  288. * The origin stream advances to the begin of the next record
  289. *
  290. * @return
  291. * @throws AsnException
  292. * @throws IOException
  293. */
  294. public byte[] readSequence() throws AsnException, IOException {
  295. int length = readLength();
  296. return this.readSequenceData(length);
  297. }
  298. /**
  299. * This method can be invoked after the sequence tag and length has been
  300. * read. Returns the AsnInputStream that contains the sequence data. The origin
  301. * stream advances to the begin of the next record
  302. *
  303. * @param length
  304. * The sequence length
  305. * @return
  306. * @throws AsnException
  307. * @throws IOException
  308. */
  309. public AsnInputStream readSequenceStreamData(int length) throws AsnException, IOException {
  310. if (length == Tag.Indefinite_Length) {
  311. return this.readSequenceIndefinite();
  312. } else {
  313. int startPos = this.pos;
  314. this.advance(length);
  315. return new AsnInputStream(this, startPos, length);
  316. }
  317. }
  318. /**
  319. * This method can be invoked after the sequence tag and length has been
  320. * read. Returns the byte stream that contains the sequence data. The origin
  321. * stream advances to the begin of the next record
  322. *
  323. * @param length
  324. * The sequence length
  325. * @return
  326. * @throws AsnException
  327. * @throws IOException
  328. */
  329. public byte[] readSequenceData(int length) throws AsnException, IOException {
  330. AsnInputStream ais = this.readSequenceStreamData(length);
  331. byte[] res = new byte[ais.length];
  332. System.arraycopy(ais.buffer, ais.start + ais.pos, res, 0, ais.length);
  333. return res;
  334. }
  335. public AsnInputStream readSequenceIndefinite() throws AsnException, IOException {
  336. int startPos = this.pos;
  337. this.advanceIndefiniteLength();
  338. return new AsnInputStream(this, startPos, this.pos - startPos - 2);
  339. }
  340. public byte[] readIndefinite() throws AsnException, IOException {
  341. int startPos = this.pos;
  342. this.advanceIndefiniteLength();
  343. byte[] res = new byte[this.pos - startPos - 2];
  344. System.arraycopy(this.buffer, this.start + startPos, res, 0, this.pos - startPos - 2);
  345. return res;
  346. }
  347. private void advanceIndefiniteLength() throws AsnException, IOException {
  348. while (this.available() > 0) {
  349. // found End-of-contents tag
  350. int tag = this.readTag();
  351. if (tag == 0 && this.tagClass == 0) {
  352. if (this.read() == 0)
  353. return;
  354. else
  355. throw new AsnException("End-of-contents tag must have the zero length");
  356. }
  357. int length = this.readLength();
  358. if (length == Tag.Indefinite_Length)
  359. this.advanceIndefiniteLength();
  360. else
  361. this.advance(length);
  362. }
  363. }
  364. /**
  365. * Skip length and content fields of primitive and constructed element (definite and indefinite length supported)
  366. *
  367. * @throws IOException
  368. * @throws AsnException
  369. */
  370. public void advanceElement() throws IOException, AsnException {
  371. int length = this.readLength();
  372. this.advanceElementData(length);
  373. }
  374. /**
  375. * Skip content field of primitive and constructed element (definite and indefinite length supported)
  376. *
  377. * @param length
  378. * @throws IOException
  379. * @throws AsnException
  380. */
  381. public void advanceElementData(int length) throws IOException, AsnException {
  382. if( length==Tag.Indefinite_Length )
  383. this.advanceIndefiniteLength();
  384. else
  385. this.advance(length);
  386. }
  387. public boolean readBoolean() throws AsnException, IOException {
  388. int length = readLength();
  389. return this.readBooleanData(length);
  390. }
  391. public boolean readBooleanData(int length) throws AsnException, IOException {
  392. if (this.pCBit != 0 || length != 1)
  393. throw new AsnException("Failed when parsing the Boolean field: this field must be primitive and the length must be equal 1");
  394. byte temp = (byte) this.read();
  395. // If temp is not zero stands for true irrespective of actual Value
  396. return (temp != 0);
  397. }
  398. public long readInteger() throws AsnException, IOException {
  399. int length = this.readLength();
  400. return this.readIntegerData(length);
  401. }
  402. public long readIntegerData(int length) throws AsnException, IOException {
  403. long value = 0;
  404. byte temp;
  405. if (this.pCBit != 0 || length == 0 || length == Tag.Indefinite_Length)
  406. throw new AsnException("Failed when parsing the Interger field: this field must be primitive and have the length more then zero");
  407. temp = (byte) this.read();
  408. value = temp;
  409. for (int i = 0; i < length - 1; i++) {
  410. temp = (byte) this.read();
  411. value = (value << 8) | (0x00FF & temp);
  412. }
  413. return value;
  414. }
  415. public double readReal() throws AsnException, IOException {
  416. int length = readLength();
  417. return readRealData(length);
  418. }
  419. public double readRealData(int length) throws AsnException, IOException {
  420. if (this.pCBit != 0 || length == Tag.Indefinite_Length)
  421. throw new AsnException("Failed when parsing the Real field: this field must be primitive");
  422. // universal part
  423. if (length == 0) {
  424. // yeah, nice
  425. return 0.0;
  426. }
  427. if (length == 1) {
  428. // +INF/-INF
  429. int b = this.read() & 0xFF;
  430. if (b == 0x40) {
  431. return Double.POSITIVE_INFINITY;
  432. } else if (b == 0x41) {
  433. return Double.NEGATIVE_INFINITY;
  434. } else {
  435. throw new AsnException(
  436. "Failed when parsing the Real field: Real length indicates positive/negative infinity, but value is wrong: "
  437. + Integer.toBinaryString(b));
  438. }
  439. }
  440. int infoBits = this.read();
  441. // substract on for info bits
  442. length--;
  443. // only binary has first bit of info set to 1;
  444. // now the tricky part, this takes into account base10
  445. if ((infoBits & 0xC0) == 0) {
  446. // FIXME: add check on boundry of simple length
  447. // encoded as char string
  448. // IA5 == ASCII...?
  449. // .............................
  450. String nrRep = new String(this.buffer, this.start + this.pos, length, _REAL_BASE10_CHARSET);
  451. // this will swallow NR(1-3) and give proper double :)
  452. return Double.parseDouble(nrRep);
  453. // .............................
  454. } else if((infoBits & 0x80) == 0x80) {
  455. // encoded binary - mantisa and all that funny digits.
  456. // the REAL type has been semantically equivalent to the
  457. // type:
  458. // [UNIVERSAL 9] IMPLICIT SEQUENCE {
  459. // mantissa INTEGER (ALL EXCEPT 0),
  460. // base INTEGER (2|10),
  461. // exponent INTEGER }
  462. // sign x N x (2 ^ scale) x (base ^ E); --> base ^ E == 2 ^(E+x) ==
  463. // where x
  464. int tmp = 0;
  465. int signBit = (infoBits & BERStatics.REAL_BB_SIGN_MASK) << 1;
  466. // now lets determine length of e(exponent) and n(positive integer)
  467. long e = 0;
  468. int s = (infoBits & BERStatics.REAL_BB_SCALE_MASK) >> 2;
  469. tmp = infoBits & BERStatics.REAL_BB_EE_MASK;
  470. if (tmp == 0x0) {
  471. e = this.read() & 0xFF;
  472. length--;
  473. // real representation
  474. } else if (tmp == 0x01) {
  475. e = (this.read() & 0xFF) << 8;
  476. length--;
  477. e |= this.read() & 0xFF;
  478. length--;
  479. if (e > 0x7FF) {
  480. // to many bits... Double
  481. throw new AsnException(
  482. "Exponent part has to many bits lit, allowed are 11, present: "
  483. + Long.toBinaryString(e));
  484. }
  485. // prepare E to become bits - this may cause loose of data,
  486. e &= 0x7FF;
  487. } else {
  488. // this is too big for java to handle.... we can have up to 11
  489. // bits..
  490. throw new AsnException(
  491. "Exponent part has to many bits lit, allowed are 11, but stream indicates 3 or more octets");
  492. }
  493. // now we may read up to 52bits
  494. // 7*8 == 56, we need up to 52
  495. if (length > 7) {
  496. throw new AsnException(
  497. "Length exceeds JAVA double mantisa size");
  498. }
  499. long n = 0;
  500. while (length > 0) {
  501. --length;
  502. long readV = (((long) this.read() << 32) >>> 32) & 0xFF;
  503. readV = readV << (length * 8);
  504. n |= readV;
  505. }
  506. // check for possible overflow
  507. if ((n & 0x0FFFFFFF) > 4503599627370495L) { // num is 11 bits lit to
  508. // "1"
  509. throw new AsnException("Overflow on mantisa");
  510. }
  511. // we have real part, now lets add that scale; this is M x (2^F),
  512. // which essentialy is bit shift :)
  513. int shift = (int) Math.pow(2, s) - 1; // -1 for 2, where we dont
  514. // shift
  515. n = n << (shift); // this might be bad code.
  516. // now lets take care of different base, we are base2: base8 ==
  517. // base2^3,base16== base2^4
  518. int base = (infoBits & BERStatics.REAL_BB_BASE_MASK) >> 4;
  519. // is this correct?
  520. if (base == 0x01) {
  521. e = e * 3; // (2^3)^e
  522. } else if (base == 0x10) {
  523. e = e * 4; // (2^4)^e
  524. }
  525. // do check again.
  526. if (e > 0x7FF) {
  527. // to many bits... Double
  528. throw new AsnException(
  529. "Exponent part has to many bits lit, allowed are 11, present: "
  530. + Long.toBinaryString(e));
  531. }
  532. // double is 8bytes
  533. byte[] doubleRep = new byte[8];
  534. // set sign, no need to shift
  535. doubleRep[0] = (byte) (signBit);
  536. // now get first 7 bits of e;
  537. doubleRep[0] |= ((e >> 4) & 0xFF);
  538. doubleRep[1] = (byte) ((e & 0x0F) << 4);
  539. // from back its easier
  540. doubleRep[7] = (byte) n;
  541. doubleRep[6] = (byte) (n >> 8);
  542. doubleRep[5] = (byte) (n >> 16);
  543. doubleRep[4] = (byte) (n >> 24);
  544. doubleRep[3] = (byte) (n >> 32);
  545. doubleRep[2] = (byte) (n >> 40);
  546. doubleRep[1] |= (byte) ((n >> 48) & 0x0F);
  547. ByteBuffer bb = ByteBuffer.wrap(doubleRep);
  548. return bb.getDouble();
  549. } else {
  550. throw new AsnException("Failed when parsing the Real field: Unknown infoBits: " + infoBits);
  551. }
  552. }
  553. public BitSetStrictLength readBitString() throws AsnException, IOException {
  554. int length = this.readLength();
  555. return this.readBitStringData(length);
  556. }
  557. public BitSetStrictLength readBitStringData(int length) throws AsnException, IOException {
  558. BitSetStrictLength bitSet = new BitSetStrictLength(0);
  559. int bitCount = this._readBitString(bitSet, length, 0);
  560. bitSet.setStrictLength(bitCount);
  561. return bitSet;
  562. }
  563. @Deprecated
  564. public void readBitString(BitSet bitSet) throws AsnException, IOException {
  565. int length = this.readLength();
  566. this.readBitStringData(bitSet, length);
  567. }
  568. @Deprecated
  569. public void readBitStringData(BitSet bitSet, int length) throws AsnException, IOException {
  570. this._readBitString(bitSet, length, 0);
  571. }
  572. @Deprecated
  573. public void readBitStringData(BitSet bitSet, int length, boolean isTagPrimitive) throws AsnException, IOException {
  574. if (isTagPrimitive)
  575. this.pCBit = 0;
  576. else
  577. this.pCBit = 1;
  578. this._readBitString(bitSet, length, 0);
  579. }
  580. private int _readBitString(BitSet bitSet, int length, int counter) throws AsnException,
  581. IOException {
  582. int bits = 0;
  583. if (this.pCBit == 0) {
  584. int pad = this.read();
  585. // TODO We are assuming that there is always pad, even if it is 00.
  586. // This may not be true for some
  587. // Constructed
  588. // BitString where padding is only applied to last TLV. In which
  589. // case this algo is incorrect
  590. for (int count = 1; count < (length - 1); count++) {
  591. byte dataByte = (byte) this.read();
  592. for (bits = 0; bits < 8; bits++) {
  593. if (0 != (dataByte & (0x80 >> bits))) {
  594. bitSet.set(counter);
  595. }
  596. ++counter;
  597. }
  598. }
  599. byte lastByte = (byte) this.read();
  600. for (bits = 0; bits < (8 - pad); bits++) {
  601. if (0 != (lastByte & (0x80 >> bits))) {
  602. bitSet.set(counter);
  603. }
  604. ++counter;
  605. }
  606. return counter;
  607. } else {
  608. if (length == Tag.Indefinite_Length) {
  609. while (true) {
  610. int tag = this.readTag();
  611. if (tag == 0) {
  612. length = this.read();
  613. if (length == 0)
  614. break;
  615. else
  616. throw new AsnException("Error while decoding the bit-string: End-of-contents tag must have the zero length");
  617. }
  618. if (tag != Tag.STRING_BIT || this.tagClass != Tag.CLASS_UNIVERSAL)
  619. throw new AsnException("Error while decoding the bit-string: subsequent bit string tag must be CLASS_UNIVERSAL - STRING_BIT");
  620. int length2 = this.readLength();
  621. counter = _readBitString(bitSet, length2, counter);
  622. }
  623. } else {
  624. int startPos = this.pos;
  625. while (true) {
  626. if (this.pos > startPos + length)
  627. throw new AsnException("Error while decoding the bit-string: constructed bit-string content do not fit its length");
  628. if (this.pos == startPos + length)
  629. break;
  630. int tag = this.readTag();
  631. if (tag != Tag.STRING_BIT || this.tagClass != Tag.CLASS_UNIVERSAL)
  632. throw new AsnException("Error while decoding the bit-string: subsequent bit string string tag must be CLASS_UNIVERSAL - STRING_BIT");
  633. int length2 = this.readLength();
  634. if (this.pos + length2 > startPos + length)
  635. throw new AsnException("Error while decoding the bit-string: subsequent bit string is unconsistent");
  636. counter = _readBitString(bitSet, length2, counter);
  637. }
  638. }
  639. return counter;
  640. }
  641. }
  642. public byte[] readOctetString() throws AsnException, IOException {
  643. int length = this.readLength();
  644. return this.readOctetStringData(length);
  645. }
  646. @Deprecated
  647. public void readOctetString(OutputStream outputStream) throws AsnException, IOException {
  648. int length = this.readLength();
  649. this.readOctetStringData(outputStream, length);
  650. }
  651. public byte[] readOctetStringData(int length) throws AsnException, IOException {
  652. if (this.pCBit == 0) {
  653. if (length == Tag.Indefinite_Length)
  654. throw new AsnException("Error while decoding the octet-string: primitive with Indefinite_Length");
  655. byte[] buf = new byte[length];
  656. int cnt = this.read(buf);
  657. if (cnt != length)
  658. throw new AsnException("Error while decoding the octet-string: not enouph data for the octet string");
  659. return buf;
  660. } else {
  661. ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
  662. this._readOctetString(outputStream, length);
  663. return outputStream.toByteArray();
  664. }
  665. }
  666. @Deprecated
  667. public void readOctetStringData(OutputStream outputStream, int length) throws AsnException, IOException {
  668. this._readOctetString(outputStream, length);
  669. }
  670. @Deprecated
  671. public void readOctetStringData(OutputStream outputStream, int length, boolean isTagPrimitive) throws AsnException, IOException {
  672. if (isTagPrimitive)
  673. this.pCBit = 0;
  674. else
  675. this.pCBit = 1;
  676. this._readOctetString(outputStream, length);
  677. }
  678. private void _readOctetString(OutputStream outputStream, int length) throws AsnException, IOException {
  679. if (this.pCBit == 0) {
  680. this.fillOutputStream(outputStream, length);
  681. } else {
  682. if (length == Tag.Indefinite_Length) {
  683. while (true) {
  684. int tag = this.readTag();
  685. if (tag == 0) {
  686. length = this.read();
  687. if (length == 0)
  688. break;
  689. else
  690. throw new AsnException("Error while decoding the octet-string: End-of-contents tag must have the zero length");
  691. }
  692. if (tag != Tag.STRING_OCTET || this.tagClass != Tag.CLASS_UNIVERSAL)
  693. throw new AsnException("Error while decoding the octet-string: subsequent octet string tag must be CLASS_UNIVERSAL - STRING_BIT");
  694. int length2 = this.readLength();
  695. this._readOctetString(outputStream, length2);
  696. }
  697. } else {
  698. int startPos = this.pos;
  699. while (true) {
  700. if (this.pos == startPos + length)
  701. break;
  702. int tag = this.readTag();
  703. if (tag != Tag.STRING_OCTET || this.tagClass != Tag.CLASS_UNIVERSAL)
  704. throw new AsnException("Error while decoding the octet-string: subsequent octet string string tag must be CLASS_UNIVERSAL - STRING_BIT");
  705. int length2 = this.readLength();
  706. if (this.pos + length2 > startPos + length)
  707. throw new AsnException("Error while decoding the octet-string: subsequent octet string is unconsistent");
  708. this._readOctetString(outputStream, length2);
  709. }
  710. }
  711. }
  712. }
  713. // private helper methods -------------------------------------------------
  714. private void fillOutputStream(OutputStream stream, int length)
  715. throws AsnException, IOException {
  716. byte[] dataBucket = new byte[DATA_BUCKET_SIZE];
  717. int readCount;
  718. while (length != 0) {
  719. int cnt = length < DATA_BUCKET_SIZE ? length : DATA_BUCKET_SIZE;
  720. readCount = read(dataBucket, 0, cnt);
  721. if (readCount < cnt)
  722. throw new AsnException("input stream has reached the end");
  723. stream.write(dataBucket, 0, readCount);
  724. length -= readCount;
  725. }
  726. }
  727. public void readNull() throws AsnException, IOException {
  728. // int tagValue = this.readTag();
  729. int length = readLength();
  730. this.readNullData(length);
  731. }
  732. public void readNullData(int length) throws AsnException, IOException {
  733. if (this.pCBit != 0 || length != 0)
  734. throw new AsnException("Failed when parsing the NULL field: this field must be primitive and the length must be equal 0");
  735. }
  736. public long[] readObjectIdentifier() throws AsnException, IOException {
  737. int length = readLength();
  738. return this.readObjectIdentifierData(length);
  739. }
  740. public long[] readObjectIdentifierData(int length) throws AsnException, IOException {
  741. if (this.pCBit != 0 || length == Tag.Indefinite_Length)
  742. throw new AsnException("Failed when parsing the ObjectIdentifier field: this field must be primitive and the length must be defined");
  743. byte[] data = new byte[length];
  744. read(data);
  745. length = 2;
  746. for (int i = 1; i < data.length; ++i) {
  747. if (data[i] >= 0)
  748. ++length;
  749. }
  750. long[] oids = new long[length];
  751. int b = 0x00FF & data[0];
  752. // The first octet has value 40 * value1 + value2.
  753. oids[0] = b / 40;
  754. if (oids[0] == 0 || oids[0] == 1)
  755. oids[1] = b % 40;
  756. else {
  757. oids[0] = 2;
  758. oids[1] = b - 80;
  759. }
  760. int v = 0;
  761. length = 2;
  762. for (int i = 1; i < data.length; ++i) {
  763. byte b1 = data[i];
  764. if ((b1 & 0x80) != 0x0) {
  765. v = (v << 7) | ((b1 & 0x7F));
  766. } else {
  767. v = (v << 7) | (b1 & 0x7F);
  768. oids[length++] = v;
  769. v = 0;
  770. }
  771. }
  772. if (length == oids.length)
  773. return oids;
  774. else {
  775. long[] oids2 = new long[length];
  776. System.arraycopy(oids, 0, oids2, 0, length);
  777. return oids2;
  778. }
  779. }
  780. public String readIA5String() throws AsnException, IOException {
  781. int length = readLength();
  782. return readString(BERStatics.STRING_IA5_ENCODING, Tag.STRING_IA5, length);
  783. }
  784. public String readIA5StringData(int length) throws AsnException, IOException {
  785. return readString(BERStatics.STRING_IA5_ENCODING, Tag.STRING_IA5, length);
  786. }
  787. public String readUTF8String() throws AsnException, IOException {
  788. int length = readLength();
  789. return readString(BERStatics.STRING_UTF8_ENCODING, Tag.STRING_UTF8, length);
  790. }
  791. public String readUTF8StringData(int length) throws AsnException, IOException {
  792. return readString(BERStatics.STRING_UTF8_ENCODING, Tag.STRING_UTF8, length);
  793. }
  794. public String readGraphicString() throws AsnException, IOException {
  795. int length = readLength();
  796. return readString(BERStatics.STRING_IA5_ENCODING, Tag.STRING_GRAPHIC, length);
  797. }
  798. public String readGraphicStringData(int length) throws AsnException, IOException {
  799. return readString(BERStatics.STRING_IA5_ENCODING, Tag.STRING_GRAPHIC, length);
  800. }
  801. private String readString(String charset, int tagValue, int length) throws IOException,
  802. AsnException {
  803. if (pCBit == 0) {
  804. byte[] buf = new byte[length];
  805. int readCnt = this.read(buf);
  806. if (readCnt < length)
  807. throw new AsnException("Error decoding string fieald: not enough data in the stream");
  808. String s = new String(buf, charset);
  809. return s;
  810. } else {
  811. ByteArrayOutputStream bos = new ByteArrayOutputStream();
  812. this.readConstructedString(bos, tagValue, length);
  813. String s = new String(bos.toByteArray(), charset);
  814. return s;
  815. }
  816. }
  817. private void readConstructedString(ByteArrayOutputStream bos, int parentTag, int length)
  818. throws AsnException, IOException {
  819. AsnInputStream ais = this.readSequenceStreamData(length);
  820. while(true) {
  821. if (ais.available() == 0)
  822. break;
  823. int localTag = ais.readTag();
  824. if (parentTag != localTag)
  825. throw new AsnException("Error decoding string fieald: Parent tag=" + parentTag + ", does not match member tag=" + localTag);
  826. int localLength = ais.readLength();
  827. if (ais.pCBit == 0) {
  828. byte[] buf = new byte[localLength];
  829. int readCnt = ais.read(buf);
  830. if (readCnt < localLength)
  831. throw new AsnException("Error decoding string fieald: not enough data in the stream");
  832. bos.write(buf);
  833. } else {
  834. ais.readConstructedString(bos, parentTag, localLength);
  835. }
  836. }
  837. }
  838. @Override
  839. public String toString() {
  840. StringBuilder sb = new StringBuilder();
  841. sb.append("Size=");
  842. sb.append(this.length);
  843. sb.append(", Pos=");
  844. sb.append(this.pos);
  845. sb.append(", Tag=");
  846. sb.append(this.tag);
  847. sb.append(", TagClass=");
  848. sb.append(this.tagClass);
  849. sb.append(", pCBit=");
  850. sb.append(this.pCBit);
  851. sb.append("\n");
  852. byte[] bf = new byte[this.length];
  853. System.arraycopy(this.buffer, this.start, bf, 0, this.length);
  854. sb.append(AsnOutputStream.arrayToString(bf));
  855. return sb.toString();
  856. }
  857. }