/*
 * compiler/core/oid.c - routines for:
 *          converting an arc number list to an ENC_OID
 *          converting an ENC_OID to an arc number list
 *          arcName mapping routine
 *
 *       does not handle OID's with unresolved valueRefs instead of arcNums
 *
 *  MS 91
 *
 * Copyright (C) 1991, 1992 Michael Sample
 *            and the University of British Columbia
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * $Header: /cvs/Darwin/src/live/Security/SecuritySNACCRuntime/compiler/core/oid.c,v 1.1 2001/06/20 21:27:58 dmitch Exp $
 * $Log: oid.c,v $
 * Revision 1.1  2001/06/20 21:27:58  dmitch
 * Adding missing snacc compiler files.
 *
 * Revision 1.1.1.1  1999/03/16 18:06:51  aram
 * Originals from SMIME Free Library.
 *
 * Revision 1.3  1995/07/25 19:41:41  rj
 * changed `_' to `-' in file names.
 *
 * Revision 1.2  1994/09/01  00:41:33  rj
 * snacc_config.h removed; oid.h includet.
 *
 * Revision 1.1  1994/08/28  09:49:26  rj
 * first check-in. for a list of changes to the snacc-1.1 distribution please refer to the ChangeLog.
 *
 */

#include <stdio.h> /* for FILE * */

#include "asn-incl.h"
#include "oid.h"

typedef struct ArcNameMapElmt
{
    char *arcName;
    int   arcNum;
} ArcNameMapElmt;


/*
 * these are the CCITT and ISO pre-defined arc names for the
 * OBJECT IDENTIFIER tree.
 * Ref: CCITT X.208 1988 - Annexes B C and D
 *
 * NOTE: the last entry must have a NULL string and a
 *       -1 arcnumber to indicate the end of the array.
 */
ArcNameMapElmt oidArcNameMapG[] =
{
    "ccitt", 0,
    "iso", 1,
    "joint-iso-ccitt", 2,
    "standard", 0,
    "registration-authority", 1,
    "member-body", 2,
    "identified-organization", 3,
    "recommendation", 0,
    "question", 1,
    "administration", 2,
    "network-operator", 3,
    NULL,-1
};


/*
 * returns the arcnum (>0) of the given name if it
 * is a defined oid arc name like "iso" or "ccitt"
 * returns -1 if the name was  not found
 *
 * name must be null terminated.
 */
int
OidArcNameToNum PARAMS ((name),
    char *name)
{
    int i;
    for (i= 0; oidArcNameMapG[i].arcName != NULL; i++)
    {
        if (strcmp (name, oidArcNameMapG[i].arcName) == 0)
            return oidArcNameMapG[i].arcNum;
    }
    return -1;
} /* OidArcNameToNum */



/*
 * Takes and OBJECT IDENTIFER in the linked format
 * (produced by parser) and returns the number of octets
 * that are needed to hold the encoded version of that
 * OBJECT IDENTIFIER.
 */
unsigned long int
EncodedOidLen PARAMS ((oid),
    OID *oid)
{
    unsigned long totalLen;
    unsigned long headArcNum;
    unsigned long tmpArcNum;
    OID *tmpOid;

    /*
     * oid must have at least 2 elmts
     */
    if (oid->next == NULL)
       return 0;

    headArcNum = (oid->arcNum * 40) + oid->next->arcNum;

    /*
     * figure out total encoded length of oid
     */
    tmpArcNum = headArcNum;
    for (totalLen = 1; (tmpArcNum >>= 7) != 0; totalLen++)
	;
    for (tmpOid = oid->next->next; tmpOid != NULL; tmpOid = tmpOid->next)
    {
        totalLen++;
        tmpArcNum = tmpOid->arcNum;
        for (; (tmpArcNum >>= 7) != 0; totalLen++)
	    ;
    }

    return totalLen;

}  /* EncodedOidLen */


/*
 * Given an oid arc number list and a pre-allocated ENC_OID
 * (use EncodedOidLen to figure out byte length needed)
 * fills the ENC_OID with a BER encoded version
 * of the oid.
 */
void
BuildEncodedOid PARAMS ((oid, result),
    OID *oid _AND_
    AsnOid *result)
{
    unsigned long len;
    unsigned long headArcNum;
    unsigned long tmpArcNum;
    char         *buf;
    int           i;
    OID          *tmpOid;

    buf = result->octs;

    /*
     * oid must have at least 2 elmts
     */
    if (oid->next == NULL)
       return;
    /*
     * munge together first two arcNum
     * note first arcnum must be <= 2
     * and second must be < 39 if first = 0 or 1
     * see (X.209) for ref to this stupidity
     */
    headArcNum = (oid->arcNum * 40) + oid->next->arcNum;

    tmpArcNum = headArcNum;

    /*
     * calc # bytes needed for head arc num
     */
    for (len = 0; (tmpArcNum >>= 7) != 0; len++)
	;

    /*
     * write more signifcant bytes (if any) of head arc num
     * with 'more' bit set
     */
    for (i=0; i < len; i++)
        *(buf++) = 0x80 | (headArcNum >> ((len-i)*7));

    /*
     * write least significant byte of head arc num
     */
    *(buf++) = 0x7f & headArcNum;


    /*
     * write following arc nums, if any
     */
    for (tmpOid = oid->next->next; tmpOid != NULL; tmpOid = tmpOid->next)
    {
        /*
         * figure out encoded length -1 of this arcNum
         */
        tmpArcNum = tmpOid->arcNum;
        for (len = 0; (tmpArcNum >>= 7) != 0; len++)
	    ;


        /*
         * write more signifcant bytes (if any)
         * with 'more' bit set
         */
        for (i=0; i < len; i++)
            *(buf++) = 0x80 | (tmpOid->arcNum >> ((len-i)*7));

        /*
         * write least significant byte
         */
        *(buf++) = 0x7f & tmpOid->arcNum;
    }

} /* BuildEncodedOid */


/*
 * Given an ENC_OID, this routine converts it into a
 * linked oid (OID).
 */
void
UnbuildEncodedOid PARAMS ((eoid, result),
    AsnOid *eoid _AND_
    OID **result)
{
    OID **nextOid;
    OID *headOid;
    int arcNum;
    int i;
    int firstArcNum;
    int secondArcNum;

    for (arcNum = 0, i=0; (i < eoid->octetLen) && (eoid->octs[i] & 0x80);i++)
        arcNum = (arcNum << 7) + (eoid->octs[i] & 0x7f);

    arcNum = (arcNum << 7) + (eoid->octs[i] & 0x7f);
    i++;

    firstArcNum = arcNum / 40;
    if (firstArcNum > 2)
        firstArcNum = 2;

    secondArcNum = arcNum - (firstArcNum * 40);

    headOid = (OID*)Malloc (sizeof (OID));
    headOid->arcNum = firstArcNum;
    headOid->next = (OID*)Malloc (sizeof (OID));
    headOid->next->arcNum = secondArcNum;
    nextOid = &headOid->next->next;

    for ( ; i < eoid->octetLen; )
    {
        for (arcNum = 0; (i < eoid->octetLen) && (eoid->octs[i] & 0x80);i++)
            arcNum = (arcNum << 7) + (eoid->octs[i] & 0x7f);

        arcNum = (arcNum << 7) + (eoid->octs[i] & 0x7f);
        i++;
        *nextOid = (OID*)Malloc (sizeof (OID));
        (*nextOid)->arcNum = arcNum;
        nextOid = &(*nextOid)->next;
    }

    *result = headOid;

} /* UnbuildEncodedOid */
