| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** |
| * @author Vladimir N. Molotkov, Stepan M. Mishura |
| * @version $Revision$ |
| */ |
| |
| package org.apache.harmony.security.asn1; |
| |
| import libcore.base.Objects; |
| |
| |
| /** |
| * Encodes ASN.1 types with DER (X.690) |
| * |
| * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a> |
| */ |
| |
| public final class DerOutputStream extends BerOutputStream { |
| |
| public DerOutputStream(ASN1Type asn1, Object object) { |
| super(); |
| |
| content = object; |
| |
| index = -1; |
| asn1.setEncodingContent(this); |
| |
| encoded = new byte[asn1.getEncodedLength(this)]; |
| |
| index = 0; |
| asn1.encodeASN(this); |
| } |
| |
| public void encodeChoice(ASN1Choice choice) { |
| |
| ASN1Type type = (ASN1Type) val[index][0]; |
| |
| content = val[index][1]; |
| |
| index++; |
| |
| type.encodeASN(this); |
| } |
| |
| public void encodeExplicit(ASN1Explicit explicit) { |
| |
| content = val[index][0]; |
| length = len[index][0]; |
| |
| index++; |
| |
| explicit.type.encodeASN(this); |
| } |
| |
| public void encodeSequence(ASN1Sequence sequence) { |
| |
| ASN1Type[] type = sequence.type; |
| |
| Object[] values = val[index]; |
| int[] compLens = len[index]; |
| |
| index++; |
| for (int i = 0; i < type.length; i++) { |
| |
| if (values[i] == null) { |
| continue; |
| } |
| |
| content = values[i]; |
| length = compLens[i]; |
| |
| type[i].encodeASN(this); |
| } |
| } |
| |
| public void encodeSequenceOf(ASN1SequenceOf sequenceOf) { |
| encodeValueCollection(sequenceOf); |
| } |
| |
| public void encodeSetOf(ASN1SetOf setOf) { |
| encodeValueCollection(setOf); |
| } |
| |
| private final void encodeValueCollection(ASN1ValueCollection collection) { |
| |
| Object[] values = val[index]; |
| int[] compLens = len[index]; |
| |
| index++; |
| for (int i = 0; i < values.length; i++) { |
| |
| content = values[i]; |
| length = compLens[i]; |
| |
| collection.type.encodeASN(this); |
| } |
| } |
| |
| /* |
| * DATA |
| */ |
| |
| private final static int initSize = 32; |
| |
| private int index; |
| |
| private int[][] len = new int[initSize][]; |
| |
| private Object[][] val = new Object[initSize][]; |
| |
| private void push(int[] lengths, Object[] values) { |
| |
| index++; |
| if (index == val.length) { |
| |
| int[][] newLen = new int[val.length * 2][]; |
| System.arraycopy(len, 0, newLen, 0, val.length); |
| len = newLen; |
| |
| Object[][] newVal = new Object[val.length * 2][]; |
| System.arraycopy(val, 0, newVal, 0, val.length); |
| val = newVal; |
| } |
| len[index] = lengths; |
| val[index] = values; |
| } |
| |
| /* |
| * LENGTH |
| */ |
| |
| public void getChoiceLength(ASN1Choice choice) { |
| |
| int i = choice.getIndex(content); |
| content = choice.getObjectToEncode(content); |
| |
| Object[] values = new Object[] { choice.type[i], content }; |
| |
| push(null, values); |
| |
| choice.type[i].setEncodingContent(this); |
| |
| // in case if we get content bytes while getting its length |
| // FIXME what about remove it: need redesign |
| values[1] = content; |
| } |
| |
| public void getExplicitLength(ASN1Explicit explicit) { |
| |
| Object[] values = new Object[1]; |
| int[] compLens = new int[1]; |
| |
| values[0] = content; |
| |
| push(compLens, values); |
| |
| explicit.type.setEncodingContent(this); |
| |
| // in case if we get content bytes while getting its length |
| // FIXME what about remove it: need redesign |
| values[0] = content; |
| compLens[0] = length; |
| |
| length = explicit.type.getEncodedLength(this); |
| } |
| |
| public void getSequenceLength(ASN1Sequence sequence) { |
| |
| ASN1Type[] type = sequence.type; |
| |
| Object[] values = new Object[type.length]; |
| int[] compLens = new int[type.length]; |
| |
| sequence.getValues(content, values); |
| |
| push(compLens, values); |
| |
| int seqLen = 0; |
| for (int i = 0; i < type.length; i++) { |
| // check optional types |
| if (values[i] == null) { |
| if (sequence.OPTIONAL[i]) { |
| continue; |
| } else { |
| throw new RuntimeException();//FIXME type & message |
| } |
| } |
| |
| if (Objects.equal(sequence.DEFAULT[i], values[i])) { |
| values[i] = null; |
| continue; |
| } |
| |
| content = values[i]; |
| |
| type[i].setEncodingContent(this); |
| |
| compLens[i] = length; |
| |
| // in case if we get content bytes while getting its length |
| // FIXME what about remove it: need redesign |
| values[i] = content; |
| |
| seqLen += type[i].getEncodedLength(this); |
| } |
| length = seqLen; |
| } |
| |
| public void getSequenceOfLength(ASN1SequenceOf sequence) { |
| getValueOfLength(sequence); |
| } |
| |
| public void getSetOfLength(ASN1SetOf setOf) { |
| getValueOfLength(setOf); |
| } |
| |
| private void getValueOfLength(ASN1ValueCollection collection) { |
| |
| //FIXME what about another way? |
| Object[] cv = collection.getValues(content).toArray(); |
| |
| Object[] values = new Object[cv.length]; |
| int[] compLens = new int[values.length]; |
| |
| push(compLens, values); |
| int seqLen = 0; |
| for (int i = 0; i < values.length; i++) { |
| |
| content = cv[i]; |
| |
| collection.type.setEncodingContent(this); |
| |
| compLens[i] = length; |
| |
| // in case if we get content bytes while getting its length |
| // FIXME what about remove it: need redesign |
| values[i] = content; |
| |
| seqLen += collection.type.getEncodedLength(this); |
| } |
| length = seqLen; |
| } |
| } |