| /* ------------------------------------------------------------------ |
| * 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); |
| } |
| |
| |