dect
/
asterisk
Archived
13
0
Fork 0
This repository has been archived on 2022-02-17. You can view files and clone it, but cannot push or open issues or pull requests.
asterisk/addons/ooh323c/src/encode.c

1104 lines
29 KiB
C

/*
* Copyright (C) 1997-2005 by Objective Systems, Inc.
*
* This software is furnished under an open source license and may be
* used and copied only in accordance with the terms of this license.
* The text of the license may generally be found in the root
* directory of this installation in the COPYING file. It
* can also be viewed online at the following URL:
*
* http://www.obj-sys.com/open/license.html
*
* Any redistributions of this file including modified versions must
* maintain this copyright notice.
*
*****************************************************************************/
#include <stdlib.h>
#include "ooasn1.h"
static int encode16BitConstrainedString
(OOCTXT* pctxt, Asn116BitCharString value, Asn116BitCharSet* pCharSet);
static int encode2sCompBinInt (OOCTXT* pctxt, ASN1INT value);
static int encodeNonNegBinInt (OOCTXT* pctxt, ASN1UINT value);
static int encodeUnconsLength (OOCTXT* pctxt, ASN1UINT value);
static int getIdentByteCount (ASN1UINT ident);
int encodeBit (OOCTXT* pctxt, ASN1BOOL value)
{
int stat = ASN_OK;
/* If start of new byte, init to zero */
if (pctxt->buffer.bitOffset == 8) {
pctxt->buffer.data[pctxt->buffer.byteIndex] = 0;
}
/* Adjust bit offset and determine if at end of current byte */
if (--pctxt->buffer.bitOffset < 0) {
if (++pctxt->buffer.byteIndex >= pctxt->buffer.size) {
if ((stat = encodeExpandBuffer (pctxt, 1)) != ASN_OK) {
return stat;
}
}
pctxt->buffer.data[pctxt->buffer.byteIndex] = 0;
pctxt->buffer.bitOffset = 7;
}
/* Set single-bit value */
if (value) {
pctxt->buffer.data[pctxt->buffer.byteIndex] |=
( 1 << pctxt->buffer.bitOffset );
}
/* If last bit in octet, set offsets to start new byte (ED, 9/7/01) */
if (pctxt->buffer.bitOffset == 0) {
pctxt->buffer.bitOffset = 8;
pctxt->buffer.byteIndex++;
pctxt->buffer.data[pctxt->buffer.byteIndex] = 0;
}
return stat;
}
int encodeBits (OOCTXT* pctxt, ASN1UINT value, ASN1UINT nbits)
{
int nbytes = (nbits + 7)/ 8, stat = ASN_OK;
if (nbits == 0) return stat;
/* If start of new byte, init to zero */
if (pctxt->buffer.bitOffset == 8) {
pctxt->buffer.data[pctxt->buffer.byteIndex] = 0;
}
/* Mask off unused bits from the front of the value */
if (nbits < (sizeof(ASN1UINT) * 8))
value &= ((1 << nbits) - 1);
/* If bits will fit in current byte, set them and return */
if (nbits < (unsigned)pctxt->buffer.bitOffset) {
pctxt->buffer.bitOffset -= nbits;
pctxt->buffer.data[pctxt->buffer.byteIndex] |=
( value << pctxt->buffer.bitOffset );
return stat;
}
/* Check buffer space and allocate more memory if necessary */
stat = encodeCheckBuffer (pctxt, nbytes);
if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat);
/* Set bits in remainder of the current byte and then loop */
/* to set bits in subsequent bytes.. */
nbits -= pctxt->buffer.bitOffset;
pctxt->buffer.data[pctxt->buffer.byteIndex++] |=
(ASN1OCTET)( value >> nbits );
pctxt->buffer.data[pctxt->buffer.byteIndex] = 0;
while (nbits >= 8) {
nbits -= 8;
pctxt->buffer.data[pctxt->buffer.byteIndex++] =
(ASN1OCTET)( value >> nbits );
pctxt->buffer.data[pctxt->buffer.byteIndex] = 0;
}
/* copy final partial byte */
pctxt->buffer.bitOffset = 8 - nbits;
if (nbits > 0) {
pctxt->buffer.data[pctxt->buffer.byteIndex] =
(ASN1OCTET)((value & ((1 << nbits)-1)) << pctxt->buffer.bitOffset);
}
else
pctxt->buffer.data[pctxt->buffer.byteIndex] = 0;
return stat;
}
int encodeBitsFromOctet (OOCTXT* pctxt, ASN1OCTET value, ASN1UINT nbits)
{
int lshift = pctxt->buffer.bitOffset;
int rshift = 8 - pctxt->buffer.bitOffset;
int stat = ASN_OK;
ASN1OCTET mask;
if (nbits == 0) return ASN_OK;
/* Mask off unused bits from the end of the value */
if (nbits < 8) {
switch (nbits) {
case 1: mask = 0x80; break;
case 2: mask = 0xC0; break;
case 3: mask = 0xE0; break;
case 4: mask = 0xF0; break;
case 5: mask = 0xF8; break;
case 6: mask = 0xFC; break;
case 7: mask = 0xFE; break;
default:;
}
value &= mask;
}
/* If we are on a byte boundary, we can do a direct assignment */
if (pctxt->buffer.bitOffset == 8) {
pctxt->buffer.data[pctxt->buffer.byteIndex] = value;
if (nbits == 8) {
pctxt->buffer.byteIndex++;
pctxt->buffer.data[pctxt->buffer.byteIndex] = 0;
}
else
pctxt->buffer.bitOffset -= nbits;
}
/* Otherwise, need to set some bits in the first octet and */
/* possibly some bits in the following octet.. */
else {
pctxt->buffer.data[pctxt->buffer.byteIndex] |=
(ASN1OCTET)(value >> rshift);
pctxt->buffer.bitOffset -= nbits;
if (pctxt->buffer.bitOffset < 0) {
pctxt->buffer.byteIndex++;
pctxt->buffer.data[pctxt->buffer.byteIndex] =
(ASN1OCTET)(value << lshift);
pctxt->buffer.bitOffset += 8;
}
}
return stat;
}
int encodeBitString (OOCTXT* pctxt, ASN1UINT numbits, const ASN1OCTET* data)
{
int enclen, octidx = 0, stat;
Asn1SizeCnst* pSizeList = pctxt->pSizeConstraint;
for (;;) {
if ((enclen = encodeLength (pctxt, numbits)) < 0) {
return LOG_ASN1ERR (pctxt, enclen);
}
if (enclen > 0) {
ASN1BOOL doAlign;
stat = bitAndOctetStringAlignmentTest
(pSizeList, numbits, TRUE, &doAlign);
if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat);
if (doAlign) {
stat = encodeByteAlign (pctxt);
if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat);
}
stat = encodeOctets (pctxt, &data[octidx], enclen);
if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat);
}
if (enclen < (int)numbits) {
numbits -= enclen;
octidx += (enclen/8);
}
else break;
}
return ASN_OK;
}
int encodeBMPString
(OOCTXT* pctxt, ASN1BMPString value, Asn116BitCharSet* permCharSet)
{
Asn116BitCharSet charSet;
int stat;
/* Set character set */
init16BitCharSet (&charSet, BMP_FIRST, BMP_LAST, BMP_ABITS, BMP_UBITS);
if (permCharSet) {
set16BitCharSet (pctxt, &charSet, permCharSet);
}
/* Encode constrained string */
stat = encode16BitConstrainedString (pctxt, value, &charSet);
if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat);
return stat;
}
int encodeByteAlign (OOCTXT* pctxt)
{
if (pctxt->buffer.bitOffset != 8) {
if ((pctxt->buffer.byteIndex + 1) >= pctxt->buffer.size) {
int stat = encodeExpandBuffer (pctxt, 1);
if (stat != ASN_OK) return (stat);
}
pctxt->buffer.byteIndex++;
pctxt->buffer.bitOffset = 8;
pctxt->buffer.data[pctxt->buffer.byteIndex] = 0;
}
return ASN_OK;
}
int encodeCheckBuffer (OOCTXT* pctxt, ASN1UINT nbytes)
{
int stat = ASN_OK;
/* Add one to required bytes because increment logic will always */
/* init the byte at the incremented index to zero.. */
if ( ( pctxt->buffer.byteIndex + nbytes + 1 ) >= pctxt->buffer.size ) {
if ((stat = encodeExpandBuffer (pctxt, nbytes+1)) != ASN_OK) {
return LOG_ASN1ERR (pctxt, stat);
}
}
return (stat);
}
int encodeConsInteger
(OOCTXT* pctxt, ASN1INT value, ASN1INT lower, ASN1INT upper)
{
ASN1UINT range_value;
ASN1UINT adjusted_value;
int stat;
/* Check value against given range */
if (value < lower || value > upper) {
return ASN_E_CONSVIO;
}
/* Adjust range value based on lower/upper signed values and */
/* other possible conflicts.. */
if ((upper > 0 && lower >= 0) || (upper <= 0 && lower < 0)) {
range_value = upper - lower;
adjusted_value = value - lower;
}
else {
range_value = upper + abs(lower);
adjusted_value = value + abs(lower);
}
if (range_value != ASN1UINT_MAX) { range_value += 1; }
if (range_value == 0 || lower > upper)
stat = ASN_E_RANGERR;
else if (lower != upper) {
stat = encodeConsWholeNumber (pctxt, adjusted_value, range_value);
}
else
stat = ASN_OK;
return stat;
}
int encodeConsUnsigned
(OOCTXT* pctxt, ASN1UINT value, ASN1UINT lower, ASN1UINT upper)
{
ASN1UINT range_value;
ASN1UINT adjusted_value;
int stat;
/* Check for special case: if lower is 0 and upper is ASN1UINT_MAX, */
/* set range to ASN1UINT_MAX; otherwise to upper - lower + 1 */
range_value = (lower == 0 && upper == ASN1UINT_MAX) ?
ASN1UINT_MAX : upper - lower + 1;
adjusted_value = value - lower;
if (lower != upper) {
stat = encodeConsWholeNumber (pctxt, adjusted_value, range_value);
}
else
stat = ASN_OK;
return stat;
}
int encodeConsWholeNumber
(OOCTXT* pctxt, ASN1UINT adjusted_value, ASN1UINT range_value)
{
ASN1UINT nocts, range_bitcnt = getUIntBitCount (range_value - 1);
int stat;
if (adjusted_value >= range_value && range_value != ASN1UINT_MAX) {
return LOG_ASN1ERR (pctxt, ASN_E_RANGERR);
}
/* If range is <= 255, bit-field case (10.5.7a) */
if (range_value <= 255) {
return encodeBits (pctxt, adjusted_value, range_bitcnt);
}
/* If range is exactly 256, one-octet case (10.5.7b) */
else if (range_value == 256) {
stat = encodeByteAlign (pctxt);
if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat);
return encodeBits (pctxt, adjusted_value, 8);
}
/* If range > 256 and <= 64k (65536), two-octet case (10.5.7c) */
else if (range_value <= 65536) {
stat = encodeByteAlign (pctxt);
if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat);
return encodeBits (pctxt, adjusted_value, 16);
}
/* If range > 64k, indefinite-length case (10.5.7d) */
else {
/* Encode length determinant as a constrained whole number. */
/* Constraint is 1 to max number of bytes needed to hold */
/* the target integer value.. */
if (adjusted_value < 256) nocts = 1;
else if (adjusted_value < 65536) nocts = 2;
else if (adjusted_value < 0x1000000) nocts = 3;
else nocts = 4;
stat = encodeBits (pctxt, nocts - 1, 2);
if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat);
stat = encodeByteAlign (pctxt);
if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat);
return encodeNonNegBinInt (pctxt, adjusted_value);
}
}
int encodeConstrainedStringEx (OOCTXT* pctxt,
const char* string,
const char* charSet,
ASN1UINT abits, /* aligned char bits */
ASN1UINT ubits, /* unaligned char bits */
ASN1UINT canSetBits)
{
ASN1UINT i, len = strlen(string);
int stat;
/* note: need to save size constraint for use in alignCharStr */
/* because it will be cleared in encodeLength from the context.. */
Asn1SizeCnst* psize = pctxt->pSizeConstraint;
/* Encode length */
stat = encodeLength (pctxt, len);
if (stat < 0) return LOG_ASN1ERR (pctxt, stat);
/* Byte align */
if (alignCharStr (pctxt, len, abits, psize)) {
stat = encodeByteAlign (pctxt);
if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat);
}
/* Encode data */
if (abits >= canSetBits && canSetBits > 4) {
for (i = 0; i < len; i++) {
if ((stat = encodeBits (pctxt, string[i], abits)) != ASN_OK)
return LOG_ASN1ERR (pctxt, stat);
}
}
else if (0 != charSet) {
ASN1UINT nchars = strlen(charSet), pos;
const char* ptr;
for (i = 0; i < len; i++) {
ptr = memchr (charSet, string[i], nchars);
if (0 == ptr)
return LOG_ASN1ERR (pctxt, ASN_E_CONSVIO);
else
pos = ptr - charSet;
if ((stat = encodeBits (pctxt, pos, abits)) != ASN_OK)
return LOG_ASN1ERR (pctxt, stat);
}
}
else return LOG_ASN1ERR (pctxt, ASN_E_INVPARAM);
return stat;
}
int encodeExpandBuffer (OOCTXT* pctxt, ASN1UINT nbytes)
{
if (pctxt->buffer.dynamic)
{
/* If dynamic encoding is enabled, expand the current buffer to */
/* allow encoding to continue. */
pctxt->buffer.size += ASN1MAX (ASN_K_ENCBUFSIZ, nbytes);
pctxt->buffer.data = (ASN1OCTET*) memHeapRealloc
(&pctxt->pMsgMemHeap, pctxt->buffer.data, pctxt->buffer.size);
if (!pctxt->buffer.data) return (ASN_E_NOMEM);
return (ASN_OK);
}
return (ASN_E_BUFOVFLW);
}
int encodeGetMsgBitCnt (OOCTXT* pctxt)
{
int numBitsInLastByte = 8 - pctxt->buffer.bitOffset;
return ((pctxt->buffer.byteIndex * 8) + numBitsInLastByte);
}
ASN1OCTET* encodeGetMsgPtr (OOCTXT* pctxt, int* pLength)
{
if (pLength) *pLength = getPERMsgLen (pctxt);
return pctxt->buffer.data;
}
int encodeIdent (OOCTXT* pctxt, ASN1UINT ident)
{
ASN1UINT mask;
int nshifts = 0, stat;
if (ident !=0) {
ASN1UINT lv;
nshifts = getIdentByteCount (ident);
while (nshifts > 0) {
mask = ((ASN1UINT)0x7f) << (7 * (nshifts - 1));
nshifts--;
lv = (ASN1UINT)((ident & mask) >> (nshifts * 7));
if (nshifts != 0) { lv |= 0x80; }
if ((stat = encodeBits (pctxt, lv, 8)) != ASN_OK)
return LOG_ASN1ERR (pctxt, stat);
}
}
else {
/* encode a single zero byte */
if ((stat = encodeBits (pctxt, 0, 8)) != ASN_OK)
return LOG_ASN1ERR (pctxt, stat);
}
return ASN_OK;
}
int encodeLength (OOCTXT* pctxt, ASN1UINT value)
{
ASN1BOOL extendable;
Asn1SizeCnst* pSize =
checkSize (pctxt->pSizeConstraint, value, &extendable);
ASN1UINT lower = (pSize) ? pSize->lower : 0;
ASN1UINT upper = (pSize) ? pSize->upper : ASN1UINT_MAX;
int enclen, stat;
/* If size constraints exist and the given length did not fall */
/* within the range of any of them, signal constraint violation */
/* error.. */
if (pctxt->pSizeConstraint && !pSize)
return LOG_ASN1ERR (pctxt, ASN_E_CONSVIO);
/* Reset the size constraint in the context block structure */
pctxt->pSizeConstraint = 0;
/* If size constraint is present and extendable, encode extension */
/* bit.. */
if (extendable) {
stat = (pSize) ?
encodeBit (pctxt, pSize->extended) : encodeBit (pctxt, 1);
if (stat != ASN_OK) return (stat);
}
/* If upper limit is less than 64k, constrained case */
if (upper < 65536) {
stat = (lower == upper) ? ASN_OK :
encodeConsWholeNumber (pctxt, value - lower, upper - lower + 1);
enclen = (stat == ASN_OK) ? value : stat;
}
else {
/* unconstrained case or Constrained with upper bound >= 64K*/
enclen = encodeUnconsLength (pctxt, value);
}
return enclen;
}
int encodeObjectIdentifier (OOCTXT* pctxt, ASN1OBJID* pvalue)
{
int len, stat;
ASN1UINT temp;
register int numids, i;
/* Calculate length in bytes and encode */
len = 1; /* 1st 2 arcs require 1 byte */
numids = pvalue->numids;
for (i = 2; i < numids; i++) {
len += getIdentByteCount (pvalue->subid[i]);
}
/* PER encode length */
if ((stat = encodeLength (pctxt, (ASN1UINT)len)) < 0) {
return LOG_ASN1ERR (pctxt, stat);
}
/* Validate given object ID by applying ASN.1 rules */
if (0 == pvalue) return LOG_ASN1ERR (pctxt, ASN_E_INVOBJID);
if (numids < 2) return LOG_ASN1ERR (pctxt, ASN_E_INVOBJID);
if (pvalue->subid[0] > 2) return LOG_ASN1ERR (pctxt, ASN_E_INVOBJID);
if (pvalue->subid[0] != 2 && pvalue->subid[1] > 39)
return LOG_ASN1ERR (pctxt, ASN_E_INVOBJID);
/* Passed checks, encode object identifier */
/* Munge first two sub ID's and encode */
temp = ((pvalue->subid[0] * 40) + pvalue->subid[1]);
if ((stat = encodeIdent (pctxt, temp)) != ASN_OK)
return LOG_ASN1ERR (pctxt, stat);
/* Encode the remainder of the OID value */
for (i = 2; i < numids; i++) {
if ((stat = encodeIdent (pctxt, pvalue->subid[i])) != ASN_OK)
return LOG_ASN1ERR (pctxt, stat);
}
return ASN_OK;
}
int encodebitsFromOctet (OOCTXT* pctxt, ASN1OCTET value, ASN1UINT nbits)
{
int lshift = pctxt->buffer.bitOffset;
int rshift = 8 - pctxt->buffer.bitOffset;
int stat = ASN_OK;
ASN1OCTET mask;
if (nbits == 0) return ASN_OK;
/* Mask off unused bits from the end of the value */
if (nbits < 8) {
switch (nbits) {
case 1: mask = 0x80; break;
case 2: mask = 0xC0; break;
case 3: mask = 0xE0; break;
case 4: mask = 0xF0; break;
case 5: mask = 0xF8; break;
case 6: mask = 0xFC; break;
case 7: mask = 0xFE; break;
default:;
}
value &= mask;
}
/* If we are on a byte boundary, we can do a direct assignment */
if (pctxt->buffer.bitOffset == 8) {
pctxt->buffer.data[pctxt->buffer.byteIndex] = value;
if (nbits == 8) {
pctxt->buffer.byteIndex++;
pctxt->buffer.data[pctxt->buffer.byteIndex] = 0;
}
else
pctxt->buffer.bitOffset -= nbits;
}
/* Otherwise, need to set some bits in the first octet and */
/* possibly some bits in the following octet.. */
else {
pctxt->buffer.data[pctxt->buffer.byteIndex] |=
(ASN1OCTET)(value >> rshift);
pctxt->buffer.bitOffset -= nbits;
if (pctxt->buffer.bitOffset < 0) {
pctxt->buffer.byteIndex++;
pctxt->buffer.data[pctxt->buffer.byteIndex] =
(ASN1OCTET)(value << lshift);
pctxt->buffer.bitOffset += 8;
}
}
return stat;
}
int encodeOctets (OOCTXT* pctxt, const ASN1OCTET* pvalue, ASN1UINT nbits)
{
int i = 0, stat;
int numFullOcts = nbits / 8;
if (nbits == 0) return 0;
/* Check buffer space and allocate more memory if necessary */
stat = encodeCheckBuffer (pctxt, numFullOcts + 1);
if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat);
if (numFullOcts > 0) {
/* If the current bit offset is 8 (i.e. we don't have a */
/* byte started), can copy the string directly to the */
/* encode buffer.. */
if (pctxt->buffer.bitOffset == 8) {
memcpy (&pctxt->buffer.data[pctxt->buffer.byteIndex], pvalue,
numFullOcts);
pctxt->buffer.byteIndex += numFullOcts;
pctxt->buffer.data[pctxt->buffer.byteIndex] = 0;
i = numFullOcts;
}
/* Else, copy bits */
else {
for (i = 0; i < numFullOcts; i++) {
stat = encodeBitsFromOctet (pctxt, pvalue[i], 8);
if (stat != ASN_OK) return stat;
}
}
}
/* Move remaining bits from the last octet to the output buffer */
if (nbits % 8 != 0) {
stat = encodeBitsFromOctet (pctxt, pvalue[i], nbits % 8);
}
return stat;
}
int encodeOctetString (OOCTXT* pctxt, ASN1UINT numocts, const ASN1OCTET* data)
{
int enclen, octidx = 0, stat;
Asn1SizeCnst* pSizeList = pctxt->pSizeConstraint;
for (;;) {
if ((enclen = encodeLength (pctxt, numocts)) < 0) {
return LOG_ASN1ERR (pctxt, enclen);
}
if (enclen > 0) {
ASN1BOOL doAlign;
stat = bitAndOctetStringAlignmentTest
(pSizeList, numocts, FALSE, &doAlign);
if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat);
if (doAlign) {
stat = encodeByteAlign (pctxt);
if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat);
}
stat = encodeOctets (pctxt, &data[octidx], enclen * 8);
if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat);
}
if (enclen < (int)numocts) {
numocts -= enclen;
octidx += enclen;
}
else break;
}
return ASN_OK;
}
int encodeOpenType (OOCTXT* pctxt, ASN1UINT numocts, const ASN1OCTET* data)
{
int enclen, octidx = 0, stat;
ASN1OCTET zeroByte = 0x00;
ASN1OpenType openType;
/* If open type contains length zero, add a single zero byte (10.1) */
if (numocts == 0) {
openType.numocts = 1;
openType.data = &zeroByte;
}
else {
openType.numocts = numocts;
openType.data = data;
}
/* Encode the open type */
for (;;) {
if ((enclen = encodeLength (pctxt, openType.numocts)) < 0) {
return LOG_ASN1ERR (pctxt, enclen);
}
stat = encodeByteAlign (pctxt);
if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat);
stat = encodeOctets (pctxt, &openType.data[octidx], enclen * 8);
if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat);
if (enclen < (int)openType.numocts) {
openType.numocts -= enclen;
octidx += enclen;
}
else break;
}
return ASN_OK;
}
int encodeOpenTypeExt (OOCTXT* pctxt, DList* pElemList)
{
DListNode* pnode;
ASN1OpenType* pOpenType;
int stat;
if (0 != pElemList) {
pnode = pElemList->head;
while (0 != pnode) {
if (0 != pnode->data) {
pOpenType = (ASN1OpenType*)pnode->data;
if (pOpenType->numocts > 0) {
stat = encodeByteAlign (pctxt);
if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat);
stat = encodeOpenType
(pctxt, pOpenType->numocts, pOpenType->data);
if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat);
}
}
pnode = pnode->next;
}
}
return ASN_OK;
}
int encodeOpenTypeExtBits (OOCTXT* pctxt, DList* pElemList)
{
DListNode* pnode;
int stat;
if (0 != pElemList) {
pnode = pElemList->head;
while (0 != pnode) {
stat = encodeBit (pctxt, (ASN1BOOL)(0 != pnode->data));
if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat);
pnode = pnode->next;
}
}
return ASN_OK;
}
int encodeSemiConsInteger (OOCTXT* pctxt, ASN1INT value, ASN1INT lower)
{
int nbytes, stat;
int shift = ((sizeof(value) - 1) * 8) - 1;
ASN1UINT tempValue;
if (lower > ASN1INT_MIN)
value -= lower;
/* Calculate signed number value length */
for ( ; shift > 0; shift -= 8) {
tempValue = (value >> shift) & 0x1ff;
if (tempValue == 0 || tempValue == 0x1ff) continue;
else break;
}
nbytes = (shift + 9) / 8;
/* Encode length */
if ((stat = encodeLength (pctxt, nbytes)) < 0) {
return stat;
}
if ((stat = encodeByteAlign (pctxt)) != ASN_OK)
return stat;
/* Encode signed value */
stat = encode2sCompBinInt (pctxt, value);
return stat;
}
int encodeSemiConsUnsigned (OOCTXT* pctxt, ASN1UINT value, ASN1UINT lower)
{
int nbytes, stat;
int shift = ((sizeof(value) - 1) * 8) - 1;
ASN1UINT mask = 1UL << ((sizeof(value) * 8) - 1);
ASN1UINT tempValue;
value -= lower;
/* Calculate unsigned number value length */
for ( ; shift > 0; shift -= 8) {
tempValue = (value >> shift) & 0x1ff;
if (tempValue == 0) continue;
else break;
}
nbytes = (shift + 9) / 8;
/* If MS bit in unsigned number is set, add an extra zero byte */
if ((value & mask) != 0) nbytes++;
/* Encode length */
if ((stat = encodeLength (pctxt, nbytes)) < 0) {
return stat;
}
if ((stat = encodeByteAlign (pctxt)) != ASN_OK)
return stat;
/* Encode additional zero byte if necessary */
if (nbytes > sizeof(value)) {
stat = encodebitsFromOctet (pctxt, 0, 8);
if (stat != ASN_OK) return (stat);
}
/* Encode unsigned value */
stat = encodeNonNegBinInt (pctxt, value);
return stat;
}
int encodeSmallNonNegWholeNumber (OOCTXT* pctxt, ASN1UINT value)
{
int stat;
if (value < 64) {
stat = encodeBits (pctxt, value, 7);
}
else {
ASN1UINT len;
/* Encode a one-byte length determinant value */
if (value < 256) len = 1;
else if (value < 65536) len = 2;
else if (value < 0x1000000) len = 3;
else len = 4;
stat = encodeBits (pctxt, len, 8);
/* Byte-align and encode the value */
if (stat == ASN_OK) {
if ((stat = encodeByteAlign (pctxt)) == ASN_OK) {
stat = encodeBits (pctxt, value, len*8);
}
}
}
return stat;
}
int encodeVarWidthCharString (OOCTXT* pctxt, const char* value)
{
int stat;
ASN1UINT len = strlen (value);
/* note: need to save size constraint for use in alignCharStr */
/* because it will be cleared in encodeLength from the context.. */
Asn1SizeCnst* psize = pctxt->pSizeConstraint;
/* Encode length */
stat = encodeLength (pctxt, len);
if (stat < 0) return LOG_ASN1ERR (pctxt, stat);
/* Byte align */
if (alignCharStr (pctxt, len, 8, psize)) {
stat = encodeByteAlign (pctxt);
if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat);
}
/* Encode data */
stat = encodeOctets (pctxt, (const ASN1OCTET*)value, len * 8);
if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat);
return ASN_OK;
}
static int encode16BitConstrainedString
(OOCTXT* pctxt, Asn116BitCharString value, Asn116BitCharSet* pCharSet)
{
ASN1UINT i, pos;
ASN1UINT nbits = pCharSet->alignedBits;
int stat;
/* Encode length */
stat = encodeLength (pctxt, value.nchars);
if (stat < 0) return LOG_ASN1ERR (pctxt, stat);
/* Byte align */
stat = encodeByteAlign (pctxt);
if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat);
/* Encode data */
for (i = 0; i < value.nchars; i++) {
if (pCharSet->charSet.data == 0) {
stat = encodeBits
(pctxt, value.data[i] - pCharSet->firstChar, nbits);
if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat);
}
else {
for (pos = 0; pos < pCharSet->charSet.nchars; pos++) {
if (value.data[i] == pCharSet->charSet.data[pos]) {
stat = encodeBits (pctxt, pos, nbits);
if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat);
break;
}
}
}
}
return stat;
}
int encode2sCompBinInt (OOCTXT* pctxt, ASN1INT value)
{
/* 10.4.6 A minimum octet 2's-complement-binary-integer encoding */
/* of the whole number has a field width that is a multiple of 8 */
/* bits and also satisifies the condition that the leading 9 bits */
/* field shall not be all zeros and shall not be all ones. */
/* first encode integer value into a local buffer */
ASN1OCTET lbuf[8], lb;
ASN1INT i = sizeof(lbuf), temp = value;
memset (lbuf, 0, sizeof(lbuf));
do {
lb = temp % 256;
temp /= 256;
if (temp < 0 && lb != 0) temp--; /* two's complement adjustment */
lbuf[--i] = lb;
} while (temp != 0 && temp != -1);
/* If the value is positive and bit 8 of the leading byte is set, */
/* copy a zero byte to the contents to signal a positive number.. */
if (value > 0 && (lb & 0x80) != 0) {
i--;
}
/* If the value is negative and bit 8 of the leading byte is clear, */
/* copy a -1 byte (0xFF) to the contents to signal a negative */
/* number.. */
else if (value < 0 && ((lb & 0x80) == 0)) {
lbuf[--i] = 0xff;
}
/* Add the data to the encode buffer */
return encodeOctets (pctxt, &lbuf[i], (sizeof(lbuf) - i) * 8);
}
static int encodeNonNegBinInt (OOCTXT* pctxt, ASN1UINT value)
{
/* 10.3.6 A minimum octet non-negative binary integer encoding of */
/* the whole number (which does not predetermine the number of */
/* octets to be used for the encoding) has a field which is a */
/* multiple of 8 bits and also satisifies the condition that the */
/* leading eight bits of the field shall not be zero unless the */
/* field is precisely 8 bits long. */
ASN1UINT bitcnt = (value == 0) ? 1 : getUIntBitCount (value);
/* round-up to nearest 8-bit boundary */
bitcnt = (bitcnt + 7) & (~7);
/* encode bits */
return encodeBits (pctxt, value, bitcnt);
}
static int encodeUnconsLength (OOCTXT* pctxt, ASN1UINT value)
{
int enclen, stat;
stat = encodeByteAlign (pctxt);
if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat);
/* 1 octet case */
if (value < 128) {
stat = encodeBits (pctxt, value, 8);
enclen = (stat == ASN_OK) ? value : stat;
}
/* 2 octet case */
else if (value < 16384) {
if ((stat = encodeBit (pctxt, 1)) == ASN_OK)
stat = encodeBits (pctxt, value, 15);
enclen = (stat == ASN_OK) ? value : stat;
}
/* fragmentation case */
else {
int multiplier = ASN1MIN (value/16384, 4);
encodeBit (pctxt, 1); /* set bit 8 of first octet */
encodeBit (pctxt, 1); /* set bit 7 of first octet */
stat = encodeBits (pctxt, multiplier, 6);
enclen = (stat == ASN_OK) ? 16384 * multiplier : stat;
}
return enclen;
}
static int getIdentByteCount (ASN1UINT ident)
{
if (ident < (1u << 7)) { /* 7 */
return 1;
}
else if (ident < (1u << 14)) { /* 14 */
return 2;
}
else if (ident < (1u << 21)) { /* 21 */
return 3;
}
else if (ident < (1u << 28)) { /* 28 */
return 4;
}
return 5;
}