/* * asner.cxx * * Abstract Syntax Notation 1 Encoding Rules * * Portable Windows Library * * Copyright (c) 1993-2002 Equivalence Pty. Ltd. * * The contents of this file are subject to the Mozilla Public License * Version 1.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.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Original Code is Portable Windows Library. * * The Initial Developer of the Original Code is Equivalence Pty. Ltd. * * Contributor(s): ______________________________________. * * $Log: asner.cxx,v $ * Revision 1.93 2005/11/30 12:47:41 csoutheren * Removed tabs, reformatted some code, and changed tags for Doxygen * * Revision 1.92 2005/11/25 01:01:15 csoutheren * Applied patch #1351168 * PWlib various fixes * * Revision 1.91 2005/06/07 06:25:53 csoutheren * Applied patch 1199897 to increase speed of ASN parser debugging output * Thanks to Dmitriy * * Revision 1.90 2004/07/12 03:42:22 csoutheren * Fixed problem with checking character set constraints too aggressively * * Revision 1.89 2004/07/12 01:56:10 csoutheren * Fixed incorrect asn decoding check * * Revision 1.88 2004/07/11 14:19:07 csoutheren * More bulletproofing of ASN routines against random data attacks * * Revision 1.87 2004/07/11 12:33:47 csoutheren * Added guards against illegal PDU values causing crashes * * Revision 1.86 2004/04/22 07:54:01 csoutheren * Fix problem with VS.net asserting on in isprint when chars outside normal range * * Revision 1.85 2004/04/18 04:33:37 rjongbloed * Changed all operators that return BOOL to return standard type bool. This is primarily * for improved compatibility with std STL usage removing many warnings. * * Revision 1.84 2004/04/03 08:22:20 csoutheren * Remove pseudo-RTTI and replaced with real RTTI * * Revision 1.83 2004/01/17 09:21:21 csoutheren * Added protection against NULL ptr to PASN_Stream::BlockDecode * * Revision 1.82 2003/08/01 02:11:38 csoutheren * Changed to allow easy isolation of PER, BER and XER encoding/decoding routines * * Revision 1.81 2003/04/28 02:50:33 robertj * Fixed problem with spaces in type name, thanks Federico Pinna * * Revision 1.80 2003/02/26 04:37:21 robertj * Tidied some comments * * Revision 1.79 2003/02/26 01:57:44 robertj * Added XML encoding rules to ASN system, thanks Federico Pinna * * Revision 1.78 2003/01/24 23:43:43 robertj * Fixed subtle problems with the use of MAX keyword for unsigned numbers, * should beUINT_MAX not INT_MAX, thanks Stevie Gray for pointing it out. * * Revision 1.77 2002/12/17 07:00:15 robertj * Fixed incorrect encoding of arrays greater than 8192 and less than 16384 * * Revision 1.76 2002/12/13 03:57:17 robertj * Fixed crash if enable extension fields beyond the "known" extensions. * * Revision 1.75 2002/12/02 01:03:33 robertj * Fixed bug were if setting the size of a constrained bit string, it * actually sets the size of the underlying byte array correctly. * * Revision 1.74 2002/11/26 23:29:32 robertj * Added missing const to DecodeSubType() function. * * Revision 1.73 2002/11/22 09:43:32 robertj * Fixed encoding of a ASN NULL sequence extension field, eg fastConnectRefused * * Revision 1.72 2002/11/21 03:46:22 robertj * Changed to encode only the minimum number of bits required, this improves * compatibility with some brain dead ASN decoders. * * Revision 1.71 2002/11/06 22:47:24 robertj * Fixed header comment (copyright etc) * * Revision 1.70 2002/10/31 05:51:10 robertj * Changed to use new UTF-8/UCS-2 conversion functions on PString. * * Revision 1.69 2002/10/29 08:12:44 robertj * Fixed MSVC warnings. * * Revision 1.68 2002/10/29 07:26:45 robertj * Fixed subtle bug when encoding or decoding Octet String with 1 or 2 bytes * in it, was not byte aligned correctly. * * Revision 1.67 2002/09/26 23:53:20 robertj * Fixed incorrect asserts in PASN_Enumerated, thanks Platzer Wolfgang * * Revision 1.66 2002/09/13 08:16:15 robertj * Fixed missing line feed when dumping hex octet strings. * * Revision 1.65 2002/08/06 02:27:58 robertj * GNU C++ v3 compatibility. * * Revision 1.64 2002/07/25 10:52:49 robertj * Changes to allow more granularity in PDU dumps, hex output increasing * with increasing trace level. * * Revision 1.63 2002/06/05 12:29:15 craigs * Changes for gcc 3.1 * * Revision 1.62 2002/05/29 01:22:35 robertj * Added ability to set object id from unsigned integer arrays. * * Revision 1.61 2002/05/21 04:23:40 robertj * Fixed problem with ASN encoding/decoding unsconstrained negative numbers, * * Revision 1.60 2002/05/14 08:34:29 robertj * Fixed problem encoding unsigned where value==lower bound, thanks Greg Adams. * * Revision 1.59 2002/05/14 06:59:50 robertj * Added more bullet proofing so a malformed PDU cannot cause teh decoder * to try and allocate huge arrays and consume all CPU and memory on a * system. A configurable limit of 100 is set for things like SEQUENCE OF. * * Revision 1.58 2002/02/08 12:47:19 robertj * Fixed incorrect encoding of integer, did not allow for sign bit, thanks Kevin Tran. * * Revision 1.57 2002/02/01 01:17:36 robertj * Fixed bug in encoding empty strings (H.450 issue), thanks Frans Dams, Frank Derks et al. * * Revision 1.56 2002/01/30 08:40:55 robertj * Fixed incorrect decode function in BER string decode, thanks ct_dev@sohu.com * * Revision 1.55 2001/12/13 09:13:57 robertj * Added function get get oid as a string. * * Revision 1.54 2001/11/26 03:07:13 robertj * Fixed decode of extendable constrained integer types. * * Revision 1.53 2001/09/14 05:26:11 robertj * Fixed problem with assigning a PASN_Choice to itself, thanks Chih-Wei Huang * * Revision 1.52 2001/09/14 01:59:59 robertj * Fixed problem with incorrectly initialised PASN_Choice sub-object. * * Revision 1.51 2001/08/08 04:19:28 robertj * Fixed PString<->BMPString conversion so can have embedded nulls. * * Revision 1.50 2001/08/07 04:37:03 robertj * Simplified &#num; parsing. * * Revision 1.49 2001/08/07 02:49:05 robertj * Fixed incorrect alignment if constrained string upper bound is exactly * 16 bits long. thanks Guntram Diehl & Thomas Arimont. * * Revision 1.48 2001/08/06 09:35:25 robertj * Fixed GNU compatibility. * * Revision 1.47 2001/08/06 09:31:48 robertj * Added conversion of BMPString to PString without losing special characters. * * Revision 1.46 2001/08/06 01:39:02 robertj * Added assignement operator with RHS of PASN_BMPString to classes * descended from PASN_BMPString. * * Revision 1.45 2001/06/14 02:14:12 robertj * Added functions to encode and decode another ASN type that is inside * an octet string, useful for ANY or EXTERNAL types etc. * * Revision 1.44 2001/05/29 00:59:16 robertj * Fixed excessive padding on constrained strings. * * Revision 1.43 2001/05/22 23:37:42 robertj * Fixed problem with assigning a constrained string value to itself, which * can occur when changing constraints. * * Revision 1.42 2001/04/30 10:47:33 robertj * Fixed stupid error in last patch. * * Revision 1.41 2001/04/30 06:47:04 robertj * Fixed problem with en/decoding more than 16 extension fields in a sequence. * * Revision 1.40 2001/04/26 08:15:58 robertj * Fixed problem with ASN compile of single constraints on enumerations. * * Revision 1.39 2001/04/23 05:46:06 robertj * Fixed problem with unconstrained PASN_NumericString coding in 8 bits * instead of 4, thanks Chew Kuan. * * Revision 1.38 2001/04/23 04:40:14 robertj * Added ASN standard types GeneralizedTime and UTCTime * * Revision 1.37 2001/04/12 03:26:59 robertj * Fixed PASN_Boolean cosntructor to be compatible with usage in ASN parser. * Changed all PASN_xxx types so constructor can take real type as only * parameter. eg PASN_OctetString s = "fred"; * Changed block encode/decode so does not do a ByteAlign() if zero * length, required for interoperability even though spec implies otherwise.. * * Revision 1.36 2001/01/24 04:37:07 robertj * Added more bulletproofing to ASN structures to obey constraints. * * Revision 1.35 2001/01/03 01:20:13 robertj * Fixed error in BlockEncode, should ByteAlign() even on zero length strings. * * Revision 1.34 2000/10/26 11:09:16 robertj * More bullet proofing of PER decoder, changed bit type to be unsigned. * * Revision 1.33 2000/10/26 01:29:32 robertj * Fixed MSVC warning. * * Revision 1.32 2000/10/25 04:05:38 robertj * More bullet proofing of PER decoder. * * Revision 1.31 2000/09/29 04:11:51 robertj * Fixed possible out of range memory access, thanks Petr Parýzek * * Revision 1.30 2000/02/29 06:32:12 robertj * Added ability to remove optional field in sequence, thanks Dave Harvey. * * Revision 1.29 2000/01/20 06:22:22 robertj * Fixed boundary condition error for constrained integer encoding (values 1, 256 etc) * * Revision 1.28 1999/11/22 23:15:43 robertj * Fixed bug in PASN_Choice::Compare(), should make sure choices are the same before comparing. * * Revision 1.27 1999/08/19 15:43:07 robertj * Fixed incorrect size of OID if zero length encoded. * * Revision 1.26 1999/08/09 13:02:45 robertj * dded ASN compiler #defines for backward support of pre GCC 2.9 compilers. * Added ASN compiler #defines to reduce its memory footprint. * * Revision 1.25 1999/08/08 15:45:59 robertj * Fixed incorrect encoding of unknown extensions. * * Revision 1.24 1999/08/05 00:44:28 robertj * Fixed PER encoding problems for large integer values. * * Revision 1.23 1999/07/22 06:48:54 robertj * Added comparison operation to base ASN classes and compiled ASN code. * Added support for ANY type in ASN parser. * * Revision 1.22 1999/07/08 08:39:12 robertj * Fixed bug when assigning negative number ot cosntrained PASN_Integer * * Revision 1.21 1999/06/30 08:58:12 robertj * Fixed bug in encoding/decoding OID greater than 2.39 * * Revision 1.20 1999/06/17 13:27:09 robertj * Fixed bug causing crashes on pass through of unknown extensions. * * Revision 1.19 1999/06/07 00:31:25 robertj * Fixed signed/unsigned problem with number of unknown extensions check. * * Revision 1.18 1999/04/26 05:58:48 craigs * Fixed problems with encoding of extensions * * Revision 1.17 1999/03/09 08:12:38 robertj * Fixed problem with closing a steam encoding twice. * * Revision 1.16 1999/01/16 01:28:25 robertj * Fixed problems with reading stream multiple times. * * Revision 1.15 1998/11/30 04:50:44 robertj * New directory structure * * Revision 1.14 1998/10/22 04:33:11 robertj * Fixed bug in constrained strings and PER, incorrect order of character set. * * Revision 1.13 1998/09/23 06:21:49 robertj * Added open source copyright license. * * Revision 1.12 1998/05/26 05:29:23 robertj * Workaroung for g++ iostream bug. * * Revision 1.11 1998/05/21 04:58:54 robertj * GCC comptaibility. * * Revision 1.10 1998/05/21 04:26:54 robertj * Fixed numerous PER problems. * * Revision 1.9 1998/05/11 06:01:55 robertj * Why did this compile under MSC? * * Revision 1.8 1998/05/07 05:19:29 robertj * Fixed problems with using copy constructor/assignment oeprator on PASN_Objects. * * Revision 1.7 1998/03/05 12:49:50 robertj * MemCheck fixes. * * Revision 1.6 1998/02/03 06:28:27 robertj * Fixed length calculation of integers in BER. * Added new function to read a block with minimum number of bytes. * * Revision 1.5 1998/01/26 01:51:20 robertj * Removed uninitialised variable warnings. * * Revision 1.4 1997/12/18 05:07:56 robertj * Fixed bug in choice name display. * Added function to get choice discriminator name. * Fixed bug in encoding extensions. * * Revision 1.3 1997/12/11 10:36:22 robertj * Support for new ASN parser. * */ #include #ifdef __GNUC__ #pragma implementation "asner.h" #endif #include #if P_EXPAT #include #endif #define new PNEW static PINDEX MaximumArraySize = 128; static PINDEX MaximumStringSize = 16*1024; static PINDEX MaximumSetSize = 512; static PINDEX CountBits(unsigned range) { switch (range) { case 0 : return sizeof(unsigned)*8; case 1: return 1; } size_t nBits = 0; while (nBits < (sizeof(unsigned)*8) && range > (unsigned)(1 << nBits)) nBits++; return nBits; } inline BOOL CheckByteOffset(PINDEX offset, PINDEX upper = MaximumStringSize) { // a 1mbit PDU has got to be an error return (0 <= offset && offset <= upper); } static PINDEX FindNameByValue(const PASN_Names *names, unsigned namesCount, PINDEX value) { if (names != NULL) { for (unsigned int i = 0;i < namesCount;i++) { if (names[i].value == value) return i; } } return P_MAX_INDEX; } /////////////////////////////////////////////////////////////////////// PASN_Object::PASN_Object(unsigned theTag, TagClass theTagClass, BOOL extend) { extendable = extend; tag = theTag; if (theTagClass != DefaultTagClass) tagClass = theTagClass; else tagClass = ContextSpecificTagClass; } void PASN_Object::SetTag(unsigned newTag, TagClass tagClass_) { tag = newTag; if (tagClass_ != DefaultTagClass) tagClass = tagClass_; } PINDEX PASN_Object::GetObjectLength() const { PINDEX len = 1; if (tag >= 31) len += (CountBits(tag)+6)/7; PINDEX dataLen = GetDataLength(); if (dataLen < 128) len++; else len += (CountBits(dataLen)+7)/8 + 1; return len + dataLen; } void PASN_Object::SetConstraintBounds(ConstraintType, int, unsigned) { } void PASN_Object::SetCharacterSet(ConstraintType, const char *) { } void PASN_Object::SetCharacterSet(ConstraintType, unsigned, unsigned) { } PINDEX PASN_Object::GetMaximumArraySize() { return MaximumArraySize; } void PASN_Object::SetMaximumArraySize(PINDEX sz) { MaximumArraySize = sz; } PINDEX PASN_Object::GetMaximumStringSize() { return MaximumStringSize; } void PASN_Object::SetMaximumStringSize(PINDEX sz) { MaximumStringSize = sz; } /////////////////////////////////////////////////////////////////////// PASN_ConstrainedObject::PASN_ConstrainedObject(unsigned tag, TagClass tagClass) : PASN_Object(tag, tagClass) { constraint = Unconstrained; lowerLimit = 0; upperLimit = UINT_MAX; } void PASN_ConstrainedObject::SetConstraintBounds(ConstraintType ctype, int lower, unsigned upper) { constraint = ctype; if (constraint == Unconstrained) { lower = 0; upper = UINT_MAX; } extendable = ctype == ExtendableConstraint; // if ((lower >= 0 && upper < 0x7fffffff) || // (lower < 0 && (unsigned)lower <= upper)) { lowerLimit = lower; upperLimit = upper; // } } /////////////////////////////////////////////////////////////////////// PASN_Null::PASN_Null(unsigned tag, TagClass tagClass) : PASN_Object(tag, tagClass) { } PObject::Comparison PASN_Null::Compare(const PObject & obj) const { PAssert(PIsDescendant(&obj, PASN_Null), PInvalidCast); return EqualTo; } PObject * PASN_Null::Clone() const { PAssert(IsClass(PASN_Null::Class()), PInvalidCast); return new PASN_Null(*this); } void PASN_Null::PrintOn(ostream & strm) const { strm << "<>"; } PString PASN_Null::GetTypeAsString() const { return "Null"; } PINDEX PASN_Null::GetDataLength() const { return 0; } BOOL PASN_Null::Decode(PASN_Stream & strm) { return strm.NullDecode(*this); } void PASN_Null::Encode(PASN_Stream & strm) const { strm.NullEncode(*this); } /////////////////////////////////////////////////////////////////////// PASN_Boolean::PASN_Boolean(BOOL val) : PASN_Object(UniversalBoolean, UniversalTagClass) { value = val; } PASN_Boolean::PASN_Boolean(unsigned tag, TagClass tagClass, BOOL val) : PASN_Object(tag, tagClass) { value = val; } PObject::Comparison PASN_Boolean::Compare(const PObject & obj) const { PAssert(PIsDescendant(&obj, PASN_Boolean), PInvalidCast); return value == ((const PASN_Boolean &)obj).value ? EqualTo : GreaterThan; } PObject * PASN_Boolean::Clone() const { PAssert(IsClass(PASN_Boolean::Class()), PInvalidCast); return new PASN_Boolean(*this); } void PASN_Boolean::PrintOn(ostream & strm) const { if (value) strm << "TRUE"; else strm << "FALSE"; } PString PASN_Boolean::GetTypeAsString() const { return "Boolean"; } PINDEX PASN_Boolean::GetDataLength() const { return 1; } BOOL PASN_Boolean::Decode(PASN_Stream & strm) { return strm.BooleanDecode(*this); } void PASN_Boolean::Encode(PASN_Stream & strm) const { strm.BooleanEncode(*this); } /////////////////////////////////////////////////////////////////////// PASN_Integer::PASN_Integer(unsigned val) : PASN_ConstrainedObject(UniversalInteger, UniversalTagClass) { value = val; } PASN_Integer::PASN_Integer(unsigned tag, TagClass tagClass, unsigned val) : PASN_ConstrainedObject(tag, tagClass) { value = val; } BOOL PASN_Integer::IsUnsigned() const { return constraint != Unconstrained && lowerLimit >= 0; } PASN_Integer & PASN_Integer::operator=(unsigned val) { if (constraint == Unconstrained) value = val; else if (lowerLimit >= 0) { // Is unsigned integer if (val < (unsigned)lowerLimit) value = lowerLimit; else if (val > upperLimit) value = upperLimit; else value = val; } else { int ival = (int)val; if (ival < lowerLimit) value = lowerLimit; else if (upperLimit < INT_MAX && ival > (int)upperLimit) value = upperLimit; else value = val; } return *this; } PObject::Comparison PASN_Integer::Compare(const PObject & obj) const { PAssert(PIsDescendant(&obj, PASN_Integer), PInvalidCast); const PASN_Integer & other = (const PASN_Integer &)obj; if (IsUnsigned()) { if (value < other.value) return LessThan; if (value > other.value) return GreaterThan; } else { if ((int)value < (int)other.value) return LessThan; if ((int)value > (int)other.value) return GreaterThan; } return EqualTo; } PObject * PASN_Integer::Clone() const { PAssert(IsClass(PASN_Integer::Class()), PInvalidCast); return new PASN_Integer(*this); } void PASN_Integer::PrintOn(ostream & strm) const { if (constraint == Unconstrained || lowerLimit < 0) strm << (int)value; else strm << value; } void PASN_Integer::SetConstraintBounds(ConstraintType type, int lower, unsigned upper) { PASN_ConstrainedObject::SetConstraintBounds(type, lower, upper); operator=(value); } PString PASN_Integer::GetTypeAsString() const { return "Integer"; } static PINDEX GetIntegerDataLength(int value) { // create a mask which is the top nine bits of a DWORD, or 0xFF800000 // on a big endian machine int shift = (sizeof(value)-1)*8-1; // remove all sequences of nine 0's or 1's at the start of the value while (shift > 0 && ((value >> shift)&0x1ff) == (value < 0 ? 0x1ff : 0)) shift -= 8; return (shift+9)/8; } PINDEX PASN_Integer::GetDataLength() const { return GetIntegerDataLength(value); } BOOL PASN_Integer::Decode(PASN_Stream & strm) { return strm.IntegerDecode(*this); } void PASN_Integer::Encode(PASN_Stream & strm) const { strm.IntegerEncode(*this); } /////////////////////////////////////////////////////////////////////// PASN_Enumeration::PASN_Enumeration(unsigned val) : PASN_Object(UniversalEnumeration, UniversalTagClass, FALSE),names(NULL),namesCount(0) { value = val; maxEnumValue = P_MAX_INDEX; } PASN_Enumeration::PASN_Enumeration(unsigned tag, TagClass tagClass, unsigned maxEnum, BOOL extend, unsigned val) : PASN_Object(tag, tagClass, extend),names(NULL),namesCount(0) { value = val; maxEnumValue = maxEnum; } PASN_Enumeration::PASN_Enumeration(unsigned tag, TagClass tagClass, unsigned maxEnum, BOOL extend, const PASN_Names * nameSpec, unsigned namesCnt, unsigned val) : PASN_Object(tag, tagClass, extend), names(nameSpec),namesCount(namesCnt) { maxEnumValue = maxEnum; PAssert(val <= maxEnum, PInvalidParameter); value = val; } PObject::Comparison PASN_Enumeration::Compare(const PObject & obj) const { PAssert(PIsDescendant(&obj, PASN_Enumeration), PInvalidCast); const PASN_Enumeration & other = (const PASN_Enumeration &)obj; if (value < other.value) return LessThan; if (value > other.value) return GreaterThan; return EqualTo; } PObject * PASN_Enumeration::Clone() const { PAssert(IsClass(PASN_Enumeration::Class()), PInvalidCast); return new PASN_Enumeration(*this); } void PASN_Enumeration::PrintOn(ostream & strm) const { PINDEX idx = FindNameByValue(names, namesCount, value); if (idx != P_MAX_INDEX) strm << names[idx].name; else strm << '<' << value << '>'; } PString PASN_Enumeration::GetTypeAsString() const { return "Enumeration"; } PINDEX PASN_Enumeration::GetDataLength() const { return GetIntegerDataLength(value); } BOOL PASN_Enumeration::Decode(PASN_Stream & strm) { return strm.EnumerationDecode(*this); } void PASN_Enumeration::Encode(PASN_Stream & strm) const { strm.EnumerationEncode(*this); } PINDEX PASN_Enumeration::GetValueByName(PString name) const { for(unsigned uiIndex = 0; uiIndex < namesCount; uiIndex++){ if(strcmp(names[uiIndex].name, name) == 0){ return (maxEnumValue - namesCount + uiIndex + 1); } } return UINT_MAX; } /////////////////////////////////////////////////////////////////////// PASN_Real::PASN_Real(double val) : PASN_Object(UniversalReal, UniversalTagClass) { value = val; } PASN_Real::PASN_Real(unsigned tag, TagClass tagClass, double val) : PASN_Object(tag, tagClass) { value = val; } PObject::Comparison PASN_Real::Compare(const PObject & obj) const { PAssert(PIsDescendant(&obj, PASN_Real), PInvalidCast); const PASN_Real & other = (const PASN_Real &)obj; if (value < other.value) return LessThan; if (value > other.value) return GreaterThan; return EqualTo; } PObject * PASN_Real::Clone() const { PAssert(IsClass(PASN_Real::Class()), PInvalidCast); return new PASN_Real(*this); } void PASN_Real::PrintOn(ostream & strm) const { strm << value; } PString PASN_Real::GetTypeAsString() const { return "Real"; } PINDEX PASN_Real::GetDataLength() const { PAssertAlways(PUnimplementedFunction); return 0; } BOOL PASN_Real::Decode(PASN_Stream & strm) { return strm.RealDecode(*this); } void PASN_Real::Encode(PASN_Stream & strm) const { strm.RealEncode(*this); } /////////////////////////////////////////////////////////////////////// PASN_ObjectId::PASN_ObjectId(const char * dotstr) : PASN_Object(UniversalObjectId, UniversalTagClass) { if (dotstr != NULL) SetValue(dotstr); } PASN_ObjectId::PASN_ObjectId(unsigned tag, TagClass tagClass) : PASN_Object(tag, tagClass) { } PASN_ObjectId::PASN_ObjectId(const PASN_ObjectId & other) : PASN_Object(other), value(other.value, other.GetSize()) { } PASN_ObjectId & PASN_ObjectId::operator=(const PASN_ObjectId & other) { PASN_Object::operator=(other); value = PUnsignedArray(other.value, other.GetSize()); return *this; } PASN_ObjectId & PASN_ObjectId::operator=(const char * dotstr) { if (dotstr != NULL) SetValue(dotstr); else value.SetSize(0); return *this; } PASN_ObjectId & PASN_ObjectId::operator=(const PString & dotstr) { SetValue(dotstr); return *this; } PASN_ObjectId & PASN_ObjectId::operator=(const PUnsignedArray & numbers) { SetValue(numbers); return *this; } void PASN_ObjectId::SetValue(const PString & dotstr) { PStringArray parts = dotstr.Tokenise('.'); value.SetSize(parts.GetSize()); for (PINDEX i = 0; i < parts.GetSize(); i++) value[i] = parts[i].AsUnsigned(); } void PASN_ObjectId::SetValue(const unsigned * numbers, PINDEX size) { value = PUnsignedArray(numbers, size); } bool PASN_ObjectId::operator==(const char * dotstr) const { PASN_ObjectId id; id.SetValue(dotstr); return *this == id; } PObject::Comparison PASN_ObjectId::Compare(const PObject & obj) const { PAssert(PIsDescendant(&obj, PASN_ObjectId), PInvalidCast); const PASN_ObjectId & other = (const PASN_ObjectId &)obj; return value.Compare(other.value); } PObject * PASN_ObjectId::Clone() const { PAssert(IsClass(PASN_ObjectId::Class()), PInvalidCast); return new PASN_ObjectId(*this); } void PASN_ObjectId::PrintOn(ostream & strm) const { for (PINDEX i = 0; i < value.GetSize(); i++) { strm << (unsigned)value[i]; if (i < value.GetSize()-1) strm << '.'; } } PString PASN_ObjectId::AsString() const { PStringStream s; PrintOn(s); return s; } PString PASN_ObjectId::GetTypeAsString() const { return "Object ID"; } BOOL PASN_ObjectId::CommonDecode(PASN_Stream & strm, unsigned dataLen) { value.SetSize(0); // handle zero length strings correctly if (dataLen == 0) return TRUE; unsigned subId; // start at the second identifier in the buffer, because we will later // expand the first number into the first two IDs PINDEX i = 1; while (dataLen > 0) { unsigned byte; subId = 0; do { /* shift and add in low order 7 bits */ if (strm.IsAtEnd()) return FALSE; byte = strm.ByteDecode(); subId = (subId << 7) + (byte & 0x7f); dataLen--; } while ((byte & 0x80) != 0); value.SetAt(i++, subId); } /* * The first two subidentifiers are encoded into the first component * with the value (X * 40) + Y, where: * X is the value of the first subidentifier. * Y is the value of the second subidentifier. */ subId = value[1]; if (subId < 40) { value[0] = 0; value[1] = subId; } else if (subId < 80) { value[0] = 1; value[1] = subId-40; } else { value[0] = 2; value[1] = subId-80; } return TRUE; } void PASN_ObjectId::CommonEncode(PBYTEArray & encodecObjectId) const { PINDEX length = value.GetSize(); const unsigned * objId = value; if (length < 2) { // Thise case is really illegal, but we have to do SOMETHING encodecObjectId.SetSize(0); return; } unsigned subId = (objId[0] * 40) + objId[1]; objId += 2; PINDEX outputPosition = 0; while (--length > 0) { if (subId < 128) encodecObjectId[outputPosition++] = (BYTE)subId; else { unsigned mask = 0x7F; /* handle subid == 0 case */ int bits = 0; /* testmask *MUST* !!!! be of an unsigned type */ unsigned testmask = 0x7F; int testbits = 0; while (testmask != 0) { if (subId & testmask) { /* if any bits set */ mask = testmask; bits = testbits; } testmask <<= 7; testbits += 7; } /* mask can't be zero here */ while (mask != 0x7F) { /* fix a mask that got truncated above */ if (mask == 0x1E00000) mask = 0xFE00000; encodecObjectId[outputPosition++] = (BYTE)(((subId & mask) >> bits) | 0x80); mask >>= 7; bits -= 7; } encodecObjectId[outputPosition++] = (BYTE)(subId & mask); } if (length > 1) subId = *objId++; } } PINDEX PASN_ObjectId::GetDataLength() const { PBYTEArray dummy; CommonEncode(dummy); return dummy.GetSize(); } BOOL PASN_ObjectId::Decode(PASN_Stream & strm) { return strm.ObjectIdDecode(*this); } void PASN_ObjectId::Encode(PASN_Stream & strm) const { strm.ObjectIdEncode(*this); } /////////////////////////////////////////////////////////////////////// PASN_BitString::PASN_BitString(unsigned nBits, const BYTE * buf) : PASN_ConstrainedObject(UniversalBitString, UniversalTagClass), totalBits(nBits), bitData((totalBits+7)/8) { if (buf != NULL) memcpy(bitData.GetPointer(), buf, bitData.GetSize()); } PASN_BitString::PASN_BitString(unsigned tag, TagClass tagClass, unsigned nBits) : PASN_ConstrainedObject(tag, tagClass), totalBits(nBits), bitData((totalBits+7)/8) { } PASN_BitString::PASN_BitString(const PASN_BitString & other) : PASN_ConstrainedObject(other), bitData(other.bitData, other.bitData.GetSize()) { totalBits = other.totalBits; } PASN_BitString & PASN_BitString::operator=(const PASN_BitString & other) { PASN_ConstrainedObject::operator=(other); totalBits = other.totalBits; bitData = PBYTEArray(other.bitData, other.bitData.GetSize()); return *this; } void PASN_BitString::SetData(unsigned nBits, const PBYTEArray & bytes) { if ((PINDEX)nBits >= MaximumStringSize) return; bitData = bytes; SetSize(nBits); } void PASN_BitString::SetData(unsigned nBits, const BYTE * buf, PINDEX size) { if ((PINDEX)nBits >= MaximumStringSize) return; if (size == 0) size = (nBits+7)/8; memcpy(bitData.GetPointer(size), buf, size); SetSize(nBits); } BOOL PASN_BitString::SetSize(unsigned nBits) { if (!CheckByteOffset(nBits)) return FALSE; if (constraint == Unconstrained) totalBits = nBits; else if (totalBits < (unsigned)lowerLimit) { if (lowerLimit < 0) return FALSE; totalBits = lowerLimit; } else if ((unsigned)totalBits > upperLimit) { if (upperLimit > (unsigned)MaximumSetSize) return FALSE; totalBits = upperLimit; } else totalBits = nBits; return bitData.SetSize((totalBits+7)/8); } bool PASN_BitString::operator[](PINDEX bit) const { if ((unsigned)bit < totalBits) return (bitData[bit>>3] & (1 << (7 - (bit&7)))) != 0; return FALSE; } void PASN_BitString::Set(unsigned bit) { if (bit < totalBits) bitData[(PINDEX)(bit>>3)] |= 1 << (7 - (bit&7)); } void PASN_BitString::Clear(unsigned bit) { if (bit < totalBits) bitData[(PINDEX)(bit>>3)] &= ~(1 << (7 - (bit&7))); } void PASN_BitString::Invert(unsigned bit) { if (bit < totalBits) bitData[(PINDEX)(bit>>3)] ^= 1 << (7 - (bit&7)); } PObject::Comparison PASN_BitString::Compare(const PObject & obj) const { PAssert(PIsDescendant(&obj, PASN_BitString), PInvalidCast); const PASN_BitString & other = (const PASN_BitString &)obj; if (totalBits < other.totalBits) return LessThan; if (totalBits > other.totalBits) return GreaterThan; return bitData.Compare(other.bitData); } PObject * PASN_BitString::Clone() const { PAssert(IsClass(PASN_BitString::Class()), PInvalidCast); return new PASN_BitString(*this); } void PASN_BitString::PrintOn(ostream & strm) const { int indent = strm.precision() + 2; _Ios_Fmtflags flags = strm.flags(); if (totalBits > 128) strm << "Hex {\n" << hex << setfill('0') << resetiosflags(ios::floatfield) << setiosflags(ios::fixed) << setw(16) << setprecision(indent) << bitData << dec << setfill(' ') << resetiosflags(ios::floatfield) << setw(indent-1) << "}"; else if (totalBits > 32) strm << "Hex:" << hex << setfill('0') << resetiosflags(ios::floatfield) << setiosflags(ios::fixed) << setprecision(2) << setw(16) << bitData << dec << setfill(' ') << resetiosflags(ios::floatfield); else { BYTE mask = 0x80; PINDEX offset = 0; for (unsigned i = 0; i < totalBits; i++) { strm << ((bitData[offset]&mask) != 0 ? '1' : '0'); mask >>= 1; if (mask == 0) { mask = 0x80; offset++; } } } strm.flags(flags); } void PASN_BitString::SetConstraintBounds(ConstraintType type, int lower, unsigned upper) { if (lower < 0) return; PASN_ConstrainedObject::SetConstraintBounds(type, lower, upper); SetSize(GetSize()); } PString PASN_BitString::GetTypeAsString() const { return "Bit String"; } PINDEX PASN_BitString::GetDataLength() const { return (totalBits+7)/8 + 1; } BOOL PASN_BitString::Decode(PASN_Stream & strm) { return strm.BitStringDecode(*this); } void PASN_BitString::Encode(PASN_Stream & strm) const { strm.BitStringEncode(*this); } /////////////////////////////////////////////////////////////////////// PASN_OctetString::PASN_OctetString(const char * str, PINDEX size) : PASN_ConstrainedObject(UniversalOctetString, UniversalTagClass) { if (str != NULL) { if (size == 0) size = ::strlen(str); SetValue((const BYTE *)str, size); } } PASN_OctetString::PASN_OctetString(unsigned tag, TagClass tagClass) : PASN_ConstrainedObject(tag, tagClass) { } PASN_OctetString::PASN_OctetString(const PASN_OctetString & other) : PASN_ConstrainedObject(other), value(other.value, other.GetSize()) { } PASN_OctetString & PASN_OctetString::operator=(const PASN_OctetString & other) { PASN_ConstrainedObject::operator=(other); value = PBYTEArray(other.value, other.GetSize()); return *this; } PASN_OctetString & PASN_OctetString::operator=(const char * str) { if (str == NULL) value.SetSize(lowerLimit); else SetValue((const BYTE *)str, strlen(str)); return *this; } PASN_OctetString & PASN_OctetString::operator=(const PString & str) { SetValue((const BYTE *)(const char *)str, str.GetSize()-1); return *this; } PASN_OctetString & PASN_OctetString::operator=(const PBYTEArray & arr) { PINDEX len = arr.GetSize(); if ((unsigned)len > upperLimit || (int)len < lowerLimit) SetValue(arr, len); else value = arr; return *this; } void PASN_OctetString::SetValue(const BYTE * data, PINDEX len) { if ((unsigned)len > upperLimit) len = upperLimit; if (SetSize((int)len < lowerLimit ? lowerLimit : len)) memcpy(value.GetPointer(), data, len); } PString PASN_OctetString::AsString() const { if (value.IsEmpty()) return PString(); return PString((const char *)(const BYTE *)value, value.GetSize()); } PObject::Comparison PASN_OctetString::Compare(const PObject & obj) const { PAssert(PIsDescendant(&obj, PASN_OctetString), PInvalidCast); const PASN_OctetString & other = (const PASN_OctetString &)obj; return value.Compare(other.value); } PObject * PASN_OctetString::Clone() const { PAssert(IsClass(PASN_OctetString::Class()), PInvalidCast); return new PASN_OctetString(*this); } void PASN_OctetString::PrintOn(ostream & strm) const { int indent = strm.precision() + 2; _Ios_Fmtflags flags = strm.flags(); strm << ' ' << value.GetSize() << " octets {\n" << hex << setfill('0') << resetiosflags(ios::floatfield) << setprecision(indent) << setw(16); if (value.GetSize() <= 32 || (flags&ios::floatfield) != ios::fixed) strm << value << '\n'; else { PBYTEArray truncatedArray(value, 32); strm << truncatedArray << '\n' << setfill(' ') << setw(indent+4) << "...\n"; } strm << dec << setfill(' ') << setw(indent-1) << "}"; strm.flags(flags); } void PASN_OctetString::SetConstraintBounds(ConstraintType type, int lower, unsigned upper) { if (lower < 0) return; PASN_ConstrainedObject::SetConstraintBounds(type, lower, upper); SetSize(GetSize()); } PString PASN_OctetString::GetTypeAsString() const { return "Octet String"; } PINDEX PASN_OctetString::GetDataLength() const { return value.GetSize(); } BOOL PASN_OctetString::SetSize(PINDEX newSize) { if (!CheckByteOffset(newSize, MaximumStringSize)) return FALSE; if (constraint != Unconstrained) { if (newSize < (PINDEX)lowerLimit) { if (lowerLimit < 0) return FALSE; newSize = lowerLimit; } else if ((unsigned)newSize > upperLimit) { if (upperLimit > (unsigned)MaximumStringSize) return FALSE; newSize = upperLimit; } } return value.SetSize(newSize); } BOOL PASN_OctetString::Decode(PASN_Stream & strm) { return strm.OctetStringDecode(*this); } void PASN_OctetString::Encode(PASN_Stream & strm) const { strm.OctetStringEncode(*this); } /////////////////////////////////////////////////////////////////////// PASN_ConstrainedString::PASN_ConstrainedString(const char * canonical, PINDEX size, unsigned tag, TagClass tagClass) : PASN_ConstrainedObject(tag, tagClass) { canonicalSet = canonical; canonicalSetSize = size; canonicalSetBits = CountBits(size); SetCharacterSet(canonicalSet, canonicalSetSize, Unconstrained); } PASN_ConstrainedString & PASN_ConstrainedString::operator=(const char * str) { if (str == NULL) str = ""; PStringStream newValue; PINDEX len = strlen(str); // Can't copy any more characters than the upper constraint if ((unsigned)len > upperLimit) len = upperLimit; // Now copy individual characters, if they are in character set constraint for (PINDEX i = 0; i < len; i++) { PINDEX sz = characterSet.GetSize(); if (sz == 0 || memchr(characterSet, str[i], sz) != NULL) newValue << str[i]; } // Make sure string meets minimum length constraint while ((int)len < lowerLimit) { newValue << characterSet[0]; len++; } value = newValue; value.MakeMinimumSize(); return *this; } void PASN_ConstrainedString::SetCharacterSet(ConstraintType ctype, const char * set) { SetCharacterSet(set, strlen(set), ctype); } void PASN_ConstrainedString::SetCharacterSet(ConstraintType ctype, unsigned firstChar, unsigned lastChar) { char buffer[256]; for (unsigned i = firstChar; i < lastChar; i++) buffer[i] = (char)i; SetCharacterSet(buffer, lastChar - firstChar + 1, ctype); } void PASN_ConstrainedString::SetCharacterSet(const char * set, PINDEX setSize, ConstraintType ctype) { if (ctype == Unconstrained) { characterSet.SetSize(canonicalSetSize); memcpy(characterSet.GetPointer(), canonicalSet, canonicalSetSize); } else if (setSize >= MaximumSetSize || canonicalSetSize >= MaximumSetSize || characterSet.GetSize() >= MaximumSetSize) return; else { characterSet.SetSize(setSize); PINDEX count = 0; for (PINDEX i = 0; i < canonicalSetSize; i++) { if (memchr(set, canonicalSet[i], setSize) != NULL) characterSet[count++] = canonicalSet[i]; } if (count < 0) return; characterSet.SetSize(count); } charSetUnalignedBits = CountBits(characterSet.GetSize()); charSetAlignedBits = 1; while (charSetUnalignedBits > charSetAlignedBits) charSetAlignedBits <<= 1; operator=((const char *)value); } PObject::Comparison PASN_ConstrainedString::Compare(const PObject & obj) const { PAssert(PIsDescendant(&obj, PASN_ConstrainedString), PInvalidCast); const PASN_ConstrainedString & other = (const PASN_ConstrainedString &)obj; return value.Compare(other.value); } void PASN_ConstrainedString::PrintOn(ostream & strm) const { strm << value.ToLiteral(); } void PASN_ConstrainedString::SetConstraintBounds(ConstraintType type, int lower, unsigned upper) { if (lower < 0) return; PASN_ConstrainedObject::SetConstraintBounds(type, lower, upper); if (constraint != Unconstrained) { if (value.GetSize() < (PINDEX)lowerLimit) value.SetSize(lowerLimit); else if ((unsigned)value.GetSize() > upperLimit) value.SetSize(upperLimit); } } PINDEX PASN_ConstrainedString::GetDataLength() const { return value.GetSize()-1; } BOOL PASN_ConstrainedString::Decode(PASN_Stream & strm) { return strm.ConstrainedStringDecode(*this); } void PASN_ConstrainedString::Encode(PASN_Stream & strm) const { strm.ConstrainedStringEncode(*this); } #define DEFINE_STRING_CLASS(name, set) \ static const char name##StringSet[] = set; \ PASN_##name##String::PASN_##name##String(const char * str) \ : PASN_ConstrainedString(name##StringSet, sizeof(name##StringSet)-1, \ Universal##name##String, UniversalTagClass) \ { PASN_ConstrainedString::SetValue(str); } \ PASN_##name##String::PASN_##name##String(unsigned tag, TagClass tagClass) \ : PASN_ConstrainedString(name##StringSet, sizeof(name##StringSet)-1, tag, tagClass) \ { } \ PASN_##name##String & PASN_##name##String::operator=(const char * str) \ { PASN_ConstrainedString::SetValue(str); return *this; } \ PASN_##name##String & PASN_##name##String::operator=(const PString & str) \ { PASN_ConstrainedString::SetValue(str); return *this; } \ PObject * PASN_##name##String::Clone() const \ { PAssert(IsClass(PASN_##name##String::Class()), PInvalidCast); \ return new PASN_##name##String(*this); } \ PString PASN_##name##String::GetTypeAsString() const \ { return #name " String"; } DEFINE_STRING_CLASS(Numeric, " 0123456789") DEFINE_STRING_CLASS(Printable, " '()+,-./0123456789:=?" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz") DEFINE_STRING_CLASS(Visible, " !\"#$%&'()*+,-./0123456789:;<=>?" "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" "`abcdefghijklmnopqrstuvwxyz{|}~") DEFINE_STRING_CLASS(IA5, "\000\001\002\003\004\005\006\007" "\010\011\012\013\014\015\016\017" "\020\021\022\023\024\025\026\027" "\030\031\032\033\034\035\036\037" " !\"#$%&'()*+,-./0123456789:;<=>?" "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" "`abcdefghijklmnopqrstuvwxyz{|}~\177") DEFINE_STRING_CLASS(General, "\000\001\002\003\004\005\006\007" "\010\011\012\013\014\015\016\017" "\020\021\022\023\024\025\026\027" "\030\031\032\033\034\035\036\037" " !\"#$%&'()*+,-./0123456789:;<=>?" "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" "`abcdefghijklmnopqrstuvwxyz{|}~\177" "\200\201\202\203\204\205\206\207" "\210\211\212\213\214\215\216\217" "\220\221\222\223\224\225\226\227" "\230\231\232\233\234\235\236\237" "\240\241\242\243\244\245\246\247" "\250\251\252\253\254\255\256\257" "\260\261\262\263\264\265\266\267" "\270\271\272\273\274\275\276\277" "\300\301\302\303\304\305\306\307" "\310\311\312\313\314\315\316\317" "\320\321\322\323\324\325\326\327" "\330\331\332\333\334\335\336\337" "\340\341\342\343\344\345\346\347" "\350\351\352\353\354\355\356\357" "\360\361\362\363\364\365\366\367" "\370\371\372\373\374\375\376\377") /////////////////////////////////////////////////////////////////////// PASN_BMPString::PASN_BMPString(const char * str) : PASN_ConstrainedObject(UniversalBMPString, UniversalTagClass) { Construct(); if (str != NULL) SetValue(str); } PASN_BMPString::PASN_BMPString(const PWORDArray & wstr) : PASN_ConstrainedObject(UniversalBMPString, UniversalTagClass) { Construct(); SetValue(wstr); } PASN_BMPString::PASN_BMPString(unsigned tag, TagClass tagClass) : PASN_ConstrainedObject(tag, tagClass) { Construct(); } void PASN_BMPString::Construct() { firstChar = 0; lastChar = 0xffff; charSetAlignedBits = 16; charSetUnalignedBits = 16; } PASN_BMPString::PASN_BMPString(const PASN_BMPString & other) : PASN_ConstrainedObject(other), value(other.value, other.value.GetSize()), characterSet(other.characterSet) { firstChar = other.firstChar; lastChar = other.lastChar; charSetAlignedBits = other.charSetAlignedBits; charSetUnalignedBits = other.charSetUnalignedBits; } PASN_BMPString & PASN_BMPString::operator=(const PASN_BMPString & other) { PASN_ConstrainedObject::operator=(other); value = PWORDArray(other.value, other.value.GetSize()); characterSet = other.characterSet; firstChar = other.firstChar; lastChar = other.lastChar; charSetAlignedBits = other.charSetAlignedBits; charSetUnalignedBits = other.charSetUnalignedBits; return *this; } BOOL PASN_BMPString::IsLegalCharacter(WORD ch) { if (ch < firstChar) return FALSE; if (ch > lastChar) return FALSE; if (characterSet.IsEmpty()) return TRUE; const WORD * wptr = characterSet; PINDEX count = characterSet.GetSize(); while (count-- > 0) { if (*wptr == ch) return TRUE; wptr++; } return FALSE; } PASN_BMPString & PASN_BMPString::operator=(const PWORDArray & array) { PINDEX paramSize = array.GetSize(); // Can't copy any more than the upper constraint if ((unsigned)paramSize > upperLimit) paramSize = upperLimit; // Number of bytes must be at least lhe lower constraint PINDEX newSize = (int)paramSize < lowerLimit ? lowerLimit : paramSize; value.SetSize(newSize); PINDEX count = 0; for (PINDEX i = 0; i < paramSize; i++) { WORD c = array[i]; if (IsLegalCharacter(c)) value[count++] = c; } // Pad out with the first character till required size while (count < newSize) value[count++] = firstChar; return *this; } void PASN_BMPString::SetCharacterSet(ConstraintType ctype, const char * charSet) { PWORDArray array(strlen(charSet)); PINDEX count = 0; while (*charSet != '\0') array[count++] = (BYTE)*charSet++; SetCharacterSet(ctype, array); } void PASN_BMPString::SetCharacterSet(ConstraintType ctype, const PWORDArray & charSet) { if (ctype == Unconstrained) { firstChar = 0; lastChar = 0xffff; characterSet.SetSize(0); } else { characterSet = charSet; charSetUnalignedBits = CountBits(lastChar - firstChar + 1); if (!charSet.IsEmpty()) { unsigned count = 0; for (PINDEX i = 0; i < charSet.GetSize(); i++) { if (characterSet[i] >= firstChar && characterSet[i] <= lastChar) count++; } count = CountBits(count); if (charSetUnalignedBits > count) charSetUnalignedBits = count; } charSetAlignedBits = 1; while (charSetUnalignedBits > charSetAlignedBits) charSetAlignedBits <<= 1; SetValue(value); } } void PASN_BMPString::SetCharacterSet(ConstraintType ctype, unsigned first, unsigned last) { if (ctype != Unconstrained) { PAssert(first < 0x10000 && last < 0x10000 && last > first, PInvalidParameter); firstChar = (WORD)first; lastChar = (WORD)last; } SetCharacterSet(ctype, characterSet); } PObject * PASN_BMPString::Clone() const { PAssert(IsClass(PASN_BMPString::Class()), PInvalidCast); return new PASN_BMPString(*this); } PObject::Comparison PASN_BMPString::Compare(const PObject & obj) const { PAssert(PIsDescendant(&obj, PASN_BMPString), PInvalidCast); const PASN_BMPString & other = (const PASN_BMPString &)obj; return value.Compare(other.value); } void PASN_BMPString::PrintOn(ostream & strm) const { int indent = strm.precision() + 2; PINDEX sz = value.GetSize(); strm << ' ' << sz << " characters {\n"; PINDEX i = 0; while (i < sz) { strm << setw(indent) << " " << hex << setfill('0'); PINDEX j; for (j = 0; j < 8; j++) if (i+j < sz) strm << setw(4) << value[i+j] << ' '; else strm << " "; strm << " "; for (j = 0; j < 8; j++) { if (i+j < sz) { WORD c = value[i+j]; if (c < 128 && isprint(c)) strm << (char)c; else strm << ' '; } } strm << dec << setfill(' ') << '\n'; i += 8; } strm << setw(indent-1) << "}"; } PString PASN_BMPString::GetTypeAsString() const { return "BMP String"; } PINDEX PASN_BMPString::GetDataLength() const { return value.GetSize()*2; } BOOL PASN_BMPString::Decode(PASN_Stream & strm) { return strm.BMPStringDecode(*this); } void PASN_BMPString::Encode(PASN_Stream & strm) const { strm.BMPStringEncode(*this); } /////////////////////////////////////////////////////////////////////// PASN_GeneralisedTime & PASN_GeneralisedTime::operator=(const PTime & time) { value = time.AsString("yyyyMMddhhmmss.uz"); value.Replace("GMT", "Z"); return *this; } PTime PASN_GeneralisedTime::GetValue() const { int year = value(0,3).AsInteger(); int month = value(4,5).AsInteger(); int day = value(6,7).AsInteger(); int hour = value(8,9).AsInteger(); int minute = value(10,11).AsInteger(); int seconds = 0; int zonePos = 12; if (isdigit(value[12])) { seconds = value(12,13).AsInteger(); if (value[14] != '.') zonePos = 14; else { zonePos = 15; while (isdigit(value[zonePos])) zonePos++; } } int zone = PTime::Local; switch (value[zonePos]) { case 'Z' : zone = PTime::UTC; break; case '+' : case '-' : zone = value(zonePos+1,zonePos+2).AsInteger()*60 + value(zonePos+3,zonePos+4).AsInteger(); } return PTime(seconds, minute, hour, day, month, year, zone); } /////////////////////////////////////////////////////////////////////// PASN_UniversalTime & PASN_UniversalTime::operator=(const PTime & time) { value = time.AsString("yyMMddhhmmssz"); value.Replace("GMT", "Z"); value.MakeMinimumSize(); return *this; } PTime PASN_UniversalTime::GetValue() const { int year = value(0,1).AsInteger(); if (year < 36) year += 2000; else year += 1900; int month = value(2,3).AsInteger(); int day = value(4,5).AsInteger(); int hour = value(6,7).AsInteger(); int minute = value(8,9).AsInteger(); int seconds = 0; int zonePos = 10; if (isdigit(value[10])) { seconds = value(10,11).AsInteger(); zonePos = 12; } int zone = PTime::UTC; if (value[zonePos] != 'Z') zone = value(zonePos+1,zonePos+2).AsInteger()*60 + value(zonePos+3,zonePos+4).AsInteger(); return PTime(seconds, minute, hour, day, month, year, zone); } /////////////////////////////////////////////////////////////////////// PASN_Choice::PASN_Choice(unsigned nChoices, BOOL extend) : PASN_Object(0, ApplicationTagClass, extend),names(NULL),namesCount(0) { numChoices = nChoices; choice = NULL; } PASN_Choice::PASN_Choice(unsigned tag, TagClass tagClass, unsigned upper, BOOL extend) : PASN_Object(tag, tagClass, extend),names(NULL),namesCount(0) { numChoices = upper; choice = NULL; } PASN_Choice::PASN_Choice(unsigned tag, TagClass tagClass, unsigned upper, BOOL extend, const PASN_Names * nameSpec,unsigned namesCnt) : PASN_Object(tag, tagClass, extend), names(nameSpec),namesCount(namesCnt) { numChoices = upper; choice = NULL; } PASN_Choice::PASN_Choice(const PASN_Choice & other) : PASN_Object(other), names(other.names),namesCount(other.namesCount) { numChoices = other.numChoices; if (other.CheckCreate()) choice = (PASN_Object *)other.choice->Clone(); else choice = NULL; } PASN_Choice & PASN_Choice::operator=(const PASN_Choice & other) { if (&other == this) // Assigning to ourself, just do nothing. return *this; delete choice; PASN_Object::operator=(other); numChoices = other.numChoices; names = other.names; namesCount = other.namesCount; if (other.CheckCreate()) choice = (PASN_Object *)other.choice->Clone(); else choice = NULL; return *this; } PASN_Choice::~PASN_Choice() { delete choice; } void PASN_Choice::SetTag(unsigned newTag, TagClass tagClass) { PASN_Object::SetTag(newTag, tagClass); delete choice; if (CreateObject()) choice->SetTag(newTag, tagClass); } PString PASN_Choice::GetTagName() const { PINDEX idx = FindNameByValue(names, namesCount, tag); if (idx != P_MAX_INDEX) return names[idx].name; if (CheckCreate() && PIsDescendant(choice, PASN_Choice) && choice->GetTag() == tag && choice->GetTagClass() == tagClass) return PString(choice->GetClass()) + "->" + ((PASN_Choice *)choice)->GetTagName(); return psprintf("<%u>", tag); } BOOL PASN_Choice::CheckCreate() const { if (choice != NULL) return TRUE; return ((PASN_Choice *)this)->CreateObject(); } PASN_Object & PASN_Choice::GetObject() const { PAssert(CheckCreate(), "NULL Choice"); return *choice; } #if defined(__GNUC__) && __GNUC__ <= 2 && __GNUC_MINOR__ < 9 #define CHOICE_CAST_OPERATOR(cls) \ PASN_Choice::operator cls &() const \ { \ PAssert(CheckCreate(), "Cast of NULL choice"); \ PAssert(choice->IsDescendant(cls::Class()), PInvalidCast); \ return *(cls *)choice; \ } \ #else #define CHOICE_CAST_OPERATOR(cls) \ PASN_Choice::operator cls &() \ { \ PAssert(CheckCreate(), "Cast of NULL choice"); \ PAssert(PIsDescendant(choice, cls), PInvalidCast); \ return *(cls *)choice; \ } \ PASN_Choice::operator const cls &() const \ { \ PAssert(CheckCreate(), "Cast of NULL choice"); \ PAssert(PIsDescendant(choice, cls), PInvalidCast); \ return *(const cls *)choice; \ } \ #endif CHOICE_CAST_OPERATOR(PASN_Null) CHOICE_CAST_OPERATOR(PASN_Boolean) CHOICE_CAST_OPERATOR(PASN_Integer) CHOICE_CAST_OPERATOR(PASN_Enumeration) CHOICE_CAST_OPERATOR(PASN_Real) CHOICE_CAST_OPERATOR(PASN_ObjectId) CHOICE_CAST_OPERATOR(PASN_BitString) CHOICE_CAST_OPERATOR(PASN_OctetString) CHOICE_CAST_OPERATOR(PASN_NumericString) CHOICE_CAST_OPERATOR(PASN_PrintableString) CHOICE_CAST_OPERATOR(PASN_VisibleString) CHOICE_CAST_OPERATOR(PASN_IA5String) CHOICE_CAST_OPERATOR(PASN_GeneralString) CHOICE_CAST_OPERATOR(PASN_BMPString) CHOICE_CAST_OPERATOR(PASN_Sequence) PObject::Comparison PASN_Choice::Compare(const PObject & obj) const { PAssert(PIsDescendant(&obj, PASN_Choice), PInvalidCast); const PASN_Choice & other = (const PASN_Choice &)obj; CheckCreate(); other.CheckCreate(); if (choice == other.choice) return EqualTo; if (choice == NULL) return LessThan; if (other.choice == NULL) return GreaterThan; if (tag < other.tag) return LessThan; if (tag > other.tag) return GreaterThan; return choice->Compare(*other.choice); } void PASN_Choice::PrintOn(ostream & strm) const { strm << GetTagName(); if (choice != NULL) strm << ' ' << *choice; else strm << " (NULL)"; } PString PASN_Choice::GetTypeAsString() const { return "Choice"; } PINDEX PASN_Choice::GetDataLength() const { if (CheckCreate()) return choice->GetDataLength(); return 0; } BOOL PASN_Choice::IsPrimitive() const { if (CheckCreate()) return choice->IsPrimitive(); return FALSE; } BOOL PASN_Choice::Decode(PASN_Stream & strm) { return strm.ChoiceDecode(*this); } void PASN_Choice::Encode(PASN_Stream & strm) const { strm.ChoiceEncode(*this); } PINDEX PASN_Choice::GetValueByName(PString name) const { for(unsigned uiIndex = 0; uiIndex < numChoices; uiIndex++){ if(strcmp(names[uiIndex].name, name) == 0){ return names[uiIndex].value; } } return UINT_MAX; } /////////////////////////////////////////////////////////////////////// PASN_Sequence::PASN_Sequence(unsigned tag, TagClass tagClass, unsigned nOpts, BOOL extend, unsigned nExtend) : PASN_Object(tag, tagClass, extend) { optionMap.SetConstraints(PASN_ConstrainedObject::FixedConstraint, nOpts); knownExtensions = nExtend; totalExtensions = 0; endBasicEncoding = 0; } PASN_Sequence::PASN_Sequence(const PASN_Sequence & other) : PASN_Object(other), fields(other.fields.GetSize()), optionMap(other.optionMap), extensionMap(other.extensionMap) { for (PINDEX i = 0; i < other.fields.GetSize(); i++) fields.SetAt(i, other.fields[i].Clone()); knownExtensions = other.knownExtensions; totalExtensions = other.totalExtensions; endBasicEncoding = 0; } PASN_Sequence & PASN_Sequence::operator=(const PASN_Sequence & other) { PASN_Object::operator=(other); fields.SetSize(other.fields.GetSize()); for (PINDEX i = 0; i < other.fields.GetSize(); i++) fields.SetAt(i, other.fields[i].Clone()); optionMap = other.optionMap; knownExtensions = other.knownExtensions; totalExtensions = other.totalExtensions; extensionMap = other.extensionMap; return *this; } BOOL PASN_Sequence::HasOptionalField(PINDEX opt) const { if (opt < (PINDEX)optionMap.GetSize()) return optionMap[opt]; else return extensionMap[opt - optionMap.GetSize()]; } void PASN_Sequence::IncludeOptionalField(PINDEX opt) { if (opt < (PINDEX)optionMap.GetSize()) optionMap.Set(opt); else { PAssert(extendable, "Must be extendable type"); opt -= optionMap.GetSize(); if (opt >= (PINDEX)extensionMap.GetSize()) extensionMap.SetSize(opt+1); extensionMap.Set(opt); } } void PASN_Sequence::RemoveOptionalField(PINDEX opt) { if (opt < (PINDEX)optionMap.GetSize()) optionMap.Clear(opt); else { PAssert(extendable, "Must be extendable type"); opt -= optionMap.GetSize(); extensionMap.Clear(opt); } } PObject::Comparison PASN_Sequence::Compare(const PObject & obj) const { PAssert(PIsDescendant(&obj, PASN_Sequence), PInvalidCast); const PASN_Sequence & other = (const PASN_Sequence &)obj; return fields.Compare(other.fields); } PObject * PASN_Sequence::Clone() const { PAssert(IsClass(PASN_Sequence::Class()), PInvalidCast); return new PASN_Sequence(*this); } void PASN_Sequence::PrintOn(ostream & strm) const { int indent = strm.precision() + 2; strm << "{\n"; for (PINDEX i = 0; i < fields.GetSize(); i++) { strm << setw(indent+6) << "field[" << i << "] <"; switch (fields[i].GetTagClass()) { case UniversalTagClass : strm << "Universal"; break; case ApplicationTagClass : strm << "Application"; break; case ContextSpecificTagClass : strm << "ContextSpecific"; break; case PrivateTagClass : strm << "Private"; default : break; } strm << '-' << fields[i].GetTag() << '-' << fields[i].GetTypeAsString() << "> = " << fields[i] << '\n'; } strm << setw(indent-1) << "}"; } PString PASN_Sequence::GetTypeAsString() const { return "Sequence"; } PINDEX PASN_Sequence::GetDataLength() const { PINDEX len = 0; for (PINDEX i = 0; i < fields.GetSize(); i++) len += fields[i].GetObjectLength(); return len; } BOOL PASN_Sequence::IsPrimitive() const { return FALSE; } BOOL PASN_Sequence::Decode(PASN_Stream & strm) { return PreambleDecode(strm) && UnknownExtensionsDecode(strm); } void PASN_Sequence::Encode(PASN_Stream & strm) const { PreambleEncode(strm); UnknownExtensionsEncode(strm); } BOOL PASN_Sequence::PreambleDecode(PASN_Stream & strm) { return strm.SequencePreambleDecode(*this); } void PASN_Sequence::PreambleEncode(PASN_Stream & strm) const { strm.SequencePreambleEncode(*this); } BOOL PASN_Sequence::KnownExtensionDecode(PASN_Stream & strm, PINDEX fld, PASN_Object & field) { return strm.SequenceKnownDecode(*this, fld, field); } void PASN_Sequence::KnownExtensionEncode(PASN_Stream & strm, PINDEX fld, const PASN_Object & field) const { strm.SequenceKnownEncode(*this, fld, field); } BOOL PASN_Sequence::UnknownExtensionsDecode(PASN_Stream & strm) { return strm.SequenceUnknownDecode(*this); } void PASN_Sequence::UnknownExtensionsEncode(PASN_Stream & strm) const { strm.SequenceUnknownEncode(*this); } /////////////////////////////////////////////////////////////////////// PASN_Set::PASN_Set(unsigned tag, TagClass tagClass, unsigned nOpts, BOOL extend, unsigned nExtend) : PASN_Sequence(tag, tagClass, nOpts, extend, nExtend) { } PObject * PASN_Set::Clone() const { PAssert(IsClass(PASN_Set::Class()), PInvalidCast); return new PASN_Set(*this); } PString PASN_Set::GetTypeAsString() const { return "Set"; } /////////////////////////////////////////////////////////////////////// PASN_Array::PASN_Array(unsigned tag, TagClass tagClass) : PASN_ConstrainedObject(tag, tagClass) { } PASN_Array::PASN_Array(const PASN_Array & other) : PASN_ConstrainedObject(other), array(other.array.GetSize()) { for (PINDEX i = 0; i < other.array.GetSize(); i++) array.SetAt(i, other.array[i].Clone()); } PASN_Array & PASN_Array::operator=(const PASN_Array & other) { PASN_ConstrainedObject::operator=(other); array.SetSize(other.array.GetSize()); for (PINDEX i = 0; i < other.array.GetSize(); i++) array.SetAt(i, other.array[i].Clone()); return *this; } BOOL PASN_Array::SetSize(PINDEX newSize) { if (newSize > MaximumArraySize) return FALSE; PINDEX originalSize = array.GetSize(); if (!array.SetSize(newSize)) return FALSE; for (PINDEX i = originalSize; i < newSize; i++) { PASN_Object * obj = CreateObject(); if (obj == NULL) return FALSE; array.SetAt(i, obj); } return TRUE; } PObject::Comparison PASN_Array::Compare(const PObject & obj) const { PAssert(PIsDescendant(&obj, PASN_Array), PInvalidCast); const PASN_Array & other = (const PASN_Array &)obj; return array.Compare(other.array); } void PASN_Array::PrintOn(ostream & strm) const { int indent = strm.precision() + 2; strm << array.GetSize() << " entries {\n"; for (PINDEX i = 0; i < array.GetSize(); i++) strm << setw(indent+1) << "[" << i << "]=" << setprecision(indent) << array[i] << '\n'; strm << setw(indent-1) << "}"; } void PASN_Array::SetConstraintBounds(ConstraintType type, int lower, unsigned upper) { if (lower < 0) return; PASN_ConstrainedObject::SetConstraintBounds(type, lower, upper); if (constraint != Unconstrained) { if (GetSize() < (PINDEX)lowerLimit) SetSize(lowerLimit); else if (GetSize() > (PINDEX)upperLimit) SetSize(upperLimit); } } PString PASN_Array::GetTypeAsString() const { return "Array"; } PINDEX PASN_Array::GetDataLength() const { PINDEX len = 0; for (PINDEX i = 0; i < array.GetSize(); i++) len += array[i].GetObjectLength(); return len; } BOOL PASN_Array::IsPrimitive() const { return FALSE; } BOOL PASN_Array::Decode(PASN_Stream & strm) { return strm.ArrayDecode(*this); } void PASN_Array::Encode(PASN_Stream & strm) const { strm.ArrayEncode(*this); } /////////////////////////////////////////////////////////////////////// PASN_Stream::PASN_Stream() { Construct(); } PASN_Stream::PASN_Stream(const PBYTEArray & bytes) : PBYTEArray(bytes) { Construct(); } PASN_Stream::PASN_Stream(const BYTE * buf, PINDEX size) : PBYTEArray(buf, size) { Construct(); } void PASN_Stream::Construct() { byteOffset = 0; bitOffset = 8; } void PASN_Stream::PrintOn(ostream & strm) const { int indent = strm.precision() + 2; strm << " size=" << GetSize() << " pos=" << byteOffset << '.' << (8-bitOffset) << " {\n"; PINDEX i = 0; while (i < GetSize()) { strm << setw(indent) << " " << hex << setfill('0'); PINDEX j; for (j = 0; j < 16; j++) if (i+j < GetSize()) strm << setw(2) << (unsigned)(BYTE)theArray[i+j] << ' '; else strm << " "; strm << " "; for (j = 0; j < 16; j++) { if (i+j < GetSize()) { BYTE c = theArray[i+j]; if (c < 128 && isprint(c)) strm << c; else strm << ' '; } } strm << dec << setfill(' ') << '\n'; i += 16; } strm << setw(indent-1) << "}"; } void PASN_Stream::SetPosition(PINDEX newPos) { if (!CheckByteOffset(byteOffset)) return; if (newPos > GetSize()) byteOffset = GetSize(); else byteOffset = newPos; bitOffset = 8; } void PASN_Stream::ResetDecoder() { byteOffset = 0; bitOffset = 8; } void PASN_Stream::BeginEncoding() { bitOffset = 8; byteOffset = 0; PBYTEArray::operator=(PBYTEArray(20)); } void PASN_Stream::CompleteEncoding() { if (byteOffset != P_MAX_INDEX) { if (bitOffset != 8) { bitOffset = 8; byteOffset++; } SetSize(byteOffset); byteOffset = P_MAX_INDEX; } } BYTE PASN_Stream::ByteDecode() { if (!CheckByteOffset(byteOffset, GetSize())) return 0; bitOffset = 8; return theArray[byteOffset++]; } void PASN_Stream::ByteEncode(unsigned value) { if (!CheckByteOffset(byteOffset)) return; if (bitOffset != 8) { bitOffset = 8; byteOffset++; } if (byteOffset >= GetSize()) SetSize(byteOffset+10); theArray[byteOffset++] = (BYTE)value; } unsigned PASN_Stream::BlockDecode(BYTE * bufptr, unsigned nBytes) { if (nBytes == 0 || bufptr == NULL || !CheckByteOffset(byteOffset+nBytes)) return 0; ByteAlign(); if (byteOffset+nBytes > (unsigned)GetSize()) { nBytes = GetSize() - byteOffset; if (nBytes <= 0) return 0; } memcpy(bufptr, &theArray[byteOffset], nBytes); byteOffset += nBytes; return nBytes; } void PASN_Stream::BlockEncode(const BYTE * bufptr, PINDEX nBytes) { if (!CheckByteOffset(byteOffset, GetSize())) return; if (nBytes == 0) return; ByteAlign(); if (byteOffset+nBytes >= GetSize()) SetSize(byteOffset+nBytes+10); memcpy(theArray+byteOffset, bufptr, nBytes); byteOffset += nBytes; } void PASN_Stream::ByteAlign() { if (!CheckByteOffset(byteOffset, GetSize())) return; if (bitOffset != 8) { bitOffset = 8; byteOffset++; } } /////////////////////////////////////////////////////////////////////// #ifdef P_INCLUDE_PER #include "asnper.cxx" #endif #ifdef P_INCLUDE_BER #include "asnber.cxx" #endif #ifdef P_INCLUDE_XER #include "asnxer.cxx" #endif // End of file ////////////////////////////////////////////////////////////////