blob: 83595df02d4d7fd5d7aa0a2f20961d0e6061d782 [file] [log] [blame]
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* Licensed 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.
* -------------------------------------------------------------------
*/
// ----------------------------------------------------------------------
//
// This Software is an original work of authorship of PacketVideo Corporation.
// Portions of the Software were developed in collaboration with NTT DoCoMo,
// Inc. or were derived from the public domain or materials licensed from
// third parties. Title and ownership, including all intellectual property
// rights in and to the Software shall remain with PacketVideo Corporation
// and NTT DoCoMo, Inc.
//
// -----------------------------------------------------------------------
// ============================================================
// FILE: GenericPER.c
//
// DESCRIPTION: Generic PER encode/decode routines. These are
// called by the automatically generated MiniParser code.
//
// Written by Ralph Neff, PacketVideo, 2/8/2000
// (c) 2000 PacketVideo Corp.
// ============================================================
#include "per_headers.h"
#include "analyzeper.h"
#include "genericper.h"
#include "oscl_error_codes.h"
#include "oscl_mem.h"
#include "oscl_stdstring.h"
#include "pvlogger.h"
#define STREAM_ADDITION 64 /* Output stream grows in increments */
/* of this many bytes. */
const uint8 MaskBit[] = { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
/***********************************************************/
/*=========================================================*/
/*============ DECODING ROUTINES (Generic PER) ============*/
/*=========================================================*/
/***********************************************************/
/* --------------------------------------------- */
/* ------------- LOW LEVEL STREAM -------------- */
/* --------------------------------------------- */
// =========================================================
// ErrorMessage()
//
// This function is a generic error call for PER routines.
//
// NOTE: Removed the MessageBox called and replaced with a
// call to the analyzer via Show245(). Since tag informaion
// isn't easy to get (encoder/decoder autogen routines don't
// provide tags, and deleter autogen routines don't even have
// a tag defined!), we will fix to the "PER Decoder" tag for
// now. The proper thing to do would be to use a newly
// defined "PER Error" tag. But it's not so important to
// do this, since the source of the error is always defined
// in the message itself. (RAN-MessageBox) 10/5/01
// =========================================================
void ErrorMessage(const char *msg)
{
OSCL_UNUSED_ARG(msg);
PVLogger *logger = PVLogger::GetLoggerObject("3g324m.h245.per");
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, logger, PVLOGMSG_ERR, (0, "GenericPer::ErrorMessage - %s", msg));
}
void ErrorMessageAndLeave(const char *msg)
{
ErrorMessage(msg);
PVLogger *logger = PVLogger::GetLoggerObject("3g324m.h245.per");
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, logger, PVLOGMSG_ERR, (0, "GenericPer::ErrorMessageAndLeave - LEAVE"));
OSCL_LEAVE(OsclErrCorrupt);
}
// =========================================================
// ReadBits()
//
// This function reads some number of bits from the
// input stream.
// =========================================================
uint8 ReadBits(uint32 number, PS_InStream stream)
{
uint8 x;
uint8 NextBit, BitSize;
if (number > 8)
{
ErrorMessageAndLeave("ReadBits(): Max number (8) exceeded");
}
BitSize = (uint8)(stream->bitIndex + number);
x = (uint8)(stream->data[0] & MaskBit[(int)stream->bitIndex ]);
if (BitSize > 8)
{
NextBit = (uint8)(BitSize - 8);
x <<= NextBit;
++stream->data;
x |= ((stream->data[0]) & ~MaskBit[(int)stream->bitIndex ]) >> (8 - NextBit);
}
else if (BitSize < 8)
{
NextBit = BitSize;
x >>= (8 - NextBit);
}
else
{
NextBit = 0;
++stream->data;
}
stream->bitIndex = NextBit;
return(x);
}
// =========================================================
// ReadRemainingBits()
//
// This function advances to the next octet boundary in
// the input stream. If the stream already points to
// an octet boundary, no action is taken.
// =========================================================
void ReadRemainingBits(PS_InStream stream)
{
if (stream->bitIndex)
{
stream->bitIndex = 0;
++stream->data;
}
}
// =========================================================
// ReadOctets()
//
// This function reads one or more octets from the input
// stream. Input arguments are:
// uint32 number; /* Number of octets to read */
// uint8* octets; /* Destination for octets */
// uint8 reorder; /* Reorder for little-endian machine? */
// PS_InStream stream; /* Input stream */
// =========================================================
void ReadOctets(uint32 number, uint8* octets, uint8 reorder, PS_InStream stream)
{
ReadRemainingBits(stream); /* Octet alignment */
if (number == 0) /* No action */
{
return;
}
else if (number <= 4 && reorder) /* Apply reordering */
{
switch (number)
{
case 1:
octets[0] = stream->data[0];
break;
case 2:
octets[0] = stream->data[1];
octets[1] = stream->data[0];
break;
case 3:
octets[0] = stream->data[2];
octets[1] = stream->data[1];
octets[2] = stream->data[0];
break;
case 4:
octets[0] = stream->data[3];
octets[1] = stream->data[2];
octets[2] = stream->data[1];
octets[3] = stream->data[0];
break;
}
}
else
{
oscl_memcpy(octets, stream->data, number); /* Straight copy */
}
stream->data += number;
}
/* --------------------------------------------- */
/* ------------ HIGH LEVEL ASN DATA ------------ */
/* --------------------------------------------- */
// =========================================================
// GetBoolean()
//
// This function reads a boolean from the input stream.
// =========================================================
uint8 GetBoolean(PS_InStream stream)
{
return(ReadBits(1, stream));
}
// =========================================================
// GetInteger() X.691 Section 10.5
//
// This function decodes a constrained integer, given the
// lower/upper bounds. Note that bounds are uint32, which
// means min>=0, max<=4294967295.
// Assumes ALIGNED variant of PER.
// =========================================================
uint32 GetInteger(uint32 lower, uint32 upper, PS_InStream stream)
{
uint32 value = 0, range;
uint8 nbits, nbytes = 0;
if (lower > upper)
{
ErrorMessageAndLeave("GetInteger(): Range is negative.");
return(lower);
}
range = upper - lower + 1;
if (range == 0) /* Special case: int32EGER(0..4294967295) */
{
nbytes = (uint8)(ReadBits(2, stream) + 1);
ReadOctets(nbytes, (uint8*)&value, 1, stream);
return(value);
}
else if (range == 1) /* 0-bits */
return(lower);
else if (range < 256) /* Bit-field cases */
{
if (range <= 2) nbits = 1;
else if (range <= 4) nbits = 2;
else if (range <= 8) nbits = 3;
else if (range <= 16) nbits = 4;
else if (range <= 32) nbits = 5;
else if (range <= 64) nbits = 6;
else if (range <= 128) nbits = 7;
else nbits = 8;
value = ReadBits(nbits, stream);
if (lower + value > upper)
{
ErrorMessageAndLeave("GetInteger(): Integer exceeds range");
}
return(lower + value);
}
else /* One or more octets */
{
if (range == 256) nbytes = 1;
else if (range <= 65536) nbytes = 2;
else nbytes = (uint8)(ReadBits(2, stream) + 1);
ReadOctets(nbytes, (uint8*)&value, 1, stream);
if (lower + value > upper)
{
ErrorMessageAndLeave("GetInteger(): exceeds range");
}
return(lower + value);
}
}
// =========================================================
// GetSignedInteger() X.691 Section 10.5
//
// This function decodes a constrained integer, given the
// lower/upper bounds. The only difference from GetInteger()
// is that the bounds and returned values are int32, and
// so may be negative.
// Assumes ALIGNED variant of PER.
// =========================================================
int32 GetSignedInteger(int32 lower, int32 upper, PS_InStream stream)
{
int32 value = 0, range;
uint8 nbits, nbytes = 0;
if (lower > upper)
{
ErrorMessageAndLeave("GetSignedInteger(): Range is negative.");
return(lower);
}
range = upper - lower + 1;
if (range == 0)
{
ErrorMessageAndLeave("GetSignedInteger(): Range is zero.");
return(lower);
}
else if (range == 1) /* 0-bits */
return(lower);
else if (range < 256) /* Bit-field cases */
{
if (range <= 2) nbits = 1;
else if (range <= 4) nbits = 2;
else if (range <= 8) nbits = 3;
else if (range <= 16) nbits = 4;
else if (range <= 32) nbits = 5;
else if (range <= 64) nbits = 6;
else if (range <= 128) nbits = 7;
else nbits = 8;
value = ReadBits(nbits, stream);
if (lower + value > upper)
{
ErrorMessageAndLeave("GetSignedInteger(): Integer exceeds range");
}
return(lower + value);
}
else /* One or more octets */
{
if (range == 256) nbytes = 1;
else if (range <= 65536) nbytes = 2;
else nbytes = (uint8)(ReadBits(2, stream) + 1);
ReadOctets(nbytes, (uint8*)&value, 1, stream);
if (lower + value > upper)
{
ErrorMessageAndLeave("GetSignedInteger(): GetInteger exceeds range");
}
return(lower + value);
}
}
// =========================================================
// GetUnboundedInteger() X.691 Section 12
// and also 10.4, 10.9.
//
// This function decodes an unbounded integer. The structure
// definition can only accomodate a uint32 return type, so if
// the decoded value is negative, we signal an error.
// Assumes ALIGNED variant of PER.
// =========================================================
uint32 GetUnboundedInteger(PS_InStream stream)
{
uint32 nbytes, value = 0;
nbytes = GetLengthDet(stream); // Length Det (10.9)
ReadOctets(nbytes, (uint8*)&value, 1, stream); // Value (10.4)
// Check for negative value
if ((nbytes == 1 && value >= 0x7f) ||
(nbytes == 2 && value >= 0x8000) ||
(nbytes == 3 && value >= 0x800000) ||
(nbytes == 4 && value >= 0x80000000))
{
ErrorMessageAndLeave("GetUnboundedInteger: Found a negative value!");
}
return(value);
}
// =========================================================
// GetExtendedInteger() X.691 Section 12.1
//
// This function decodes a constrained integer with an
// extended range. We assume the value is unsigned, and
// that the ALIGNED variant of PER is used.
// =========================================================
uint32 GetExtendedInteger(uint32 lower, uint32 upper, PS_InStream stream)
{
uint32 extension_bit, value;
extension_bit = ReadBits(1, stream);
if (extension_bit)
{
value = GetUnboundedInteger(stream);
}
else
{
value = GetInteger(lower, upper, stream);
}
return(value);
}
// =========================================================
// GetOctetString() X.691 Section 16
//
// This function reads an OCTET STRING from the input stream.
// Bounds on the size, if any, are included in the input
// arguments.
// =========================================================
void GetOctetString(uint8 unbounded, uint32 min, uint32 max,
PS_OCTETSTRING x, PS_InStream stream)
{
if (unbounded) /* ====Size is unbounded==== */
{
x->size = (uint16) GetLengthDet(stream);
if (x->size)
{
x->data = (uint8*) OSCL_DEFAULT_MALLOC(x->size * sizeof(uint8));
ReadOctets(x->size, x->data, 0, stream);
}
else
{
x->data = NULL;
}
}
else /* ====Size is bounded==== */
{
if (min > max) /* Error handling */
{
ErrorMessageAndLeave("GetOctetString(): Constraint error (min>max)");
}
if (min == max) /* Fixed size (no length det!) */
{
x->size = (uint16) min;
if (x->size)
{
x->data = (uint8*) OSCL_DEFAULT_MALLOC(x->size * sizeof(uint8));
if (x->size > 2)
{
ReadOctets(x->size, x->data, 0, stream);
}
else if (x->size == 2)
{
x->data[0] = ReadBits(8, stream);
x->data[1] = ReadBits(8, stream);
}
else if (x->size == 1)
{
x->data[0] = ReadBits(8, stream);
}
}
else
{
x->data = NULL;
}
}
else /* Constrained size */
{
x->size = (uint16) GetInteger(min, max, stream);
if (x->size)
{
x->data = (uint8*) OSCL_DEFAULT_MALLOC(x->size * sizeof(uint8));
ReadOctets(x->size, x->data, 0, stream);
}
else
{
x->data = NULL;
}
}
}
}
// =========================================================
// GetBitString() X.691 Section 16
//
// This function reads a BIT STRING from the input stream.
// Bounds on the size, if any, are included in the input
// arguments. The BITSTRING structure (x) is returned.
// =========================================================
void GetBitString(uint8 unbounded, uint32 min, uint32 max,
PS_BITSTRING x, PS_InStream stream)
{
uint32 count;
uint8* temp;
if (unbounded) /* ====Size is unbounded==== */
{
count = GetLengthDet(stream);
x->size = (uint16) count;
temp = x->data = (uint8*) OSCL_DEFAULT_MALLOC((1 + x->size / 8) * sizeof(uint8));
while (count >= 8)
{
temp[0] = ReadBits(8, stream);
++temp;
count -= 8;
}
temp[0] = (uint8)(ReadBits(count, stream) << (8 - count));
}
else /* ====Size is bounded==== */
{
if (min > max) /* Error handling */
{
ErrorMessageAndLeave("GetBitString(): Constraint error (min>max)");
}
if (min == max) /* Fixed size (no length det!) */
{
count = min;
x->size = (uint16) count;
temp = x->data = (uint8*) OSCL_DEFAULT_MALLOC((1 + x->size / 8) * sizeof(uint8));
if (x->size > 16)
{
ReadRemainingBits(stream); /* Octet align */
}
while (count >= 8)
{
temp[0] = ReadBits(8, stream);
++temp;
count -= 8;
}
temp[0] = (uint8)(ReadBits(count, stream) << (8 - count));
}
else /* Constrained size */
{
count = GetInteger(min, max, stream);
x->size = (uint16) count;
temp = x->data = (uint8*) OSCL_DEFAULT_MALLOC((1 + x->size / 8) * sizeof(uint8));
ReadRemainingBits(stream);
while (count >= 8)
{
temp[0] = ReadBits(8, stream);
++temp;
count -= 8;
}
}
}
}
// =========================================================
// GetCharString() (RAN-UII)
//
// This function decodes a character string from a stream.
// Currently it only handles the special case of DTMF user
// input (that is, signalType in UserInputIndication).
// However, it should be straightforward to extend this
// to handle generic restrictions on the four common
// types (IA5String, NumericString, PrintableString,
// and VisibleString). See X.691 Clause 26.5 for details.
// NOTE: For now I'm adding NULL string termination so that
// the analyzer (ShowPERCharString() ) will correctly display
// it on the decode side. Should correct this at some point,
// since x->data should really only contain characters that
// were pulled from the input stream.
// =========================================================
void GetCharString(const char *stringName,
uint8 unbounded, uint32 min, uint32 max, const char *from,
PS_int8STRING x, PS_InStream stream)
{
if (oscl_strncmp(stringName, "IA5String", oscl_strlen("IA5String")) == 0 && // Validate DTMF UII case
unbounded == 0 &&
min == 1 &&
max == 1 &&
oscl_strncmp(from, "0123456789#*ABCD!", oscl_strlen("0123456789#*ABCD!")) == 0)
{
x->size = 2;
x->data = (uint8*) OSCL_DEFAULT_MALLOC(x->size * sizeof(uint8));
x->data[0] = ReadBits(8, stream); // Read single character,
// Normal ascii value, not octet aligned
x->data[1] = 0; // NULL terminate
}
else if (oscl_strncmp(stringName, "GeneralString", oscl_strlen("GeneralString")) == 0) // Validate GeneralString case (RAN-ALPHA)
{
x->size = (uint16)(1 + GetLengthDet(stream)); // (leave extra space for NULL)
x->data = (uint8*) OSCL_DEFAULT_MALLOC(x->size * sizeof(uint8));
ReadOctets(x->size - 1, x->data, 1, stream);
x->data[x->size-1] = 0; // NULL terminate
}
else
{
x->size = 0;
x->data = NULL;
ErrorMessageAndLeave("GetCharString(): Not yet implemented.");
}
}
// =========================================================
// GetObjectID() X.691 Section 23
//
// This function reads an OBJECT IDENTIFIER from the input
// stream. This is just a length determinant, followed by
// a variable number of octets.
// =========================================================
void GetObjectID(PS_OBJECTIDENT x, PS_InStream stream)
{
x->size = (uint16) GetLengthDet(stream);
if (x->size)
{
x->data = (uint8*) OSCL_DEFAULT_MALLOC(x->size * sizeof(uint8));
ReadOctets(x->size, x->data, 0, stream);
}
else
{
x->data = NULL;
}
}
/* --------------------------------------------- */
/* --------------- OTHER CALLS ------------------*/
/* --------------------------------------------- */
// =========================================================
// GetLengthDet() X.691 Section 10.9
//
// Decodes a general length determinant from the input
// stream. Assumes ALIGNED variant of PER.
// =========================================================
uint32 GetLengthDet(PS_InStream stream)
{
uint32 length;
uint8 byte1, byte2;
uint8 mask1 = 0x80; /* 10000000 */
uint8 mask2 = 0x40; /* 01000000 */
uint8 mask3 = 0x3f; /* 00111111 */
ReadOctets(1, (uint8*)&byte1, 0, stream); /* Get first byte */
if (!(byte1&mask1)) /* 0xxxxxxx ==>Single octet case */
{
length = (uint32) byte1;
}
else if (!(byte1&mask2)) /* 10xxxxxx ==>Dual octet case */
{
ReadOctets(1, (uint8*)&byte2, 0, stream); /* Second byte */
length = (((uint32)(byte1 & mask3)) << 8) + (int32)byte2;
}
else
{
ErrorMessageAndLeave("GetLengthDet(): Fragmented Length Dets Not Supported.");
return(0);
}
return(length);
}
// =========================================================
// GetNormSmallLength() X.691 Section 10.9.3.4
//
// Decodes a Normally Small length determinant from the
// input stream. (In SEQUENCE, this gets the size of an
// unknown extensions map).
// Assumes ALIGNED variant of PER.
// =========================================================
uint32 GetNormSmallLength(PS_InStream stream)
{
uint8 value = 0;
uint8 mask = 0x40; /* 01000000 */
value = ReadBits(7, stream);
if (value&mask)
{
ErrorMessageAndLeave("GetNormSmallLength(): Range exceeded.");
return(0);
}
return((uint32)value + 1); /* Valid range is 1...64 */
}
// =========================================================
// GetNormSmallValue() X.691 Section 10.6
//
// Decodes a Normally Small Nonnegative Whole Number from
// the input stream.
// (In CHOICE, gets choice index when extension is ON.)
// Assumes ALIGNED variant of PER.
// =========================================================
uint32 GetNormSmallValue(PS_InStream stream)
{
uint8 value = 0;
uint8 mask = 0x40; /* 01000000 */
value = ReadBits(7, stream);
if (value&mask)
{
ErrorMessageAndLeave("GetNormSmallValue(): range exceeded.");
return(0);
}
return((uint32)value); /* Valid range is 0...63 */
}
// =========================================================
// SkipOneExtension() X.691 Section 18.9
//
// The general length is first read, and that number of
// octets are then skipped.
// (In SEQUENCE, this skips over a single unknown extension.
// In CHOICE, this skips an item that has been chosen from
// the extension, assuming the choice index has already
// been read).
// Assumes aligned variant of PER.
// =========================================================
void SkipOneExtension(PS_InStream stream)
{
uint16 length;
uint8 buffer[32];
length = (uint16) GetLengthDet(stream);
while (length > 32) /* Pieces of at most 32 bytes */
{
ReadOctets(32, buffer, 0, stream);
length -= 32;
}
ReadOctets(length, buffer, 0, stream); /* Leftovers */
}
// =========================================================
// SkipAllExtensions() X.691 Section 18.9
//
// For SEQUENCE, this skips over all unknown extensions.
// This includes reading the SigMap, including size.
// Call this routine at the location of the ext marker [...].
//
// NOTE: This routine may be obsolete. Miniparser code
// instead uses a combination of GetUnknownSigMap() and
// SkipUnreadExtensions().
// =========================================================
void SkipAllExtensions(PS_InStream stream)
{
uint32 size, i, num_to_skip = 0;
size = GetNormSmallLength(stream); /* Length of SigMap */
/* Read sigmap, counting number of significant extensions */
for (i = 0;i < size;++i)
{
num_to_skip += ReadBits(1, stream);
}
for (i = 0;i < num_to_skip;++i)
{
SkipOneExtension(stream);
}
}
// =========================================================
// GetChoiceIndex() X.691 Sections 22.4 - 22.8
//
// Reads the extension bit and choice index from the input
// stream, and constructs a (possibly extended) choice index.
// Assumes ALIGNED variant of PER.
// ---------------------------------------------------------
// Inputs: rootnum (number of objects in root)
// extmarker (0 if no extension marker, 1 otherwise)
// =========================================================
uint16 GetChoiceIndex(uint32 rootnum, uint8 extmarker, PS_InStream stream)
{
uint8 extension;
uint16 index;
extension = 0;
if (extmarker) /* Get extension bit */
{
extension = ReadBits(1, stream);
}
if (!extension) /* ---Item in root--- */
{
if (rootnum == 1) /* Trivial index */
{
return(0);
}
else /* Standard index */
{
index = (uint16) GetInteger(0, rootnum - 1, stream);
} /* ---Item in extension--- */
}
else /* Extended index */
{
index = (uint16)(GetNormSmallValue(stream) + rootnum);
}
return(index);
}
// =========================================================
// GetUnknownSigMap() X.691 Sections 18.7 - 18.8
//
// This function reads an unknown significance map from
// the input stream. This includes the length of the
// significance map, and an options bit corresponding to
// each of the possible extension items. The completed
// map is returned in a special structure.
// =========================================================
PS_UnknownSigMap GetUnknownSigMap(PS_InStream stream)
{
int32 i;
PS_UnknownSigMap x;
x = (PS_UnknownSigMap) OSCL_DEFAULT_MALLOC(sizeof(S_UnknownSigMap));
x->size = (uint16) GetNormSmallLength(stream);
x->optionFlags = (uint8*) OSCL_DEFAULT_MALLOC(x->size * sizeof(uint8));
for (i = 0;i < x->size;++i)
{
x->optionFlags[i] = ReadBits(1, stream);
}
x->extensionsRead = 0;
return(x);
}
// =========================================================
// SigMapValue()
//
// This function reads a single options flag from an
// unknown significance map (UnknownSigMap). If the
// index of the desired value exceeds the size of the
// map, the return value is zero.
// =========================================================
uint8 SigMapValue(uint32 index, PS_UnknownSigMap map)
{
if (index < map->size)
{
return(map->optionFlags[index]);
}
else
{
return(0);
}
}
// =========================================================
// ExtensionPrep()
//
// This function is called immediately before reading each
// unknown extension item in a SEQUENCE. It performs two
// actions:
// 1. Records within the unknown sigmap that another
// extension is being read (++map->extensionsRead).
// This is so SkipUnreadExtensions() later knows
// how many extensions should be skipped.
// 2. Reads and discards the length wrapper from the
// input stream.
// =========================================================
void ExtensionPrep(PS_UnknownSigMap map, PS_InStream stream)
{
++map->extensionsRead;
GetLengthDet(stream);
}
// =========================================================
// SkipUnreadExtensions()
//
// This function skips any unread (and possibly unknown) items
// in the extension of a SEQUENCE. In order for this to work,
// previously read extension items must have been counted in
// map->extensionsRead; see ExtensionPrep() for details.
//
// This routine takes the following actions:
// 1. Uses map->extensionsRead to determine how many
// extension items remain in the input stream.
// 2. Skips remaining extension items.
// 3. Frees the UnknownSigMap.
// 4. Returns the number of extensions skipped.
// =========================================================
uint32 SkipUnreadExtensions(PS_UnknownSigMap map, PS_InStream stream)
{
uint32 i, numExtensions;
/* Compute the number of extensions to skip */
numExtensions = 0;
for (i = 0;i < map->size;++i)
{
numExtensions += map->optionFlags[i];
}
numExtensions -= map->extensionsRead;
/* Skip remaining extensions */
for (i = 0;i < numExtensions;++i)
{
SkipOneExtension(stream);
}
/* Free map, return number skipped */
OSCL_DEFAULT_FREE(map->optionFlags);
OSCL_DEFAULT_FREE(map);
return(numExtensions);
}
// =========================================================
// SkipOneOctet()
//
// Skip a single octet. This is used when a NULL is
// read from the extension of a CHOICE (since an empty
// octet is present)
// =========================================================
void SkipOneOctet(PS_InStream stream)
{
uint8 temp;
ReadOctets(1, &temp, 0, stream);
}
/***********************************************************/
/*=========================================================*/
/*============ ENCODING ROUTINES (Generic PER) ============*/
/*=========================================================*/
/***********************************************************/
/* --------------------------------------------- */
/* ------------- LOW LEVEL STREAM -------------- */
/* --------------------------------------------- */
// =========================================================
// WriteBits()
//
// This function writes some number of bits to the
// output stream.
// =========================================================
void WriteBits(uint32 number, uint8 bits, PS_OutStream stream)
{
uint8 BitSize;
uint8 temp;
BitSize = (uint8)((stream->bitIndex) + number);
temp = (uint8)(bits << (8 - number));
(stream->buildByte) |= (temp >> (stream->bitIndex));
if (BitSize > 8) /* Appended size > 8 bits */
{
stream->bitIndex = 8;
WriteRemainingBits(stream);
stream->buildByte = (uint8)((bits) << (16 - BitSize));
stream->bitIndex = (uint16)(BitSize - 8);
return;
}
else if (BitSize < 8) /* Appended size < 8 bits */
{
stream->bitIndex = BitSize;
return;
}
else /* Appended size == 8 bits */
{
stream->bitIndex = 8;
WriteRemainingBits(stream);
return;
}
}
// =========================================================
// WriteRemainingBits()
//
// This function advances to the next octet boundary in
// the output stream. Zero-bit padding is done, if needed.
// If the stream already points to an octet boundary, no
// action is taken.
// =========================================================
void WriteRemainingBits(PS_OutStream stream)
{
if (stream->bitIndex)
{
if (stream->byteIndex + 1 > stream->size)
{
ExpandOutStream(stream);
}
stream->data[stream->byteIndex] = stream->buildByte;
++stream->byteIndex;
stream->bitIndex = 0;
stream->buildByte = 0;
}
}
// =========================================================
// WriteOctets()
//
// This function writes one or more octets to the output
// stream. Input arguments are:
// uint32 number; /* Number of octets to write */
// uint8* octets; /* Source for octets */
// uint8 reorder; /* Reorder for little-endian machine? */
// PS_OutStream stream; /* Output stream */
// =========================================================
void WriteOctets(uint32 number, uint8* octets, uint8 reorder, PS_OutStream stream)
{
uint8* destination;
WriteRemainingBits(stream); /* Octet alignment */
/* Expand the stream, if needed */
while (stream->byteIndex + number > stream->size)
{
ExpandOutStream(stream);
}
/* Write the octets to stream */
destination = stream->data + stream->byteIndex;
if (number == 0) /* No action */
{
return;
}
else if (number <= 4 && reorder) /* Apply reordering */
{
switch (number)
{
case 1:
destination[0] = octets[0];
break;
case 2:
destination[0] = octets[1];
destination[1] = octets[0];
break;
case 3:
destination[0] = octets[2];
destination[1] = octets[1];
destination[2] = octets[0];
break;
case 4:
destination[0] = octets[3];
destination[1] = octets[2];
destination[2] = octets[1];
destination[3] = octets[0];
break;
}
}
else
{
oscl_memcpy(destination, octets, number); /* Straight copy */
}
stream->byteIndex = (uint16)(number + stream->byteIndex);
}
// =========================================================
// NewOutStream()
//
// This function creates a new, empty output stream.
// =========================================================
PS_OutStream NewOutStream(void)
{
PS_OutStream x;
x = (PS_OutStream) OSCL_DEFAULT_MALLOC(sizeof(S_OutStream));
x->data = NULL;
x->size = 0;
x->byteIndex = 0;
x->bitIndex = 0;
x->buildByte = 0;
return(x);
}
// =========================================================
// ExpandOutStream()
//
// This function expands an output stream by some number
// of bytes, as defined by STREAM_ADDITION.
// =========================================================
void ExpandOutStream(PS_OutStream x)
{
uint8* tmp = x->data;
x->data = (uint8*) OSCL_DEFAULT_MALLOC(x->size + STREAM_ADDITION);
oscl_memcpy(x->data, tmp, x->size);
if (tmp)
OSCL_DEFAULT_FREE(tmp);
x->size += STREAM_ADDITION;
}
// =========================================================
// FreeOutStream()
//
// This function frees an existing output stream.
// =========================================================
void FreeOutStream(PS_OutStream x)
{
OSCL_DEFAULT_FREE(x->data);
OSCL_DEFAULT_FREE(x);
}
/* ----------------------------------------------- */
/* ------------- HIGH LEVEL ASN DATA ------------- */
/* ----------------------------------------------- */
// =========================================================
// PutBoolean()
//
// This function writes a boolean to the output stream.
// =========================================================
void PutBoolean(uint32 value, PS_OutStream stream)
{
WriteBits(1, (uint8)value, stream);
}
// =========================================================
// PutInteger() X.691 Section 10.5
//
// This function encodes a constrained integer, given the
// lower/upper bounds. Note that bounds and value must be
// uint32. This means 0<= {lower,upper,value} <=4294967295.
// Assumes ALIGNED variant of PER.
// =========================================================
void PutInteger(uint32 lower, uint32 upper, uint32 value, PS_OutStream stream)
{
uint32 range, offset;
uint8 nbits, nbytes = 0;
uint8 code_nbytes;
if (lower > upper)
{
ErrorMessageAndLeave("PutInteger(): Negative range.");
return;
}
if (value < lower)
{
ErrorMessageAndLeave("PutInteger(): Value too small.");
return;
}
if (value > upper)
{
ErrorMessageAndLeave("PutInteger(): Value too large.");
return;
}
range = upper - lower + 1;
offset = value - lower;
if (range == 0 || range > 65536) /* Range exceeds 2-octets */
{
/* (Range==0 means [0,2^32-1] case) */
if (offset < 256) nbytes = 1; /* Send using minimum #octets */
else if (offset < 65536) nbytes = 2;
else if (offset < 16777216) nbytes = 3;
else nbytes = 4;
code_nbytes = (uint8)(nbytes - 1);
WriteBits(2, code_nbytes, stream); /* Send #octets */
WriteOctets(nbytes, (uint8*)&offset, 1, stream); /* Offset value */
return;
}
else if (range == 1) /* 0-bits */
return;
else if (range < 256) /* Bit-field cases */
{
if (range <= 2) nbits = 1;
else if (range <= 4) nbits = 2;
else if (range <= 8) nbits = 3;
else if (range <= 16) nbits = 4;
else if (range <= 32) nbits = 5;
else if (range <= 64) nbits = 6;
else if (range <= 128) nbits = 7;
else nbits = 8;
WriteBits(nbits, (uint8)offset, stream);
return;
}
else if (range == 256) /* One octet */
{
WriteOctets(1, (uint8*)(&offset), 1, stream);
return;
}
else /* range<=65536; Two octet */
{
WriteOctets(2, (uint8*)(&offset), 1, stream);
return;
}
}
// =========================================================
// PutSignedInteger() X.691 Section 10.5
//
// This function encodes a constrained integer, given the
// lower/upper bounds. The only difference from
// PutInteger() is that the bounds and the values are
// of type int32, and so may be negative.
// Assumes ALIGNED variant of PER.
// =========================================================
void PutSignedInteger(int32 lower, int32 upper, int32 value, PS_OutStream stream)
{
int32 range, offset;
uint8 nbits, nbytes = 0;
uint8 code_nbytes;
if (lower > upper)
{
ErrorMessageAndLeave("PutSignedInteger(): Negative range.");
return;
}
if (value < lower)
{
ErrorMessageAndLeave("PutSignedInteger(): Value too small.");
return;
}
if (value > upper)
{
ErrorMessageAndLeave("PutSignedInteger(): Value too large.");
return;
}
range = upper - lower + 1;
offset = value - lower;
if (range == 0 || range > 65536) /* Range exceeds 2-octets */
{
/* (Range==0 means [0,2^32-1] case) */
if (offset < 256) nbytes = 1; /* Send using minimum #octets */
else if (offset < 65536) nbytes = 2;
else if (offset < 16777216) nbytes = 3;
else nbytes = 4;
code_nbytes = (uint8)(nbytes - 1);
WriteBits(2, code_nbytes, stream); /* Send #octets */
WriteOctets(nbytes, (uint8*)&offset, 1, stream); /* Offset value */
return;
}
else if (range == 1) /* 0-bits */
return;
else if (range < 256) /* Bit-field cases */
{
if (range <= 2) nbits = 1;
else if (range <= 4) nbits = 2;
else if (range <= 8) nbits = 3;
else if (range <= 16) nbits = 4;
else if (range <= 32) nbits = 5;
else if (range <= 64) nbits = 6;
else if (range <= 128) nbits = 7;
else nbits = 8;
WriteBits(nbits, (uint8)offset, stream);
return;
}
else if (range == 256) /* One octet */
{
WriteOctets(1, (uint8*)(&offset), 1, stream);
return;
}
else /* range<=65536; Two octet */
{
WriteOctets(2, (uint8*)(&offset), 1, stream);
return;
}
}
// =========================================================
// PutUnboundedInteger() X.691 Section 12
// and also 10.4, 10.9.
//
// This function encodes an unbounded integer, which we
// currently assume has type uint32. We'd need to make
// special arrangements if negative values are allowed.
// Assumes ALIGNED variant of PER.
// =========================================================
void PutUnboundedInteger(uint32 value, PS_OutStream stream)
{
uint32 nbytes;
/* The encoding is min-octets, and so depends on value */
if (value < 128)
nbytes = 1;
else if (value < 32768)
nbytes = 2;
else if (value < 8388608)
nbytes = 3;
else
nbytes = 4;
/* Send length det, followed by 2's complement encoding */
PutLengthDet(nbytes, stream);
WriteOctets(nbytes, (uint8*)(&value), 1, stream);
}
// =========================================================
// PutExtendedInteger() X.691 Section 12.1
//
// This function encodes a constrained integer with an
// extended range. We assume the value is unsigned, and
// that the ALIGNED variant of PER is used.
// =========================================================
void PutExtendedInteger(uint32 lower, uint32 upper, uint32 value, PS_OutStream stream)
{
if (value > upper) // Extension ON
{
WriteBits(1, 1, stream);
PutUnboundedInteger(value, stream);
}
else // Extension OFF
{
WriteBits(1, 0, stream);
PutInteger(lower, upper, value, stream);
}
}
// =========================================================
// PutOctetString() X.691 Section 16
//
// This function writes an OCTET STRING to the output stream.
// Bounds on the size, if any, are included in the input
// arguments. The OCTETSTRING structure (x) is freed at
// the end.
// =========================================================
void PutOctetString(uint8 unbounded, uint32 min, uint32 max,
PS_OCTETSTRING x, PS_OutStream stream)
{
if (unbounded) /* ====Size is unbounded==== */
{
PutLengthDet(x->size, stream);
WriteOctets(x->size, x->data, 0, stream);
}
else /* ====Size is bounded==== */
{
if (min > max) /* Error handling */
{
ErrorMessageAndLeave("PutOctetString(): Constraint error (min>max)");
}
else if ((x->size < min) || (x->size > max))
{
ErrorMessageAndLeave("PutOctetString(): Size out of bounds");
}
if (min == max) /* Fixed size (no length det!) */
{
if (x->size > 2)
{
WriteOctets(x->size, x->data, 0, stream);
}
else if (x->size == 2)
{
WriteBits(8, x->data[0], stream);
WriteBits(8, x->data[1], stream);
}
else if (x->size == 1)
{
WriteBits(8, x->data[0], stream);
}
}
else /* Constrained size */
{
PutInteger(min, max, x->size, stream);
WriteOctets(x->size, x->data, 0, stream);
}
}
}
// =========================================================
// PutBitString() X.691 Section 16
//
// This function writes a BIT STRING to the output stream.
// Bounds on the size, if any, are included in the input
// arguments. The BITSTRING structure (x) is freed at
// the end.
// =========================================================
void PutBitString(uint8 unbounded, uint32 min, uint32 max,
PS_BITSTRING x, PS_OutStream stream)
{
uint32 count;
uint8* temp;
count = x->size;
temp = x->data;
if (unbounded) /* ====Size is unbounded==== */
{
PutLengthDet(x->size, stream);
while (count >= 8)
{
WriteBits(8, temp[0], stream);
++temp;
count -= 8;
}
WriteBits(count, (uint8)(temp[0] >> (8 - count)), stream);
}
else /* ====Size is bounded==== */
{
if (min > max) /* Error handling */
{
ErrorMessageAndLeave("PutBitString(): Constraint error (min>max)");
}
else if ((x->size < min) || (x->size > max))
{
ErrorMessageAndLeave("PutBitString(): Size out of bounds");
}
if (min == max) /* Fixed size (no length det!) */
{
if (x->size > 16)
{
WriteRemainingBits(stream); /* Octet align */
}
while (count >= 8)
{
WriteBits(8, temp[0], stream);
++temp;
count -= 8;
}
WriteBits(count, (uint8)(temp[0] >> (8 - count)), stream);
}
else /* Constrained size */
{
PutInteger(min, max, x->size, stream);
WriteRemainingBits(stream);
while (count >= 8)
{
WriteBits(8, temp[0], stream);
++temp;
count -= 8;
}
WriteBits(count, (uint8)(temp[0] >> (8 - count)), stream);
}
}
}
// =========================================================
// PutCharString() (RAN-UII)
//
// This function encodes a character string to a stream.
// Currently it only handles the special case of DTMF user
// input (that is, signalType in UserInputIndication).
// However, it should be straightforward to extend this
// to handle generic restrictions on the four common
// types (IA5String, NumericString, PrintableString,
// and VisibleString). See X.691 Clause 26.5 for details.
// =========================================================
void PutCharString(const char *stringName,
uint8 unbounded, uint32 min, uint32 max, const char *from,
PS_int8STRING x, PS_OutStream stream)
{
if (oscl_strncmp(stringName, "IA5String", oscl_strlen("IA5String")) == 0 && // Validate DTMF UII case
unbounded == 0 &&
min == 1 &&
max == 1 &&
oscl_strncmp(from, "0123456789#*ABCD!", oscl_strlen("0123456789#*ABCD!")) == 0)
{
WriteBits(8, x->data[0], stream); // Write single character,
// Normal ascii value, not octet aligned
}
else if (oscl_strncmp(stringName, "GeneralString", oscl_strlen("GeneralString")) == 0) // Validate GeneralString case (RAN-ALPHA)
// ------------------------------------------------------------------------
// Note on GeneralString: as far as I can tell this is treated as a
// restricted character string type which is not a known-multiplier character
// string. As such it falls under clause 26.6 of X.691. In this case, any
// constraints passed from the PER encoder are not considered 'PER-visible'
// and so they are not used. Because of this, the following should be a
// complete implementation of GeneralString (regardless of constraints).
// It should work for alphanumeric, and anything else that would use
// GeneralString.
// ------------------------------------------------------------------------
// Note also: I assume you need to install the primary graphic character
// set described in T.51, i.e. that there is no default character set.
// Invoking a character set means sending an escape code. Whether you NEED
// this to get the primary character set wasn't made clear in T.51
// itself, though I found a hint elsewhere that suggested you have to send
// the escape code. The escape code is 27 40 66 15 (or in T.51 lingo,
// "ESC 2/8 4/2 0/15"). Sending this code shouldn't hurt anything if the
// receiving end is compliant to T.51, but if it doesn't work on the first
// try, then one thing you guys might try is removing the escape code, in
// case maybe the VIG is choking on it. Comment out the relevant four lines
// below, and also get rid of the extra '4+' in the length calculation.
// BTW, the escape sequence breaks down into:
// "Designate primary T.51 character set as G0" -- 27 40 66
// "Invoke G0 as the current character set" -- 15
// ------------------------------------------------------------------------
{
#if 0
// Encode length of string, in octets
PutLengthDet(4 + (x->size), stream); // Assumes 4-byte T.51 escape sequence
// Remove the '4+' if the escape sequence is removed.
// Note: PutLengthDet() does octet alignment for us
// Send T.51 escapes
WriteBits(8, 27, stream); // Designate primary T.51 character set as G0; see T.51 clause 2.1.2
WriteBits(8, 40, stream); // (cont'd)
WriteBits(8, 66, stream); // (cont'd)
WriteBits(8, 15, stream); // Invoke character set G0 as current charset; see T.51 clause 3.5
#else
// Encode length of string, in octets
PutLengthDet((x->size), stream); // Assumes 4-byte T.51 escape sequence
// Remove the '4+' if the escape sequence is removed.
// Note: PutLengthDet() does octet alignment for us
#endif
// Send the T.51 encoded character data
WriteOctets(x->size, x->data, 1, stream);
}
else
{
ErrorMessageAndLeave("PutCharString(): Not fully implemented.");
}
}
// =========================================================
// PutObjectID() X.691 Section 23
//
// This function writes an OBJECT IDENTIFIER to the output
// stream. This is just a length determinant, followed by
// a variable number of octets. The OBJECTID structure is
// freed at the end.
// =========================================================
void PutObjectID(PS_OBJECTIDENT x, PS_OutStream stream)
{
PutLengthDet(x->size, stream);
WriteOctets(x->size, x->data, 0, stream);
}
// =========================================================
// PutExtensionNull()
//
// This function encodes a NULL object as an extension.
// =========================================================
void PutExtensionNull(PS_OutStream stream)
{
uint8 temp = 0;
PutLengthDet(1, stream); /* Length wrapper */
WriteOctets(1, &temp, 0, stream); /* Empty octet */
}
// =========================================================
// PutExtensionBoolean()
//
// This function encodes a boolean as an extension.
// =========================================================
void PutExtensionBoolean(uint32 value, PS_OutStream stream)
{
PutLengthDet(1, stream); /* Length wrapper */
PutBoolean(value, stream); /* Boolean */
WriteRemainingBits(stream); /* Complete the octet */
}
// =========================================================
// PutExtensionInteger()
//
// This function encodes an integer as an extension.
// =========================================================
void PutExtensionInteger(uint32 lower, uint32 upper, uint32 value, PS_OutStream stream)
{
PS_OutStream tempStream;
tempStream = NewOutStream(); /* Create a temp stream */
PutInteger(lower, upper, value, tempStream); /* Write integer to temp */
PutTempStream(tempStream, stream); /* Transmit contents of tempStream */
}
// =========================================================
// PutExtensionOctetString()
//
// This function encodes an octet string as an extension.
// =========================================================
void PutExtensionOctetString(uint8 unbounded,
uint32 min, uint32 max, PS_OCTETSTRING x, PS_OutStream stream)
{
PS_OutStream tempStream;
tempStream = NewOutStream(); /* Create a temp stream */
PutOctetString(unbounded, min, max, x, tempStream); /* Write to temp */
PutTempStream(tempStream, stream); /* Transmit contents of tempStream */
}
/* --------------------------------------------- */
/* ---------------- OTHER CALLS -----------------*/
/* --------------------------------------------- */
// =========================================================
// PutNormSmallValue() X.691 Section 10.6
//
// Sends a normally small nonnegative value. Range is
// [0,infinity]. (In CHOICE, this sends the choice index
// when extension is ON).
// Assumes ALIGNED variant of PER.
// =========================================================
void PutNormSmallValue(uint32 value, PS_OutStream stream)
{
uint8 sendval;
if (value < 64)
{
sendval = (uint8) value;
WriteBits(7, sendval, stream);
}
else
{
ErrorMessageAndLeave("PutNormSmallValue(): range exceeded.");
}
}
// =========================================================
// PutChoiceIndex() X.691 Sections 22.4 - 22.8
//
// Writes the extension bit (if needed) and the choice index
// to the bitstream. Assumes ALIGNED variant of PER.
//
// Inputs: rootnum (number of items in root)
// extmarker (0 if no extension marker, 1 otherwise)
// index (choice index, possibly extended)
// =========================================================
void PutChoiceIndex(uint32 rootnum, uint8 extmarker, uint32 index,
PS_OutStream stream)
{
if (!extmarker) /* ---Extension marker NOT present --- */
{
PutInteger(0, rootnum - 1, (uint32)index, stream);
}
else /* ---Extension marker present --- */
{
if (index < rootnum)
{
WriteBits(1, 0, stream); /* Extension bit OFF */
PutInteger(0, rootnum - 1, (uint32)index, stream);
}
else
{
WriteBits(1, 1, stream); /* Extension bit ON */
PutNormSmallValue((uint32)(index - rootnum), stream);
}
}
}
// =========================================================
// PutNormSmallLength() X.691 Section 10.9.3.4
//
// Sends a normally small length determinant. Range is
// [1,infinity]. (For SEQUENCE, this sends the size of
// the SigMap for unknown extensions.)
// Assumes ALIGNED variant of PER.
// =========================================================
void PutNormSmallLength(uint32 value, PS_OutStream stream)
{
uint8 sendval;
if (value < 65)
{
sendval = (uint8)(value - 1);
WriteBits(7, sendval, stream);
}
else
{
ErrorMessageAndLeave("PutNormSmallLength(): range exceeded.");
}
}
// =========================================================
// PutLengthDet() X.691 Section 10.9
//
// Encodes a general length determinant to the output stream.
// (e.g. for extension wrapper).
// Assumes ALIGNED variant of PER.
// =========================================================
void PutLengthDet(uint32 value, PS_OutStream stream)
{
uint8 byte;
uint16 bytes;
uint16 mask = 0x8000; /* 10000000 00000000 */
if (value < 128) /* One octet with leading '0' */
{
byte = (uint8) value;
WriteOctets(1, &byte, 0, stream);
}
else if (value < 16384) /* Two octets with leading '10' */
{
bytes = (uint16)(value | mask);
WriteOctets(2, (uint8*)&bytes, 0, stream);
}
else
{
ErrorMessageAndLeave("PutLengthDet(): Fragmented Length Dets Not Supported.");
}
}
// =========================================================
// PutExtensionItem()
//
// This function writes an extension item, including the
// length wrapper. It makes a generic call to one of the
// H.245-defined PER Encoder routines.
// =========================================================
void PutExtensionItem(
void (*Func)(uint8* data, PS_OutStream stream),
uint8* x, PS_OutStream stream)
{
PS_OutStream tempStream;
tempStream = NewOutStream(); /* Create a temp stream */
Func(x, tempStream); /* Encode x, writing to tempStream */
PutTempStream(tempStream, stream); /* Transmit contents of tempStream */
}
// =========================================================
// PutTempStream()
//
// This function copies the contents of a temporary output
// stream (tempStream) to the main output stream (stream),
// preceeded by a generial length determinant.
// It also frees tempStream at the end.
// =========================================================
void PutTempStream(PS_OutStream tempStream, PS_OutStream stream)
{
WriteRemainingBits(tempStream);
PutLengthDet(tempStream->byteIndex, stream); /* Copy to real stream */
WriteOctets(tempStream->byteIndex, tempStream->data, 0, stream);
FreeOutStream(tempStream);
}
/********************************************************/
/*======================================================*/
/*============ OTHER ROUTINES (Generic PER) ============*/
/*======================================================*/
/********************************************************/
// =========================================================
// ConvertOutstreamToInstream()
//
// This function creates a new InStream and copies into
// it the contents of an old OutStream. This is useful
// for internal testing.
// Note that the outstream is destroyed in the process.
// =========================================================
PS_InStream ConvertOutstreamToInstream(PS_OutStream outstream)
{
PS_InStream instream;
WriteRemainingBits(outstream);
instream = (PS_InStream) OSCL_DEFAULT_MALLOC(sizeof(S_InStream));
instream->data = outstream->data;
instream->bitIndex = 0;
OSCL_DEFAULT_FREE(outstream);
return(instream);
}
// =========================================================
// NewOctetString()
//
// This function creates a new OCTETSTRING.
// For now, the data field just contains the string
// "OctetString".
// Later, I'll add input parameters and construct the
// real thing.
// THIS ROUTINE NEEDS ATTENTION!
// =========================================================
PS_OCTETSTRING NewOctetString(void)
{
PS_OCTETSTRING x;
x = (PS_OCTETSTRING) OSCL_DEFAULT_MALLOC(sizeof(S_OCTETSTRING));
x->size = 12;
x->data = (uint8*) OSCL_DEFAULT_MALLOC(12 * sizeof(uint8));
oscl_strncpy((char *) x->data, "OctetString", x->size);
return(x);
}
// =========================================================
// NewBitString()
//
// This function creates a new BITSTRING.
// For now, the data field just contains the string
// "BitString".
// Later, I'll add input parameters and construct the
// real thing.
// THIS ROUTINE NEEDS ATTENTION!
// =========================================================
PS_BITSTRING NewBitString(void)
{
PS_BITSTRING x;
x = (PS_BITSTRING) OSCL_DEFAULT_MALLOC(sizeof(S_BITSTRING));
x->size = 10;
x->data = (uint8*) OSCL_DEFAULT_MALLOC(10 * sizeof(uint8));
oscl_strncpy((char *) x->data, "BitString", x->size);
return(x);
}
// =========================================================
// NewCharString()
//
// This function creates a new int8STRING.
// For now, the data field just contains the string
// "CharString".
// Later, I'll add input parameters and construct the
// real thing.
// THIS ROUTINE NEEDS ATTENTION!
// =========================================================
PS_int8STRING NewCharString(void)
{
PS_int8STRING x;
x = (PS_int8STRING) OSCL_DEFAULT_MALLOC(sizeof(S_int8STRING));
x->size = 11;
x->data = (uint8*) OSCL_DEFAULT_MALLOC(11 * sizeof(uint8));
oscl_strncpy((char *) x->data, "CharString", x->size);
return(x);
}
// =========================================================
// NewObjectID()
//
// This function creates a new OBJECTID.
// For now, the ID just contains the string "Object ID".
// Later, I'll add input parameters and construct the
// real thing.
// THIS ROUTINE NEEDS ATTENTION!
// =========================================================
PS_OBJECTIDENT NewObjectID(void)
{
PS_OBJECTIDENT x;
x = (PS_OBJECTIDENT) OSCL_DEFAULT_MALLOC(sizeof(S_OBJECTIDENT));
x->size = 10;
x->data = (uint8*) OSCL_DEFAULT_MALLOC(10 * sizeof(uint8));
oscl_strncpy((char *) x->data, "Object ID", x->size);
return(x);
}
// =========================================================
// InitOctetString()
//
// This function inits a previously allocated OCTET STRING.
// For now, the data field just contains the string
// "OctetString".
// Later, I'll add input parameters and construct the
// real thing.
// THIS ROUTINE NEEDS ATTENTION!
// =========================================================
void InitOctetString(PS_OCTETSTRING x)
{
x->size = 12;
x->data = (uint8*) OSCL_DEFAULT_MALLOC(12 * sizeof(uint8));
oscl_strncpy((char *) x->data, "OctetString", x->size);
}
// =========================================================
// InitBitString()
//
// This function inits a previously allocated BIT STRING.
// For now, the data field just contains the string
// "BitString".
// Later, I'll add input parameters and construct the
// real thing.
// THIS ROUTINE NEEDS ATTENTION!
// =========================================================
void InitBitString(PS_BITSTRING x)
{
x->size = 10;
x->data = (uint8*) OSCL_DEFAULT_MALLOC(10 * sizeof(uint8));
oscl_strncpy((char *) x->data, "BitString", x->size);
}
// =========================================================
// InitCharString()
//
// This function inits a previously allocated int8 STRING.
// For now, the data field just contains the string
// "CharString".
// Later, I'll add input parameters and construct the
// real thing.
// THIS ROUTINE NEEDS ATTENTION!
// =========================================================
void InitCharString(PS_int8STRING x)
{
x->size = 11;
x->data = (uint8*) OSCL_DEFAULT_MALLOC(11 * sizeof(uint8));
oscl_strncpy((char *) x->data, "CharString", x->size);
}
// =========================================================
// InitObjectid()
//
// This function inits a previously allocated OBJECT IDENTIFIER.
// For now, the data field just contains the string
// "ObjectID".
// Later, I'll add input parameters and construct the
// real thing.
// THIS ROUTINE NEEDS ATTENTION!
// =========================================================
void InitObjectid(PS_OBJECTIDENT x)
{
x->size = 9;
x->data = (uint8*) OSCL_DEFAULT_MALLOC(9 * sizeof(uint8));
oscl_strncpy((char *) x->data, "ObjectID", x->size);
}
// =========================================================
// FreeOctetString()
//
// This frees an OCTET STRING.
// =========================================================
void FreeOctetString(PS_OCTETSTRING x)
{
if (x->size > 0)
{
OSCL_DEFAULT_FREE(x->data);
}
OSCL_DEFAULT_FREE(x);
}
// =========================================================
// FreeBitString()
//
// This frees a BIT STRING.
// =========================================================
void FreeBitString(PS_BITSTRING x)
{
OSCL_DEFAULT_FREE(x->data);
OSCL_DEFAULT_FREE(x);
}
// =========================================================
// FreeCharString()
//
// This frees a int8 STRING.
// =========================================================
void FreeCharString(PS_int8STRING x)
{
if (x->data)
{
OSCL_DEFAULT_FREE(x->data);
}
OSCL_DEFAULT_FREE(x);
}
// =========================================================
// FreeObjectID()
//
// This frees an OBJECT IDENTIFIER.
// =========================================================
void FreeObjectID(PS_OBJECTIDENT x)
{
OSCL_DEFAULT_FREE(x->data);
OSCL_DEFAULT_FREE(x);
}