/*
* 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 java.io.IOException;
import org.apache.harmony.security.internal.nls.Messages;
/**
* Implicitly tagged ASN.1 type.
*
* @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
*/
public class ASN1Implicit extends ASN1Type {
// primitive type of tagging
private static final int TAGGING_PRIMITIVE = 0;
// constructed type of tagging
private static final int TAGGING_CONSTRUCTED = 1;
// string type of tagging
private static final int TAGGING_STRING = 2;
// tagged ASN.1 type
private final ASN1Type type;
// type of tagging. There are three of them
// 1) primitive: only primitive identifier is valid
// 2) constructed: only constructed identifier is valid
// 3) string: both identifiers are valid
private final int taggingType;
/**
* Constructs implicitly tagged ASN.1 type
* with context-specific tag class and specified tag number.
*
* @param tagNumber - ASN.1 tag number
* @param type - ASN.1 type to be tagged
* @throws IllegalArgumentException - if tagNumber or type is invalid
*/
public ASN1Implicit(int tagNumber, ASN1Type type) {
this(CLASS_CONTEXTSPECIFIC, tagNumber, type);
}
/**
* Constructs implicitly tagged ASN.1 type
*
* @param tagClass - ASN.1 tag class.
* @param tagNumber - ASN.1 tag number
* @param type - ASN.1 type to be tagged
* @throws IllegalArgumentException - if tagNumber, tagClass or type is invalid
*/
public ASN1Implicit(int tagClass, int tagNumber, ASN1Type type) {
super(tagClass, tagNumber);
if ((type instanceof ASN1Choice) || (type instanceof ASN1Any)) {
// According to X.680:
// 'The IMPLICIT alternative shall not be used if the type
// defined by "Type" is an untagged choice type or an
// untagged open type'
throw new IllegalArgumentException(
Messages.getString("security.9F")); //$NON-NLS-1$
}
this.type = type;
if (type.checkTag(type.id)) {
if (type.checkTag(type.constrId)) {
// the base encoding can be primitive ot constructed
// use both encodings
taggingType = TAGGING_STRING;
} else {
// if the base encoding is primitive use primitive encoding
taggingType = TAGGING_PRIMITIVE;
}
} else {
// if the base encoding is constructed use constructed encoding
taggingType = TAGGING_CONSTRUCTED;
}
}
//
//
// Decode
//
//
/**
* TODO
*/
public final boolean checkTag(int identifier) {
switch (taggingType) {
case TAGGING_PRIMITIVE:
return id == identifier;
case TAGGING_CONSTRUCTED:
return constrId == identifier;
default: // TAGGING_STRING
return id == identifier || constrId == identifier;
}
}
/**
* TODO
*/
public Object decode(BerInputStream in) throws IOException {
if (!checkTag(in.tag)) {
// FIXME need look for tagging type
throw new ASN1Exception(Messages.getString("security.100", //$NON-NLS-1$
new Object[] { in.tagOffset, Integer.toHexString(id),
Integer.toHexString(in.tag) }));
}
// substitute indentifier for further decoding
if (id == in.tag) {
in.tag = type.id;
} else {
in.tag = type.constrId;
}
in.content = type.decode(in);
if (in.isVerify) {
return null;
}
return getDecodedObject(in);
}
//
//
// Encode
//
//
public void encodeASN(BerOutputStream out) {
//FIXME need another way for specifying identifier to be encoded
if (taggingType == TAGGING_CONSTRUCTED) {
out.encodeTag(constrId);
} else {
out.encodeTag(id);
}
encodeContent(out);
}
public void encodeContent(BerOutputStream out) {
type.encodeContent(out);
}
public void setEncodingContent(BerOutputStream out) {
type.setEncodingContent(out);
}
}
|