001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: /**
019: * @author Vladimir N. Molotkov, Stepan M. Mishura
020: * @version $Revision$
021: */package org.apache.harmony.security.asn1;
022:
023: import java.io.IOException;
024:
025: import org.apache.harmony.security.internal.nls.Messages;
026:
027: /**
028: * This class represents ASN.1 Bitstring type.
029: *
030: * @see http://asn1.elibel.tm.fr/en/standards/index.htm
031: */
032:
033: public class ASN1BitString extends ASN1StringType {
034:
035: // default implementation
036: private static final ASN1BitString ASN1 = new ASN1BitString();
037:
038: /**
039: * Constructs ASN.1 Bitstring type
040: *
041: * The constructor is provided for inheritance purposes
042: * when there is a need to create a custom ASN.1 Bitstring type.
043: * To get a default implementation it is recommended to use
044: * getInstance() method.
045: */
046: public ASN1BitString() {
047: super (TAG_BITSTRING);
048: }
049:
050: /**
051: * Returns ASN.1 Bitstring type default implementation
052: *
053: * The default implementation works with encoding
054: * that is represented as BitString object.
055: *
056: * @return ASN.1 Bitstring type default implementation
057: * @see org.apache.harmony.security.asn1.BitString
058: */
059: public static ASN1BitString getInstance() {
060: return ASN1;
061: }
062:
063: //
064: //
065: // Decode
066: //
067: //
068:
069: public Object decode(BerInputStream in) throws IOException {
070:
071: in.readBitString();
072:
073: if (in.isVerify) {
074: return null;
075: }
076: return getDecodedObject(in);
077: }
078:
079: /**
080: * Extracts BitString object from BER input stream.
081: *
082: * @param in - BER input stream
083: * @return BitString object
084: */
085: public Object getDecodedObject(BerInputStream in)
086: throws IOException {
087: byte[] bytes = new byte[in.length - 1];
088: System.arraycopy(in.buffer, in.contentOffset + 1, bytes, 0,
089: in.length - 1);
090: return new BitString(bytes, in.buffer[in.contentOffset]);
091: }
092:
093: //
094: // Encode
095: //
096:
097: public void encodeContent(BerOutputStream out) {
098: out.encodeBitString();
099: }
100:
101: public void setEncodingContent(BerOutputStream out) {
102: out.length = ((BitString) out.content).bytes.length + 1;
103: }
104:
105: //
106: //
107: // Named Bit List
108: //
109: //
110:
111: /**
112: * Default implementation for ASN.1 Named Bitstring type
113: *
114: * The default implementation works with encoding
115: * that is mapped to array of boolean.
116: */
117: public static class ASN1NamedBitList extends ASN1BitString {
118:
119: private static final byte[] SET_MASK = { (byte) 128, 64, 32,
120: 16, 8, 4, 2, 1 };
121:
122: private static final BitString emptyString = new BitString(
123: new byte[] {}, 0);
124:
125: private static final int INDEFINITE_SIZE = -1;
126:
127: private final int minBits;
128:
129: private final int maxBits;
130:
131: public ASN1NamedBitList() {
132: this .minBits = INDEFINITE_SIZE;
133: this .maxBits = INDEFINITE_SIZE;
134: }
135:
136: public ASN1NamedBitList(int minBits) {
137: this .minBits = minBits;
138: this .maxBits = INDEFINITE_SIZE;
139: }
140:
141: public ASN1NamedBitList(int minBits, int maxBits) {
142: this .minBits = minBits;
143: this .maxBits = maxBits;
144: }
145:
146: public Object getDecodedObject(BerInputStream in)
147: throws IOException {
148:
149: boolean[] value = null;
150:
151: int unusedBits = in.buffer[in.contentOffset];
152: int bitsNumber = (in.length - 1) * 8 - unusedBits;
153:
154: if (maxBits == INDEFINITE_SIZE) {
155: if (minBits == INDEFINITE_SIZE) {
156: value = new boolean[bitsNumber];
157: } else {
158: if (bitsNumber > minBits) {
159: value = new boolean[bitsNumber];
160: } else {
161: value = new boolean[minBits];
162: }
163: }
164: } else {
165: if (bitsNumber > maxBits) {
166: throw new ASN1Exception(Messages
167: .getString("security.97")); //FIXME message //$NON-NLS-1$
168: }
169: value = new boolean[maxBits];
170: }
171:
172: if (bitsNumber == 0) {
173: // empty bit string
174: return value;
175: }
176:
177: int i = 1;
178: int j = 0;
179: byte octet = in.buffer[in.contentOffset + i];
180: for (int size = in.length - 1; i < size; i++) {
181:
182: for (int k = 0; k < 8; k++, j++) {
183: value[j] = (SET_MASK[k] & octet) != 0;
184: }
185: i++;
186: octet = in.buffer[in.contentOffset + i];
187: }
188:
189: // final octet
190: for (int k = 0; k < (8 - unusedBits); k++, j++) {
191: value[j] = (SET_MASK[k] & octet) != 0;
192: }
193:
194: return value;
195: }
196:
197: public void setEncodingContent(BerOutputStream out) {
198:
199: boolean[] toEncode = (boolean[]) out.content;
200:
201: int index = toEncode.length - 1;
202: while (index > -1 && !toEncode[index]) {
203: index--;
204: }
205:
206: if (index == -1) {
207: out.content = emptyString;
208: out.length = 1;
209: } else {
210: int unusedBits = 7 - index % 8;
211: byte[] bytes = new byte[index / 8 + 1];
212:
213: int j = 0;
214: index = bytes.length - 1;
215: for (int i = 0; i < index; i++) {
216: for (int k = 0; k < 8; k++, j++) {
217: if (toEncode[j]) {
218: bytes[i] = (byte) (bytes[i] | SET_MASK[k]);
219: }
220: }
221: }
222:
223: //final octet
224: for (int k = 0; k < (8 - unusedBits); k++, j++) {
225: if (toEncode[j]) {
226: bytes[index] = (byte) (bytes[index] | SET_MASK[k]);
227: }
228: }
229:
230: out.content = new BitString(bytes, unusedBits);
231: out.length = bytes.length + 1;
232: }
233: }
234: }
235: }
|