//////////////////////////////////////////////////////////////////////////// 
// 
// Copyright (C) DSTC Pty Ltd (ACN 052 372 577) 1993, 1994, 1995.
// Unpublished work.  All Rights Reserved.
// 
// The software contained on this media is the property of the
// DSTC Pty Ltd.  Use of this software is strictly in accordance
// with the license agreement in the accompanying LICENSE.DOC 
// file. If your distribution of this software does not contain 
// a LICENSE.DOC file then you have no rights to use this 
// software in any manner and should contact DSTC at the address 
// below to determine an appropriate licensing arrangement.
// 
//      DSTC Pty Ltd
//      Level 7, GP South
//      University of Queensland
//      St Lucia, 4072
//      Australia
//      Tel: +61 7 3365 4310
//      Fax: +61 7 3365 4311
//      Email: jcsi@dstc.qut.edu.au
// 
// This software is being provided "AS IS" without warranty of
// any kind.  In no event shall DSTC Pty Ltd be liable for
// damage of any kind arising out of or in connection with
// the use or performance of this software.
// 
//////////////////////////////////////////////////////////////////////////// 

package com.dstc.security.cms.v1;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import com.dstc.security.asn1.Asn1;
import com.dstc.security.asn1.Constructed;
import com.dstc.security.asn1.Sequence;
import com.dstc.security.asn1.Asn1Exception;
import com.dstc.security.asn1.Oid;
import com.dstc.security.asn1.OctetString;
import com.dstc.security.x509.AlgorithmId;
import com.dstc.security.provider.OID;

/**
 * <p> Implements the ASN.1 structure EncryptedContentInfo.
 *
 * <pre>
 *     EncryptedContentInfo ::= SEQUENCE {
 *        contentType ContentType,
 *        contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
 *        encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL }
 *      
 *      EncryptedContent ::= OCTET STRING
 * </pre>
 * @version 0.98, 98/11/01
 * @author Ming Yung
 */
public final class EncryptedContentInfo extends Sequence
{
  private Oid contentType;
  private AlgorithmId contentEncryptionAlgoId;
  private byte[] encryptedContent;

  /**
   * Constructs an EncryptedContentInfo
   */
  public EncryptedContentInfo(String contentType, AlgorithmId algoId,
                              byte content[])
  {
    this.contentType = new Oid(contentType);
    addComponent(this.contentType);

    this.contentEncryptionAlgoId = algoId;
    addComponent(algoId);

    //implicit tagging of constructed primitive type
    this.encryptedContent = content;
    ConstructedOctet octs = new ConstructedOctet(0, content);
    addComponent(octs);
  }

  /**
   * Constructs an EncryptedContentInfo from a DER encoding
   */
  public EncryptedContentInfo(byte encoded[]) throws Asn1Exception
  {
    doDecode(encoded);
    int i=0;

    this.contentType = (Oid)components.elementAt(i++);

    this.contentEncryptionAlgoId = 
      new AlgorithmId(((Asn1)components.elementAt(i++)).encode());

    //Primitive encoding?
    try
    {
      this.encryptedContent = ((OctetString)components.elementAt(i)).getBytes();
      return;
    }
    catch (ClassCastException e)
    {
      //Ignore
    }

    //Must be a constructed encoding then
    ConstructedOctet dummy = 
      new ConstructedOctet(((Asn1)components.elementAt(i)).encode());
    this.encryptedContent = dummy.realContent;
  }

  /**
   * Returns the content type for this EncryptedContentInfo
   */
  public Oid getContentType()
  {
    return this.contentType;
  }

  /**
   * Returns the content encryption algorithm for this EncryptedContentInfo
   */
  public AlgorithmId getContentEncryptionAlgorithm()
  {
    return this.contentEncryptionAlgoId;
  }

  /**
   * Returns the encrypted content for this EncryptedContentInfo
   */
  public byte[] getEncryptedContent()
  {
    return (byte[])encryptedContent.clone();
  }

  /**
   * Inner class representing a constructed encoding for an OctetString
   */
  protected class ConstructedOctet extends Constructed
  {
    byte[] realContent; 

    /**
     * Constructs a ConstructedOctet from a byte array
     */
    protected ConstructedOctet(int dummy, byte[] data)
    {
      //super(Asn1.TAG_CLASS_CONTEXT, dummy);
      this.setTagClass(Asn1.TAG_CLASS_CONTEXT);
      this.setTagNumber(0);
      addComponent(new OctetString(data));
    }
 
    /**
     * Constructs a ConstructedOctet from a DER encoding
     */
    protected ConstructedOctet(byte encoded[]) throws Asn1Exception
    {
      doDecode(encoded);

      ByteArrayOutputStream bos = new ByteArrayOutputStream();

      try
      {
        for (int i=0; i< components.size(); i++)
        {
          bos.write(((OctetString)components.elementAt(i)).getBytes());
        }

        realContent = bos.toByteArray();
      }
      catch (IOException e)
      {
        e.printStackTrace();
      }//try
    }//Constructor
  }//Inner class
}//Class
