aboutsummaryrefslogtreecommitdiffstats
path: root/addons/ooh323c/src/encode.c
diff options
context:
space:
mode:
authorrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2009-06-30 16:40:38 +0000
committerrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2009-06-30 16:40:38 +0000
commite9d15cbea7a98184521c851500176da7aa424012 (patch)
treed3d6aa7ea86d11ecaa6e88efbc46a5dde1c63ea5 /addons/ooh323c/src/encode.c
parentb85bdd32a783a8f07004d41db8a696645685a331 (diff)
Move Asterisk-addons modules into the main Asterisk source tree.
Someone asked yesterday, "is there a good reason why we can't just put these modules in Asterisk?". After a brief discussion, as long as the modules are clearly set aside in their own directory and not enabled by default, it is perfectly fine. For more information about why a module goes in addons, see README-addons.txt. chan_ooh323 does not currently compile as it is behind some trunk API updates. However, it will not build by default, so it should be okay for now. git-svn-id: http://svn.digium.com/svn/asterisk/trunk@204413 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'addons/ooh323c/src/encode.c')
-rw-r--r--addons/ooh323c/src/encode.c1103
1 files changed, 1103 insertions, 0 deletions
diff --git a/addons/ooh323c/src/encode.c b/addons/ooh323c/src/encode.c
new file mode 100644
index 000000000..45e5916df
--- /dev/null
+++ b/addons/ooh323c/src/encode.c
@@ -0,0 +1,1103 @@
+/*
+ * 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;
+}