Added IsSupportingRTP function to simplify detecting when STUN supports RTP
[pwlib.git] / src / ptclib / asner.cxx
blobc7a3fd7514137604b1aff0dbc61b6a35099c69b0
1 /*
2 * asner.cxx
4 * Abstract Syntax Notation 1 Encoding Rules
6 * Portable Windows Library
8 * Copyright (c) 1993-2002 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
26 * $Log$
27 * Revision 1.90 2004/07/12 03:42:22 csoutheren
28 * Fixed problem with checking character set constraints too aggressively
30 * Revision 1.89 2004/07/12 01:56:10 csoutheren
31 * Fixed incorrect asn decoding check
33 * Revision 1.88 2004/07/11 14:19:07 csoutheren
34 * More bulletproofing of ASN routines against random data attacks
36 * Revision 1.87 2004/07/11 12:33:47 csoutheren
37 * Added guards against illegal PDU values causing crashes
39 * Revision 1.86 2004/04/22 07:54:01 csoutheren
40 * Fix problem with VS.net asserting on in isprint when chars outside normal range
42 * Revision 1.85 2004/04/18 04:33:37 rjongbloed
43 * Changed all operators that return BOOL to return standard type bool. This is primarily
44 * for improved compatibility with std STL usage removing many warnings.
46 * Revision 1.84 2004/04/03 08:22:20 csoutheren
47 * Remove pseudo-RTTI and replaced with real RTTI
49 * Revision 1.83 2004/01/17 09:21:21 csoutheren
50 * Added protection against NULL ptr to PASN_Stream::BlockDecode
52 * Revision 1.82 2003/08/01 02:11:38 csoutheren
53 * Changed to allow easy isolation of PER, BER and XER encoding/decoding routines
55 * Revision 1.81 2003/04/28 02:50:33 robertj
56 * Fixed problem with spaces in type name, thanks Federico Pinna
58 * Revision 1.80 2003/02/26 04:37:21 robertj
59 * Tidied some comments
61 * Revision 1.79 2003/02/26 01:57:44 robertj
62 * Added XML encoding rules to ASN system, thanks Federico Pinna
64 * Revision 1.78 2003/01/24 23:43:43 robertj
65 * Fixed subtle problems with the use of MAX keyword for unsigned numbers,
66 * should beUINT_MAX not INT_MAX, thanks Stevie Gray for pointing it out.
68 * Revision 1.77 2002/12/17 07:00:15 robertj
69 * Fixed incorrect encoding of arrays greater than 8192 and less than 16384
71 * Revision 1.76 2002/12/13 03:57:17 robertj
72 * Fixed crash if enable extension fields beyond the "known" extensions.
74 * Revision 1.75 2002/12/02 01:03:33 robertj
75 * Fixed bug were if setting the size of a constrained bit string, it
76 * actually sets the size of the underlying byte array correctly.
78 * Revision 1.74 2002/11/26 23:29:32 robertj
79 * Added missing const to DecodeSubType() function.
81 * Revision 1.73 2002/11/22 09:43:32 robertj
82 * Fixed encoding of a ASN NULL sequence extension field, eg fastConnectRefused
84 * Revision 1.72 2002/11/21 03:46:22 robertj
85 * Changed to encode only the minimum number of bits required, this improves
86 * compatibility with some brain dead ASN decoders.
88 * Revision 1.71 2002/11/06 22:47:24 robertj
89 * Fixed header comment (copyright etc)
91 * Revision 1.70 2002/10/31 05:51:10 robertj
92 * Changed to use new UTF-8/UCS-2 conversion functions on PString.
94 * Revision 1.69 2002/10/29 08:12:44 robertj
95 * Fixed MSVC warnings.
97 * Revision 1.68 2002/10/29 07:26:45 robertj
98 * Fixed subtle bug when encoding or decoding Octet String with 1 or 2 bytes
99 * in it, was not byte aligned correctly.
101 * Revision 1.67 2002/09/26 23:53:20 robertj
102 * Fixed incorrect asserts in PASN_Enumerated, thanks Platzer Wolfgang
104 * Revision 1.66 2002/09/13 08:16:15 robertj
105 * Fixed missing line feed when dumping hex octet strings.
107 * Revision 1.65 2002/08/06 02:27:58 robertj
108 * GNU C++ v3 compatibility.
110 * Revision 1.64 2002/07/25 10:52:49 robertj
111 * Changes to allow more granularity in PDU dumps, hex output increasing
112 * with increasing trace level.
114 * Revision 1.63 2002/06/05 12:29:15 craigs
115 * Changes for gcc 3.1
117 * Revision 1.62 2002/05/29 01:22:35 robertj
118 * Added ability to set object id from unsigned integer arrays.
120 * Revision 1.61 2002/05/21 04:23:40 robertj
121 * Fixed problem with ASN encoding/decoding unsconstrained negative numbers,
123 * Revision 1.60 2002/05/14 08:34:29 robertj
124 * Fixed problem encoding unsigned where value==lower bound, thanks Greg Adams.
126 * Revision 1.59 2002/05/14 06:59:50 robertj
127 * Added more bullet proofing so a malformed PDU cannot cause teh decoder
128 * to try and allocate huge arrays and consume all CPU and memory on a
129 * system. A configurable limit of 100 is set for things like SEQUENCE OF.
131 * Revision 1.58 2002/02/08 12:47:19 robertj
132 * Fixed incorrect encoding of integer, did not allow for sign bit, thanks Kevin Tran.
134 * Revision 1.57 2002/02/01 01:17:36 robertj
135 * Fixed bug in encoding empty strings (H.450 issue), thanks Frans Dams, Frank Derks et al.
137 * Revision 1.56 2002/01/30 08:40:55 robertj
138 * Fixed incorrect decode function in BER string decode, thanks ct_dev@sohu.com
140 * Revision 1.55 2001/12/13 09:13:57 robertj
141 * Added function get get oid as a string.
143 * Revision 1.54 2001/11/26 03:07:13 robertj
144 * Fixed decode of extendable constrained integer types.
146 * Revision 1.53 2001/09/14 05:26:11 robertj
147 * Fixed problem with assigning a PASN_Choice to itself, thanks Chih-Wei Huang
149 * Revision 1.52 2001/09/14 01:59:59 robertj
150 * Fixed problem with incorrectly initialised PASN_Choice sub-object.
152 * Revision 1.51 2001/08/08 04:19:28 robertj
153 * Fixed PString<->BMPString conversion so can have embedded nulls.
155 * Revision 1.50 2001/08/07 04:37:03 robertj
156 * Simplified &#num; parsing.
158 * Revision 1.49 2001/08/07 02:49:05 robertj
159 * Fixed incorrect alignment if constrained string upper bound is exactly
160 * 16 bits long. thanks Guntram Diehl & Thomas Arimont.
162 * Revision 1.48 2001/08/06 09:35:25 robertj
163 * Fixed GNU compatibility.
165 * Revision 1.47 2001/08/06 09:31:48 robertj
166 * Added conversion of BMPString to PString without losing special characters.
168 * Revision 1.46 2001/08/06 01:39:02 robertj
169 * Added assignement operator with RHS of PASN_BMPString to classes
170 * descended from PASN_BMPString.
172 * Revision 1.45 2001/06/14 02:14:12 robertj
173 * Added functions to encode and decode another ASN type that is inside
174 * an octet string, useful for ANY or EXTERNAL types etc.
176 * Revision 1.44 2001/05/29 00:59:16 robertj
177 * Fixed excessive padding on constrained strings.
179 * Revision 1.43 2001/05/22 23:37:42 robertj
180 * Fixed problem with assigning a constrained string value to itself, which
181 * can occur when changing constraints.
183 * Revision 1.42 2001/04/30 10:47:33 robertj
184 * Fixed stupid error in last patch.
186 * Revision 1.41 2001/04/30 06:47:04 robertj
187 * Fixed problem with en/decoding more than 16 extension fields in a sequence.
189 * Revision 1.40 2001/04/26 08:15:58 robertj
190 * Fixed problem with ASN compile of single constraints on enumerations.
192 * Revision 1.39 2001/04/23 05:46:06 robertj
193 * Fixed problem with unconstrained PASN_NumericString coding in 8 bits
194 * instead of 4, thanks Chew Kuan.
196 * Revision 1.38 2001/04/23 04:40:14 robertj
197 * Added ASN standard types GeneralizedTime and UTCTime
199 * Revision 1.37 2001/04/12 03:26:59 robertj
200 * Fixed PASN_Boolean cosntructor to be compatible with usage in ASN parser.
201 * Changed all PASN_xxx types so constructor can take real type as only
202 * parameter. eg PASN_OctetString s = "fred";
203 * Changed block encode/decode so does not do a ByteAlign() if zero
204 * length, required for interoperability even though spec implies otherwise..
206 * Revision 1.36 2001/01/24 04:37:07 robertj
207 * Added more bulletproofing to ASN structures to obey constraints.
209 * Revision 1.35 2001/01/03 01:20:13 robertj
210 * Fixed error in BlockEncode, should ByteAlign() even on zero length strings.
212 * Revision 1.34 2000/10/26 11:09:16 robertj
213 * More bullet proofing of PER decoder, changed bit type to be unsigned.
215 * Revision 1.33 2000/10/26 01:29:32 robertj
216 * Fixed MSVC warning.
218 * Revision 1.32 2000/10/25 04:05:38 robertj
219 * More bullet proofing of PER decoder.
221 * Revision 1.31 2000/09/29 04:11:51 robertj
222 * Fixed possible out of range memory access, thanks Petr Parýzek <paryzek@wo.cz>
224 * Revision 1.30 2000/02/29 06:32:12 robertj
225 * Added ability to remove optional field in sequence, thanks Dave Harvey.
227 * Revision 1.29 2000/01/20 06:22:22 robertj
228 * Fixed boundary condition error for constrained integer encoding (values 1, 256 etc)
230 * Revision 1.28 1999/11/22 23:15:43 robertj
231 * Fixed bug in PASN_Choice::Compare(), should make sure choices are the same before comparing.
233 * Revision 1.27 1999/08/19 15:43:07 robertj
234 * Fixed incorrect size of OID if zero length encoded.
236 * Revision 1.26 1999/08/09 13:02:45 robertj
237 * dded ASN compiler #defines for backward support of pre GCC 2.9 compilers.
238 * Added ASN compiler #defines to reduce its memory footprint.
240 * Revision 1.25 1999/08/08 15:45:59 robertj
241 * Fixed incorrect encoding of unknown extensions.
243 * Revision 1.24 1999/08/05 00:44:28 robertj
244 * Fixed PER encoding problems for large integer values.
246 * Revision 1.23 1999/07/22 06:48:54 robertj
247 * Added comparison operation to base ASN classes and compiled ASN code.
248 * Added support for ANY type in ASN parser.
250 * Revision 1.22 1999/07/08 08:39:12 robertj
251 * Fixed bug when assigning negative number ot cosntrained PASN_Integer
253 * Revision 1.21 1999/06/30 08:58:12 robertj
254 * Fixed bug in encoding/decoding OID greater than 2.39
256 * Revision 1.20 1999/06/17 13:27:09 robertj
257 * Fixed bug causing crashes on pass through of unknown extensions.
259 * Revision 1.19 1999/06/07 00:31:25 robertj
260 * Fixed signed/unsigned problem with number of unknown extensions check.
262 * Revision 1.18 1999/04/26 05:58:48 craigs
263 * Fixed problems with encoding of extensions
265 * Revision 1.17 1999/03/09 08:12:38 robertj
266 * Fixed problem with closing a steam encoding twice.
268 * Revision 1.16 1999/01/16 01:28:25 robertj
269 * Fixed problems with reading stream multiple times.
271 * Revision 1.15 1998/11/30 04:50:44 robertj
272 * New directory structure
274 * Revision 1.14 1998/10/22 04:33:11 robertj
275 * Fixed bug in constrained strings and PER, incorrect order of character set.
277 * Revision 1.13 1998/09/23 06:21:49 robertj
278 * Added open source copyright license.
280 * Revision 1.12 1998/05/26 05:29:23 robertj
281 * Workaroung for g++ iostream bug.
283 * Revision 1.11 1998/05/21 04:58:54 robertj
284 * GCC comptaibility.
286 * Revision 1.10 1998/05/21 04:26:54 robertj
287 * Fixed numerous PER problems.
289 * Revision 1.9 1998/05/11 06:01:55 robertj
290 * Why did this compile under MSC?
292 * Revision 1.8 1998/05/07 05:19:29 robertj
293 * Fixed problems with using copy constructor/assignment oeprator on PASN_Objects.
295 * Revision 1.7 1998/03/05 12:49:50 robertj
296 * MemCheck fixes.
298 * Revision 1.6 1998/02/03 06:28:27 robertj
299 * Fixed length calculation of integers in BER.
300 * Added new function to read a block with minimum number of bytes.
302 * Revision 1.5 1998/01/26 01:51:20 robertj
303 * Removed uninitialised variable warnings.
305 * Revision 1.4 1997/12/18 05:07:56 robertj
306 * Fixed bug in choice name display.
307 * Added function to get choice discriminator name.
308 * Fixed bug in encoding extensions.
310 * Revision 1.3 1997/12/11 10:36:22 robertj
311 * Support for new ASN parser.
315 #include <ptlib.h>
317 #ifdef __GNUC__
318 #pragma implementation "asner.h"
319 #endif
321 #include <ptclib/asner.h>
323 #if P_EXPAT
324 #include <ptclib/pxml.h>
325 #endif
327 #define new PNEW
330 static PINDEX MaximumArraySize = 128;
331 static PINDEX MaximumStringSize = 16*1024;
332 static PINDEX MaximumSetSize = 512;
335 static PINDEX CountBits(unsigned range)
337 switch (range) {
338 case 0 :
339 return sizeof(unsigned)*8;
340 case 1:
341 return 1;
344 size_t nBits = 0;
345 while (nBits < (sizeof(unsigned)*8) && range > (unsigned)(1 << nBits))
346 nBits++;
347 return nBits;
350 inline BOOL CheckByteOffset(PINDEX offset, PINDEX upper = MaximumStringSize)
352 // a 1mbit PDU has got to be an error
353 return (0 <= offset && offset <= upper);
357 ///////////////////////////////////////////////////////////////////////
359 PASN_Object::PASN_Object(unsigned theTag, TagClass theTagClass, BOOL extend)
361 extendable = extend;
363 tag = theTag;
365 if (theTagClass != DefaultTagClass)
366 tagClass = theTagClass;
367 else
368 tagClass = ContextSpecificTagClass;
372 void PASN_Object::SetTag(unsigned newTag, TagClass tagClass_)
374 tag = newTag;
375 if (tagClass_ != DefaultTagClass)
376 tagClass = tagClass_;
380 PINDEX PASN_Object::GetObjectLength() const
382 PINDEX len = 1;
384 if (tag >= 31)
385 len += (CountBits(tag)+6)/7;
387 PINDEX dataLen = GetDataLength();
388 if (dataLen < 128)
389 len++;
390 else
391 len += (CountBits(dataLen)+7)/8 + 1;
393 return len + dataLen;
397 void PASN_Object::SetConstraintBounds(ConstraintType, int, unsigned)
402 void PASN_Object::SetCharacterSet(ConstraintType, const char *)
407 void PASN_Object::SetCharacterSet(ConstraintType, unsigned, unsigned)
412 PINDEX PASN_Object::GetMaximumArraySize()
414 return MaximumArraySize;
418 void PASN_Object::SetMaximumArraySize(PINDEX sz)
420 MaximumArraySize = sz;
424 PINDEX PASN_Object::GetMaximumStringSize()
426 return MaximumStringSize;
430 void PASN_Object::SetMaximumStringSize(PINDEX sz)
432 MaximumStringSize = sz;
436 ///////////////////////////////////////////////////////////////////////
438 PASN_ConstrainedObject::PASN_ConstrainedObject(unsigned tag, TagClass tagClass)
439 : PASN_Object(tag, tagClass)
441 constraint = Unconstrained;
442 lowerLimit = 0;
443 upperLimit = UINT_MAX;
447 void PASN_ConstrainedObject::SetConstraintBounds(ConstraintType ctype,
448 int lower, unsigned upper)
450 constraint = ctype;
451 if (constraint == Unconstrained) {
452 lower = 0;
453 upper = UINT_MAX;
456 extendable = ctype == ExtendableConstraint;
457 // if ((lower >= 0 && upper < 0x7fffffff) ||
458 // (lower < 0 && (unsigned)lower <= upper)) {
459 lowerLimit = lower;
460 upperLimit = upper;
461 // }
465 ///////////////////////////////////////////////////////////////////////
467 PASN_Null::PASN_Null(unsigned tag, TagClass tagClass)
468 : PASN_Object(tag, tagClass)
473 PObject::Comparison PASN_Null::Compare(const PObject & obj) const
475 PAssert(PIsDescendant(&obj, PASN_Null), PInvalidCast);
476 return EqualTo;
480 PObject * PASN_Null::Clone() const
482 PAssert(IsClass(PASN_Null::Class()), PInvalidCast);
483 return new PASN_Null(*this);
487 void PASN_Null::PrintOn(ostream & strm) const
489 strm << "<<null>>";
493 PString PASN_Null::GetTypeAsString() const
495 return "Null";
499 PINDEX PASN_Null::GetDataLength() const
501 return 0;
505 BOOL PASN_Null::Decode(PASN_Stream & strm)
507 return strm.NullDecode(*this);
511 void PASN_Null::Encode(PASN_Stream & strm) const
513 strm.NullEncode(*this);
517 ///////////////////////////////////////////////////////////////////////
519 PASN_Boolean::PASN_Boolean(BOOL val)
520 : PASN_Object(UniversalBoolean, UniversalTagClass)
522 value = val;
526 PASN_Boolean::PASN_Boolean(unsigned tag, TagClass tagClass, BOOL val)
527 : PASN_Object(tag, tagClass)
529 value = val;
533 PObject::Comparison PASN_Boolean::Compare(const PObject & obj) const
535 PAssert(PIsDescendant(&obj, PASN_Boolean), PInvalidCast);
536 return value == ((const PASN_Boolean &)obj).value ? EqualTo : GreaterThan;
540 PObject * PASN_Boolean::Clone() const
542 PAssert(IsClass(PASN_Boolean::Class()), PInvalidCast);
543 return new PASN_Boolean(*this);
547 void PASN_Boolean::PrintOn(ostream & strm) const
549 if (value)
550 strm << "TRUE";
551 else
552 strm << "FALSE";
556 PString PASN_Boolean::GetTypeAsString() const
558 return "Boolean";
562 PINDEX PASN_Boolean::GetDataLength() const
564 return 1;
568 BOOL PASN_Boolean::Decode(PASN_Stream & strm)
570 return strm.BooleanDecode(*this);
574 void PASN_Boolean::Encode(PASN_Stream & strm) const
576 strm.BooleanEncode(*this);
580 ///////////////////////////////////////////////////////////////////////
582 PASN_Integer::PASN_Integer(unsigned val)
583 : PASN_ConstrainedObject(UniversalInteger, UniversalTagClass)
585 value = val;
589 PASN_Integer::PASN_Integer(unsigned tag, TagClass tagClass, unsigned val)
590 : PASN_ConstrainedObject(tag, tagClass)
592 value = val;
596 BOOL PASN_Integer::IsUnsigned() const
598 return constraint != Unconstrained && lowerLimit >= 0;
602 PASN_Integer & PASN_Integer::operator=(unsigned val)
604 if (constraint == Unconstrained)
605 value = val;
606 else if (lowerLimit >= 0) { // Is unsigned integer
607 if (val < (unsigned)lowerLimit)
608 value = lowerLimit;
609 else if (val > upperLimit)
610 value = upperLimit;
611 else
612 value = val;
614 else {
615 int ival = (int)val;
616 if (ival < lowerLimit)
617 value = lowerLimit;
618 else if (upperLimit < INT_MAX && ival > (int)upperLimit)
619 value = upperLimit;
620 else
621 value = val;
624 return *this;
628 PObject::Comparison PASN_Integer::Compare(const PObject & obj) const
630 PAssert(PIsDescendant(&obj, PASN_Integer), PInvalidCast);
631 const PASN_Integer & other = (const PASN_Integer &)obj;
633 if (IsUnsigned()) {
634 if (value < other.value)
635 return LessThan;
636 if (value > other.value)
637 return GreaterThan;
639 else {
640 if ((int)value < (int)other.value)
641 return LessThan;
642 if ((int)value > (int)other.value)
643 return GreaterThan;
645 return EqualTo;
649 PObject * PASN_Integer::Clone() const
651 PAssert(IsClass(PASN_Integer::Class()), PInvalidCast);
652 return new PASN_Integer(*this);
656 void PASN_Integer::PrintOn(ostream & strm) const
658 if (constraint == Unconstrained || lowerLimit < 0)
659 strm << (int)value;
660 else
661 strm << value;
665 void PASN_Integer::SetConstraintBounds(ConstraintType type, int lower, unsigned upper)
667 PASN_ConstrainedObject::SetConstraintBounds(type, lower, upper);
668 operator=(value);
672 PString PASN_Integer::GetTypeAsString() const
674 return "Integer";
678 static PINDEX GetIntegerDataLength(int value)
680 // create a mask which is the top nine bits of a DWORD, or 0xFF800000
681 // on a big endian machine
682 int shift = (sizeof(value)-1)*8-1;
684 // remove all sequences of nine 0's or 1's at the start of the value
685 while (shift > 0 && ((value >> shift)&0x1ff) == (value < 0 ? 0x1ff : 0))
686 shift -= 8;
688 return (shift+9)/8;
692 PINDEX PASN_Integer::GetDataLength() const
694 return GetIntegerDataLength(value);
698 BOOL PASN_Integer::Decode(PASN_Stream & strm)
700 return strm.IntegerDecode(*this);
704 void PASN_Integer::Encode(PASN_Stream & strm) const
706 strm.IntegerEncode(*this);
710 ///////////////////////////////////////////////////////////////////////
712 PASN_Enumeration::PASN_Enumeration(unsigned val)
713 : PASN_Object(UniversalEnumeration, UniversalTagClass, FALSE)
715 value = val;
716 maxEnumValue = P_MAX_INDEX;
720 PASN_Enumeration::PASN_Enumeration(unsigned tag, TagClass tagClass,
721 unsigned maxEnum, BOOL extend,
722 unsigned val)
723 : PASN_Object(tag, tagClass, extend)
725 value = val;
726 maxEnumValue = maxEnum;
730 static POrdinalToString BuildNamesDict(const PString & nameSpec)
732 POrdinalToString names;
734 PStringArray nameList = nameSpec.Tokenise(' ', FALSE);
736 int num = 0;
737 for (PINDEX i = 0; i < nameList.GetSize(); i++) {
738 const PString & thisName = nameList[i];
739 if (!thisName) {
740 PINDEX equalPos = thisName.Find('=');
741 if (equalPos != P_MAX_INDEX)
742 num = (int)thisName.Mid(equalPos+1).AsInteger();
743 names.SetAt(POrdinalKey(num), thisName.Left(equalPos));
744 num++;
748 return names;
752 PASN_Enumeration::PASN_Enumeration(unsigned tag, TagClass tagClass,
753 unsigned maxEnum, BOOL extend,
754 const PString & nameSpec,
755 unsigned val)
756 : PASN_Object(tag, tagClass, extend),
757 names(BuildNamesDict(nameSpec))
759 maxEnumValue = maxEnum;
761 PAssert(val <= maxEnum, PInvalidParameter);
762 value = val;
766 PObject::Comparison PASN_Enumeration::Compare(const PObject & obj) const
768 PAssert(PIsDescendant(&obj, PASN_Enumeration), PInvalidCast);
769 const PASN_Enumeration & other = (const PASN_Enumeration &)obj;
771 if (value < other.value)
772 return LessThan;
774 if (value > other.value)
775 return GreaterThan;
777 return EqualTo;
781 PObject * PASN_Enumeration::Clone() const
783 PAssert(IsClass(PASN_Enumeration::Class()), PInvalidCast);
784 return new PASN_Enumeration(*this);
788 void PASN_Enumeration::PrintOn(ostream & strm) const
790 if (names.Contains(value))
791 strm << names[value];
792 else
793 strm << '<' << value << '>';
797 PString PASN_Enumeration::GetTypeAsString() const
799 return "Enumeration";
803 PINDEX PASN_Enumeration::GetDataLength() const
805 return GetIntegerDataLength(value);
809 BOOL PASN_Enumeration::Decode(PASN_Stream & strm)
811 return strm.EnumerationDecode(*this);
815 void PASN_Enumeration::Encode(PASN_Stream & strm) const
817 strm.EnumerationEncode(*this);
821 ///////////////////////////////////////////////////////////////////////
823 PASN_Real::PASN_Real(double val)
824 : PASN_Object(UniversalReal, UniversalTagClass)
826 value = val;
830 PASN_Real::PASN_Real(unsigned tag, TagClass tagClass, double val)
831 : PASN_Object(tag, tagClass)
833 value = val;
837 PObject::Comparison PASN_Real::Compare(const PObject & obj) const
839 PAssert(PIsDescendant(&obj, PASN_Real), PInvalidCast);
840 const PASN_Real & other = (const PASN_Real &)obj;
842 if (value < other.value)
843 return LessThan;
845 if (value > other.value)
846 return GreaterThan;
848 return EqualTo;
852 PObject * PASN_Real::Clone() const
854 PAssert(IsClass(PASN_Real::Class()), PInvalidCast);
855 return new PASN_Real(*this);
859 void PASN_Real::PrintOn(ostream & strm) const
861 strm << value;
865 PString PASN_Real::GetTypeAsString() const
867 return "Real";
871 PINDEX PASN_Real::GetDataLength() const
873 PAssertAlways(PUnimplementedFunction);
874 return 0;
878 BOOL PASN_Real::Decode(PASN_Stream & strm)
880 return strm.RealDecode(*this);
884 void PASN_Real::Encode(PASN_Stream & strm) const
886 strm.RealEncode(*this);
890 ///////////////////////////////////////////////////////////////////////
892 PASN_ObjectId::PASN_ObjectId(const char * dotstr)
893 : PASN_Object(UniversalObjectId, UniversalTagClass)
895 if (dotstr != NULL)
896 SetValue(dotstr);
900 PASN_ObjectId::PASN_ObjectId(unsigned tag, TagClass tagClass)
901 : PASN_Object(tag, tagClass)
906 PASN_ObjectId::PASN_ObjectId(const PASN_ObjectId & other)
907 : PASN_Object(other),
908 value(other.value, other.GetSize())
913 PASN_ObjectId & PASN_ObjectId::operator=(const PASN_ObjectId & other)
915 PASN_Object::operator=(other);
916 value = PUnsignedArray(other.value, other.GetSize());
917 return *this;
921 PASN_ObjectId & PASN_ObjectId::operator=(const char * dotstr)
923 if (dotstr != NULL)
924 SetValue(dotstr);
925 else
926 value.SetSize(0);
927 return *this;
931 PASN_ObjectId & PASN_ObjectId::operator=(const PString & dotstr)
933 SetValue(dotstr);
934 return *this;
938 PASN_ObjectId & PASN_ObjectId::operator=(const PUnsignedArray & numbers)
940 SetValue(numbers);
941 return *this;
945 void PASN_ObjectId::SetValue(const PString & dotstr)
947 PStringArray parts = dotstr.Tokenise('.');
948 value.SetSize(parts.GetSize());
949 for (PINDEX i = 0; i < parts.GetSize(); i++)
950 value[i] = parts[i].AsUnsigned();
954 void PASN_ObjectId::SetValue(const unsigned * numbers, PINDEX size)
956 value = PUnsignedArray(numbers, size);
960 bool PASN_ObjectId::operator==(const char * dotstr) const
962 PASN_ObjectId id;
963 id.SetValue(dotstr);
964 return *this == id;
968 PObject::Comparison PASN_ObjectId::Compare(const PObject & obj) const
970 PAssert(PIsDescendant(&obj, PASN_ObjectId), PInvalidCast);
971 const PASN_ObjectId & other = (const PASN_ObjectId &)obj;
972 return value.Compare(other.value);
976 PObject * PASN_ObjectId::Clone() const
978 PAssert(IsClass(PASN_ObjectId::Class()), PInvalidCast);
979 return new PASN_ObjectId(*this);
983 void PASN_ObjectId::PrintOn(ostream & strm) const
985 for (PINDEX i = 0; i < value.GetSize(); i++) {
986 strm << (unsigned)value[i];
987 if (i < value.GetSize()-1)
988 strm << '.';
993 PString PASN_ObjectId::AsString() const
995 PStringStream s;
996 PrintOn(s);
997 return s;
1001 PString PASN_ObjectId::GetTypeAsString() const
1003 return "Object ID";
1007 BOOL PASN_ObjectId::CommonDecode(PASN_Stream & strm, unsigned dataLen)
1009 value.SetSize(0);
1011 // handle zero length strings correctly
1012 if (dataLen == 0)
1013 return TRUE;
1015 unsigned subId;
1017 // start at the second identifier in the buffer, because we will later
1018 // expand the first number into the first two IDs
1019 PINDEX i = 1;
1020 while (dataLen > 0) {
1021 unsigned byte;
1022 subId = 0;
1023 do { /* shift and add in low order 7 bits */
1024 if (strm.IsAtEnd())
1025 return FALSE;
1026 byte = strm.ByteDecode();
1027 subId = (subId << 7) + (byte & 0x7f);
1028 dataLen--;
1029 } while ((byte & 0x80) != 0);
1030 value.SetAt(i++, subId);
1034 * The first two subidentifiers are encoded into the first component
1035 * with the value (X * 40) + Y, where:
1036 * X is the value of the first subidentifier.
1037 * Y is the value of the second subidentifier.
1039 subId = value[1];
1040 if (subId < 40) {
1041 value[0] = 0;
1042 value[1] = subId;
1044 else if (subId < 80) {
1045 value[0] = 1;
1046 value[1] = subId-40;
1048 else {
1049 value[0] = 2;
1050 value[1] = subId-80;
1053 return TRUE;
1057 void PASN_ObjectId::CommonEncode(PBYTEArray & encodecObjectId) const
1059 PINDEX length = value.GetSize();
1060 const unsigned * objId = value;
1062 if (length < 2) {
1063 // Thise case is really illegal, but we have to do SOMETHING
1064 encodecObjectId.SetSize(0);
1065 return;
1068 unsigned subId = (objId[0] * 40) + objId[1];
1069 objId += 2;
1071 PINDEX outputPosition = 0;
1073 while (--length > 0) {
1074 if (subId < 128)
1075 encodecObjectId[outputPosition++] = (BYTE)subId;
1076 else {
1077 unsigned mask = 0x7F; /* handle subid == 0 case */
1078 int bits = 0;
1080 /* testmask *MUST* !!!! be of an unsigned type */
1081 unsigned testmask = 0x7F;
1082 int testbits = 0;
1083 while (testmask != 0) {
1084 if (subId & testmask) { /* if any bits set */
1085 mask = testmask;
1086 bits = testbits;
1088 testmask <<= 7;
1089 testbits += 7;
1092 /* mask can't be zero here */
1093 while (mask != 0x7F) {
1094 /* fix a mask that got truncated above */
1095 if (mask == 0x1E00000)
1096 mask = 0xFE00000;
1098 encodecObjectId[outputPosition++] = (BYTE)(((subId & mask) >> bits) | 0x80);
1100 mask >>= 7;
1101 bits -= 7;
1104 encodecObjectId[outputPosition++] = (BYTE)(subId & mask);
1107 if (length > 1)
1108 subId = *objId++;
1113 PINDEX PASN_ObjectId::GetDataLength() const
1115 PBYTEArray dummy;
1116 CommonEncode(dummy);
1117 return dummy.GetSize();
1121 BOOL PASN_ObjectId::Decode(PASN_Stream & strm)
1123 return strm.ObjectIdDecode(*this);
1127 void PASN_ObjectId::Encode(PASN_Stream & strm) const
1129 strm.ObjectIdEncode(*this);
1133 ///////////////////////////////////////////////////////////////////////
1135 PASN_BitString::PASN_BitString(unsigned nBits, const BYTE * buf)
1136 : PASN_ConstrainedObject(UniversalBitString, UniversalTagClass),
1137 totalBits(nBits),
1138 bitData((totalBits+7)/8)
1140 if (buf != NULL)
1141 memcpy(bitData.GetPointer(), buf, bitData.GetSize());
1145 PASN_BitString::PASN_BitString(unsigned tag, TagClass tagClass, unsigned nBits)
1146 : PASN_ConstrainedObject(tag, tagClass),
1147 totalBits(nBits),
1148 bitData((totalBits+7)/8)
1153 PASN_BitString::PASN_BitString(const PASN_BitString & other)
1154 : PASN_ConstrainedObject(other),
1155 bitData(other.bitData, other.bitData.GetSize())
1157 totalBits = other.totalBits;
1161 PASN_BitString & PASN_BitString::operator=(const PASN_BitString & other)
1163 PASN_ConstrainedObject::operator=(other);
1164 totalBits = other.totalBits;
1165 bitData = PBYTEArray(other.bitData, other.bitData.GetSize());
1166 return *this;
1170 void PASN_BitString::SetData(unsigned nBits, const PBYTEArray & bytes)
1172 if ((PINDEX)nBits >= MaximumStringSize)
1173 return;
1175 bitData = bytes;
1176 SetSize(nBits);
1180 void PASN_BitString::SetData(unsigned nBits, const BYTE * buf, PINDEX size)
1182 if ((PINDEX)nBits >= MaximumStringSize)
1183 return;
1185 if (size == 0)
1186 size = (nBits+7)/8;
1187 memcpy(bitData.GetPointer(size), buf, size);
1188 SetSize(nBits);
1192 BOOL PASN_BitString::SetSize(unsigned nBits)
1194 if (!CheckByteOffset(nBits))
1195 return FALSE;
1197 if (constraint == Unconstrained)
1198 totalBits = nBits;
1199 else if (totalBits < (unsigned)lowerLimit) {
1200 if (lowerLimit < 0)
1201 return FALSE;
1202 totalBits = lowerLimit;
1203 } else if ((unsigned)totalBits > upperLimit) {
1204 if (upperLimit > (unsigned)MaximumSetSize)
1205 return FALSE;
1206 totalBits = upperLimit;
1207 } else
1208 totalBits = nBits;
1209 return bitData.SetSize((totalBits+7)/8);
1213 bool PASN_BitString::operator[](PINDEX bit) const
1215 if ((unsigned)bit < totalBits)
1216 return (bitData[bit>>3] & (1 << (7 - (bit&7)))) != 0;
1217 return FALSE;
1221 void PASN_BitString::Set(unsigned bit)
1223 if (bit < totalBits)
1224 bitData[(PINDEX)(bit>>3)] |= 1 << (7 - (bit&7));
1228 void PASN_BitString::Clear(unsigned bit)
1230 if (bit < totalBits)
1231 bitData[(PINDEX)(bit>>3)] &= ~(1 << (7 - (bit&7)));
1235 void PASN_BitString::Invert(unsigned bit)
1237 if (bit < totalBits)
1238 bitData[(PINDEX)(bit>>3)] ^= 1 << (7 - (bit&7));
1242 PObject::Comparison PASN_BitString::Compare(const PObject & obj) const
1244 PAssert(PIsDescendant(&obj, PASN_BitString), PInvalidCast);
1245 const PASN_BitString & other = (const PASN_BitString &)obj;
1246 if (totalBits < other.totalBits)
1247 return LessThan;
1248 if (totalBits > other.totalBits)
1249 return GreaterThan;
1250 return bitData.Compare(other.bitData);
1254 PObject * PASN_BitString::Clone() const
1256 PAssert(IsClass(PASN_BitString::Class()), PInvalidCast);
1257 return new PASN_BitString(*this);
1261 void PASN_BitString::PrintOn(ostream & strm) const
1263 int indent = strm.precision() + 2;
1264 _Ios_Fmtflags flags = strm.flags();
1266 if (totalBits > 128)
1267 strm << "Hex {\n"
1268 << hex << setfill('0') << resetiosflags(ios::floatfield) << setiosflags(ios::fixed)
1269 << setw(16) << setprecision(indent) << bitData
1270 << dec << setfill(' ') << resetiosflags(ios::floatfield)
1271 << setw(indent-1) << "}";
1272 else if (totalBits > 32)
1273 strm << "Hex:"
1274 << hex << setfill('0') << resetiosflags(ios::floatfield) << setiosflags(ios::fixed)
1275 << setprecision(2) << setw(16) << bitData
1276 << dec << setfill(' ') << resetiosflags(ios::floatfield);
1277 else {
1278 BYTE mask = 0x80;
1279 PINDEX offset = 0;
1280 for (unsigned i = 0; i < totalBits; i++) {
1281 strm << ((bitData[offset]&mask) != 0 ? '1' : '0');
1282 mask >>= 1;
1283 if (mask == 0) {
1284 mask = 0x80;
1285 offset++;
1290 strm.flags(flags);
1294 void PASN_BitString::SetConstraintBounds(ConstraintType type, int lower, unsigned upper)
1296 if (lower < 0)
1297 return;
1299 PASN_ConstrainedObject::SetConstraintBounds(type, lower, upper);
1300 SetSize(GetSize());
1304 PString PASN_BitString::GetTypeAsString() const
1306 return "Bit String";
1310 PINDEX PASN_BitString::GetDataLength() const
1312 return (totalBits+7)/8 + 1;
1316 BOOL PASN_BitString::Decode(PASN_Stream & strm)
1318 return strm.BitStringDecode(*this);
1322 void PASN_BitString::Encode(PASN_Stream & strm) const
1324 strm.BitStringEncode(*this);
1328 ///////////////////////////////////////////////////////////////////////
1330 PASN_OctetString::PASN_OctetString(const char * str, PINDEX size)
1331 : PASN_ConstrainedObject(UniversalOctetString, UniversalTagClass)
1333 if (str != NULL) {
1334 if (size == 0)
1335 size = ::strlen(str);
1336 SetValue((const BYTE *)str, size);
1341 PASN_OctetString::PASN_OctetString(unsigned tag, TagClass tagClass)
1342 : PASN_ConstrainedObject(tag, tagClass)
1347 PASN_OctetString::PASN_OctetString(const PASN_OctetString & other)
1348 : PASN_ConstrainedObject(other),
1349 value(other.value, other.GetSize())
1354 PASN_OctetString & PASN_OctetString::operator=(const PASN_OctetString & other)
1356 PASN_ConstrainedObject::operator=(other);
1357 value = PBYTEArray(other.value, other.GetSize());
1358 return *this;
1362 PASN_OctetString & PASN_OctetString::operator=(const char * str)
1364 if (str == NULL)
1365 value.SetSize(lowerLimit);
1366 else
1367 SetValue((const BYTE *)str, strlen(str));
1368 return *this;
1372 PASN_OctetString & PASN_OctetString::operator=(const PString & str)
1374 SetValue((const BYTE *)(const char *)str, str.GetSize()-1);
1375 return *this;
1379 PASN_OctetString & PASN_OctetString::operator=(const PBYTEArray & arr)
1381 PINDEX len = arr.GetSize();
1382 if ((unsigned)len > upperLimit || (int)len < lowerLimit)
1383 SetValue(arr, len);
1384 else
1385 value = arr;
1386 return *this;
1390 void PASN_OctetString::SetValue(const BYTE * data, PINDEX len)
1392 if ((unsigned)len > upperLimit)
1393 len = upperLimit;
1394 if (SetSize((int)len < lowerLimit ? lowerLimit : len))
1395 memcpy(value.GetPointer(), data, len);
1399 PString PASN_OctetString::AsString() const
1401 if (value.IsEmpty())
1402 return PString();
1403 return PString((const char *)(const BYTE *)value, value.GetSize());
1407 PObject::Comparison PASN_OctetString::Compare(const PObject & obj) const
1409 PAssert(PIsDescendant(&obj, PASN_OctetString), PInvalidCast);
1410 const PASN_OctetString & other = (const PASN_OctetString &)obj;
1411 return value.Compare(other.value);
1415 PObject * PASN_OctetString::Clone() const
1417 PAssert(IsClass(PASN_OctetString::Class()), PInvalidCast);
1418 return new PASN_OctetString(*this);
1422 void PASN_OctetString::PrintOn(ostream & strm) const
1424 int indent = strm.precision() + 2;
1425 _Ios_Fmtflags flags = strm.flags();
1427 strm << ' ' << value.GetSize() << " octets {\n"
1428 << hex << setfill('0') << resetiosflags(ios::floatfield)
1429 << setprecision(indent) << setw(16);
1431 if (value.GetSize() <= 32 || (flags&ios::floatfield) != ios::fixed)
1432 strm << value << '\n';
1433 else {
1434 PBYTEArray truncatedArray(value, 32);
1435 strm << truncatedArray << '\n'
1436 << setfill(' ')
1437 << setw(indent+4) << "...\n";
1440 strm << dec << setfill(' ')
1441 << setw(indent-1) << "}";
1443 strm.flags(flags);
1447 void PASN_OctetString::SetConstraintBounds(ConstraintType type, int lower, unsigned upper)
1449 if (lower < 0)
1450 return;
1452 PASN_ConstrainedObject::SetConstraintBounds(type, lower, upper);
1453 SetSize(GetSize());
1457 PString PASN_OctetString::GetTypeAsString() const
1459 return "Octet String";
1463 PINDEX PASN_OctetString::GetDataLength() const
1465 return value.GetSize();
1469 BOOL PASN_OctetString::SetSize(PINDEX newSize)
1471 if (!CheckByteOffset(newSize, MaximumStringSize))
1472 return FALSE;
1474 if (constraint != Unconstrained) {
1475 if (newSize < (PINDEX)lowerLimit) {
1476 if (lowerLimit < 0)
1477 return FALSE;
1478 newSize = lowerLimit;
1479 } else if ((unsigned)newSize > upperLimit) {
1480 if (upperLimit > (unsigned)MaximumStringSize)
1481 return FALSE;
1482 newSize = upperLimit;
1486 return value.SetSize(newSize);
1490 BOOL PASN_OctetString::Decode(PASN_Stream & strm)
1492 return strm.OctetStringDecode(*this);
1496 void PASN_OctetString::Encode(PASN_Stream & strm) const
1498 strm.OctetStringEncode(*this);
1501 ///////////////////////////////////////////////////////////////////////
1503 PASN_ConstrainedString::PASN_ConstrainedString(const char * canonical, PINDEX size,
1504 unsigned tag, TagClass tagClass)
1505 : PASN_ConstrainedObject(tag, tagClass)
1507 canonicalSet = canonical;
1508 canonicalSetSize = size;
1509 canonicalSetBits = CountBits(size);
1510 SetCharacterSet(canonicalSet, canonicalSetSize, Unconstrained);
1514 PASN_ConstrainedString & PASN_ConstrainedString::operator=(const char * str)
1516 if (str == NULL)
1517 str = "";
1519 PStringStream newValue;
1521 PINDEX len = strlen(str);
1523 // Can't copy any more characters than the upper constraint
1524 if ((unsigned)len > upperLimit)
1525 len = upperLimit;
1527 // Now copy individual characters, if they are in character set constraint
1528 for (PINDEX i = 0; i < len; i++) {
1529 PINDEX sz = characterSet.GetSize();
1530 if (sz == 0 || memchr(characterSet, str[i], sz) != NULL)
1531 newValue << str[i];
1534 // Make sure string meets minimum length constraint
1535 while ((int)len < lowerLimit) {
1536 newValue << characterSet[0];
1537 len++;
1540 value = newValue;
1541 value.MakeMinimumSize();
1542 return *this;
1546 void PASN_ConstrainedString::SetCharacterSet(ConstraintType ctype, const char * set)
1548 SetCharacterSet(set, strlen(set), ctype);
1552 void PASN_ConstrainedString::SetCharacterSet(ConstraintType ctype, unsigned firstChar, unsigned lastChar)
1554 char buffer[256];
1555 for (unsigned i = firstChar; i < lastChar; i++)
1556 buffer[i] = (char)i;
1557 SetCharacterSet(buffer, lastChar - firstChar + 1, ctype);
1561 void PASN_ConstrainedString::SetCharacterSet(const char * set, PINDEX setSize, ConstraintType ctype)
1563 if (ctype == Unconstrained) {
1564 characterSet.SetSize(canonicalSetSize);
1565 memcpy(characterSet.GetPointer(), canonicalSet, canonicalSetSize);
1567 else if (setSize >= MaximumSetSize ||
1568 canonicalSetSize >= MaximumSetSize ||
1569 characterSet.GetSize() >= MaximumSetSize)
1570 return;
1571 else {
1572 characterSet.SetSize(setSize);
1573 PINDEX count = 0;
1574 for (PINDEX i = 0; i < canonicalSetSize; i++) {
1575 if (memchr(set, canonicalSet[i], setSize) != NULL)
1576 characterSet[count++] = canonicalSet[i];
1578 if (count < 0)
1579 return;
1580 characterSet.SetSize(count);
1583 charSetUnalignedBits = CountBits(characterSet.GetSize());
1585 charSetAlignedBits = 1;
1586 while (charSetUnalignedBits > charSetAlignedBits)
1587 charSetAlignedBits <<= 1;
1589 operator=((const char *)value);
1593 PObject::Comparison PASN_ConstrainedString::Compare(const PObject & obj) const
1595 PAssert(PIsDescendant(&obj, PASN_ConstrainedString), PInvalidCast);
1596 const PASN_ConstrainedString & other = (const PASN_ConstrainedString &)obj;
1597 return value.Compare(other.value);
1601 void PASN_ConstrainedString::PrintOn(ostream & strm) const
1603 strm << value.ToLiteral();
1607 void PASN_ConstrainedString::SetConstraintBounds(ConstraintType type,
1608 int lower, unsigned upper)
1610 if (lower < 0)
1611 return;
1613 PASN_ConstrainedObject::SetConstraintBounds(type, lower, upper);
1614 if (constraint != Unconstrained) {
1615 if (value.GetSize() < (PINDEX)lowerLimit)
1616 value.SetSize(lowerLimit);
1617 else if ((unsigned)value.GetSize() > upperLimit)
1618 value.SetSize(upperLimit);
1623 PINDEX PASN_ConstrainedString::GetDataLength() const
1625 return value.GetSize()-1;
1629 BOOL PASN_ConstrainedString::Decode(PASN_Stream & strm)
1631 return strm.ConstrainedStringDecode(*this);
1635 void PASN_ConstrainedString::Encode(PASN_Stream & strm) const
1637 strm.ConstrainedStringEncode(*this);
1641 #define DEFINE_STRING_CLASS(name, set) \
1642 static const char name##StringSet[] = set; \
1643 PASN_##name##String::PASN_##name##String(const char * str) \
1644 : PASN_ConstrainedString(name##StringSet, sizeof(name##StringSet)-1, \
1645 Universal##name##String, UniversalTagClass) \
1646 { PASN_ConstrainedString::SetValue(str); } \
1647 PASN_##name##String::PASN_##name##String(unsigned tag, TagClass tagClass) \
1648 : PASN_ConstrainedString(name##StringSet, sizeof(name##StringSet)-1, tag, tagClass) \
1649 { } \
1650 PASN_##name##String & PASN_##name##String::operator=(const char * str) \
1651 { PASN_ConstrainedString::SetValue(str); return *this; } \
1652 PASN_##name##String & PASN_##name##String::operator=(const PString & str) \
1653 { PASN_ConstrainedString::SetValue(str); return *this; } \
1654 PObject * PASN_##name##String::Clone() const \
1655 { PAssert(IsClass(PASN_##name##String::Class()), PInvalidCast); \
1656 return new PASN_##name##String(*this); } \
1657 PString PASN_##name##String::GetTypeAsString() const \
1658 { return #name " String"; }
1660 DEFINE_STRING_CLASS(Numeric, " 0123456789")
1661 DEFINE_STRING_CLASS(Printable, " '()+,-./0123456789:=?"
1662 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1663 "abcdefghijklmnopqrstuvwxyz")
1664 DEFINE_STRING_CLASS(Visible, " !\"#$%&'()*+,-./0123456789:;<=>?"
1665 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
1666 "`abcdefghijklmnopqrstuvwxyz{|}~")
1667 DEFINE_STRING_CLASS(IA5, "\000\001\002\003\004\005\006\007"
1668 "\010\011\012\013\014\015\016\017"
1669 "\020\021\022\023\024\025\026\027"
1670 "\030\031\032\033\034\035\036\037"
1671 " !\"#$%&'()*+,-./0123456789:;<=>?"
1672 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
1673 "`abcdefghijklmnopqrstuvwxyz{|}~\177")
1674 DEFINE_STRING_CLASS(General, "\000\001\002\003\004\005\006\007"
1675 "\010\011\012\013\014\015\016\017"
1676 "\020\021\022\023\024\025\026\027"
1677 "\030\031\032\033\034\035\036\037"
1678 " !\"#$%&'()*+,-./0123456789:;<=>?"
1679 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
1680 "`abcdefghijklmnopqrstuvwxyz{|}~\177"
1681 "\200\201\202\203\204\205\206\207"
1682 "\210\211\212\213\214\215\216\217"
1683 "\220\221\222\223\224\225\226\227"
1684 "\230\231\232\233\234\235\236\237"
1685 "\240\241\242\243\244\245\246\247"
1686 "\250\251\252\253\254\255\256\257"
1687 "\260\261\262\263\264\265\266\267"
1688 "\270\271\272\273\274\275\276\277"
1689 "\300\301\302\303\304\305\306\307"
1690 "\310\311\312\313\314\315\316\317"
1691 "\320\321\322\323\324\325\326\327"
1692 "\330\331\332\333\334\335\336\337"
1693 "\340\341\342\343\344\345\346\347"
1694 "\350\351\352\353\354\355\356\357"
1695 "\360\361\362\363\364\365\366\367"
1696 "\370\371\372\373\374\375\376\377")
1699 ///////////////////////////////////////////////////////////////////////
1701 PASN_BMPString::PASN_BMPString(const char * str)
1702 : PASN_ConstrainedObject(UniversalBMPString, UniversalTagClass)
1704 Construct();
1705 if (str != NULL)
1706 SetValue(str);
1710 PASN_BMPString::PASN_BMPString(const PWORDArray & wstr)
1711 : PASN_ConstrainedObject(UniversalBMPString, UniversalTagClass)
1713 Construct();
1714 SetValue(wstr);
1718 PASN_BMPString::PASN_BMPString(unsigned tag, TagClass tagClass)
1719 : PASN_ConstrainedObject(tag, tagClass)
1721 Construct();
1725 void PASN_BMPString::Construct()
1727 firstChar = 0;
1728 lastChar = 0xffff;
1729 charSetAlignedBits = 16;
1730 charSetUnalignedBits = 16;
1734 PASN_BMPString::PASN_BMPString(const PASN_BMPString & other)
1735 : PASN_ConstrainedObject(other),
1736 value(other.value, other.value.GetSize()),
1737 characterSet(other.characterSet)
1739 firstChar = other.firstChar;
1740 lastChar = other.lastChar;
1741 charSetAlignedBits = other.charSetAlignedBits;
1742 charSetUnalignedBits = other.charSetUnalignedBits;
1746 PASN_BMPString & PASN_BMPString::operator=(const PASN_BMPString & other)
1748 PASN_ConstrainedObject::operator=(other);
1750 value = PWORDArray(other.value, other.value.GetSize());
1751 characterSet = other.characterSet;
1752 firstChar = other.firstChar;
1753 lastChar = other.lastChar;
1754 charSetAlignedBits = other.charSetAlignedBits;
1755 charSetUnalignedBits = other.charSetUnalignedBits;
1757 return *this;
1761 BOOL PASN_BMPString::IsLegalCharacter(WORD ch)
1763 if (ch < firstChar)
1764 return FALSE;
1766 if (ch > lastChar)
1767 return FALSE;
1769 if (characterSet.IsEmpty())
1770 return TRUE;
1772 const WORD * wptr = characterSet;
1773 PINDEX count = characterSet.GetSize();
1774 while (count-- > 0) {
1775 if (*wptr == ch)
1776 return TRUE;
1777 wptr++;
1780 return FALSE;
1784 PASN_BMPString & PASN_BMPString::operator=(const PWORDArray & array)
1786 PINDEX paramSize = array.GetSize();
1788 // Can't copy any more than the upper constraint
1789 if ((unsigned)paramSize > upperLimit)
1790 paramSize = upperLimit;
1792 // Number of bytes must be at least lhe lower constraint
1793 PINDEX newSize = (int)paramSize < lowerLimit ? lowerLimit : paramSize;
1794 value.SetSize(newSize);
1796 PINDEX count = 0;
1797 for (PINDEX i = 0; i < paramSize; i++) {
1798 WORD c = array[i];
1799 if (IsLegalCharacter(c))
1800 value[count++] = c;
1803 // Pad out with the first character till required size
1804 while (count < newSize)
1805 value[count++] = firstChar;
1807 return *this;
1811 void PASN_BMPString::SetCharacterSet(ConstraintType ctype, const char * charSet)
1813 PWORDArray array(strlen(charSet));
1815 PINDEX count = 0;
1816 while (*charSet != '\0')
1817 array[count++] = (BYTE)*charSet++;
1819 SetCharacterSet(ctype, array);
1823 void PASN_BMPString::SetCharacterSet(ConstraintType ctype, const PWORDArray & charSet)
1825 if (ctype == Unconstrained) {
1826 firstChar = 0;
1827 lastChar = 0xffff;
1828 characterSet.SetSize(0);
1830 else {
1831 characterSet = charSet;
1833 charSetUnalignedBits = CountBits(lastChar - firstChar + 1);
1834 if (!charSet.IsEmpty()) {
1835 unsigned count = 0;
1836 for (PINDEX i = 0; i < charSet.GetSize(); i++) {
1837 if (characterSet[i] >= firstChar && characterSet[i] <= lastChar)
1838 count++;
1840 count = CountBits(count);
1841 if (charSetUnalignedBits > count)
1842 charSetUnalignedBits = count;
1845 charSetAlignedBits = 1;
1846 while (charSetUnalignedBits > charSetAlignedBits)
1847 charSetAlignedBits <<= 1;
1849 SetValue(value);
1854 void PASN_BMPString::SetCharacterSet(ConstraintType ctype, unsigned first, unsigned last)
1856 if (ctype != Unconstrained) {
1857 PAssert(first < 0x10000 && last < 0x10000 && last > first, PInvalidParameter);
1858 firstChar = (WORD)first;
1859 lastChar = (WORD)last;
1861 SetCharacterSet(ctype, characterSet);
1865 PObject * PASN_BMPString::Clone() const
1867 PAssert(IsClass(PASN_BMPString::Class()), PInvalidCast);
1868 return new PASN_BMPString(*this);
1872 PObject::Comparison PASN_BMPString::Compare(const PObject & obj) const
1874 PAssert(PIsDescendant(&obj, PASN_BMPString), PInvalidCast);
1875 const PASN_BMPString & other = (const PASN_BMPString &)obj;
1876 return value.Compare(other.value);
1880 void PASN_BMPString::PrintOn(ostream & strm) const
1882 int indent = strm.precision() + 2;
1883 PINDEX sz = value.GetSize();
1884 strm << ' ' << sz << " characters {\n";
1885 PINDEX i = 0;
1886 while (i < sz) {
1887 strm << setw(indent) << " " << hex << setfill('0');
1888 PINDEX j;
1889 for (j = 0; j < 8; j++)
1890 if (i+j < sz)
1891 strm << setw(4) << value[i+j] << ' ';
1892 else
1893 strm << " ";
1894 strm << " ";
1895 for (j = 0; j < 8; j++) {
1896 if (i+j < sz) {
1897 WORD c = value[i+j];
1898 if (c < 128 && isprint(c))
1899 strm << (char)c;
1900 else
1901 strm << ' ';
1904 strm << dec << setfill(' ') << '\n';
1905 i += 8;
1907 strm << setw(indent-1) << "}";
1911 PString PASN_BMPString::GetTypeAsString() const
1913 return "BMP String";
1917 PINDEX PASN_BMPString::GetDataLength() const
1919 return value.GetSize()*2;
1923 BOOL PASN_BMPString::Decode(PASN_Stream & strm)
1925 return strm.BMPStringDecode(*this);
1929 void PASN_BMPString::Encode(PASN_Stream & strm) const
1931 strm.BMPStringEncode(*this);
1935 ///////////////////////////////////////////////////////////////////////
1937 PASN_GeneralisedTime & PASN_GeneralisedTime::operator=(const PTime & time)
1939 value = time.AsString("yyyyMMddhhmmss.uz");
1940 value.Replace("GMT", "Z");
1941 return *this;
1945 PTime PASN_GeneralisedTime::GetValue() const
1947 int year = value(0,3).AsInteger();
1948 int month = value(4,5).AsInteger();
1949 int day = value(6,7).AsInteger();
1950 int hour = value(8,9).AsInteger();
1951 int minute = value(10,11).AsInteger();
1952 int seconds = 0;
1953 int zonePos = 12;
1955 if (isdigit(value[12])) {
1956 seconds = value(12,13).AsInteger();
1957 if (value[14] != '.')
1958 zonePos = 14;
1959 else {
1960 zonePos = 15;
1961 while (isdigit(value[zonePos]))
1962 zonePos++;
1966 int zone = PTime::Local;
1967 switch (value[zonePos]) {
1968 case 'Z' :
1969 zone = PTime::UTC;
1970 break;
1971 case '+' :
1972 case '-' :
1973 zone = value(zonePos+1,zonePos+2).AsInteger()*60 +
1974 value(zonePos+3,zonePos+4).AsInteger();
1977 return PTime(seconds, minute, hour, day, month, year, zone);
1981 ///////////////////////////////////////////////////////////////////////
1983 PASN_UniversalTime & PASN_UniversalTime::operator=(const PTime & time)
1985 value = time.AsString("yyMMddhhmmssz");
1986 value.Replace("GMT", "Z");
1987 value.MakeMinimumSize();
1988 return *this;
1992 PTime PASN_UniversalTime::GetValue() const
1994 int year = value(0,1).AsInteger();
1995 if (year < 36)
1996 year += 2000;
1997 else
1998 year += 1900;
2000 int month = value(2,3).AsInteger();
2001 int day = value(4,5).AsInteger();
2002 int hour = value(6,7).AsInteger();
2003 int minute = value(8,9).AsInteger();
2004 int seconds = 0;
2005 int zonePos = 10;
2007 if (isdigit(value[10])) {
2008 seconds = value(10,11).AsInteger();
2009 zonePos = 12;
2012 int zone = PTime::UTC;
2013 if (value[zonePos] != 'Z')
2014 zone = value(zonePos+1,zonePos+2).AsInteger()*60 +
2015 value(zonePos+3,zonePos+4).AsInteger();
2017 return PTime(seconds, minute, hour, day, month, year, zone);
2021 ///////////////////////////////////////////////////////////////////////
2023 PASN_Choice::PASN_Choice(unsigned nChoices, BOOL extend)
2024 : PASN_Object(0, ApplicationTagClass, extend)
2026 numChoices = nChoices;
2027 choice = NULL;
2031 PASN_Choice::PASN_Choice(unsigned tag, TagClass tagClass,
2032 unsigned upper, BOOL extend)
2033 : PASN_Object(tag, tagClass, extend)
2035 numChoices = upper;
2036 choice = NULL;
2040 PASN_Choice::PASN_Choice(unsigned tag, TagClass tagClass,
2041 unsigned upper, BOOL extend, const PString & nameSpec)
2042 : PASN_Object(tag, tagClass, extend),
2043 names(BuildNamesDict(nameSpec))
2045 numChoices = upper;
2046 choice = NULL;
2050 PASN_Choice::PASN_Choice(const PASN_Choice & other)
2051 : PASN_Object(other),
2052 names(other.names)
2054 numChoices = other.numChoices;
2056 if (other.CheckCreate())
2057 choice = (PASN_Object *)other.choice->Clone();
2058 else
2059 choice = NULL;
2063 PASN_Choice & PASN_Choice::operator=(const PASN_Choice & other)
2065 if (&other == this) // Assigning to ourself, just do nothing.
2066 return *this;
2068 delete choice;
2070 PASN_Object::operator=(other);
2072 numChoices = other.numChoices;
2073 names = other.names;
2075 if (other.CheckCreate())
2076 choice = (PASN_Object *)other.choice->Clone();
2077 else
2078 choice = NULL;
2080 return *this;
2084 PASN_Choice::~PASN_Choice()
2086 delete choice;
2090 void PASN_Choice::SetTag(unsigned newTag, TagClass tagClass)
2092 PASN_Object::SetTag(newTag, tagClass);
2094 delete choice;
2096 if (CreateObject())
2097 choice->SetTag(newTag, tagClass);
2101 PString PASN_Choice::GetTagName() const
2103 if (names.Contains(tag))
2104 return names[tag];
2106 if (CheckCreate() &&
2107 PIsDescendant(choice, PASN_Choice) &&
2108 choice->GetTag() == tag &&
2109 choice->GetTagClass() == tagClass)
2110 return PString(choice->GetClass()) + "->" + ((PASN_Choice *)choice)->GetTagName();
2112 return psprintf("<%u>", tag);
2116 BOOL PASN_Choice::CheckCreate() const
2118 if (choice != NULL)
2119 return TRUE;
2121 return ((PASN_Choice *)this)->CreateObject();
2125 PASN_Object & PASN_Choice::GetObject() const
2127 PAssert(CheckCreate(), "NULL Choice");
2128 return *choice;
2132 #if defined(__GNUC__) && __GNUC__ <= 2 && __GNUC_MINOR__ < 9
2134 #define CHOICE_CAST_OPERATOR(cls) \
2135 PASN_Choice::operator cls &() const \
2137 PAssert(CheckCreate(), "Cast of NULL choice"); \
2138 PAssert(choice->IsDescendant(cls::Class()), PInvalidCast); \
2139 return *(cls *)choice; \
2142 #else
2144 #define CHOICE_CAST_OPERATOR(cls) \
2145 PASN_Choice::operator cls &() \
2147 PAssert(CheckCreate(), "Cast of NULL choice"); \
2148 PAssert(PIsDescendant(choice, cls), PInvalidCast); \
2149 return *(cls *)choice; \
2151 PASN_Choice::operator const cls &() const \
2153 PAssert(CheckCreate(), "Cast of NULL choice"); \
2154 PAssert(PIsDescendant(choice, cls), PInvalidCast); \
2155 return *(const cls *)choice; \
2158 #endif
2161 CHOICE_CAST_OPERATOR(PASN_Null)
2162 CHOICE_CAST_OPERATOR(PASN_Boolean)
2163 CHOICE_CAST_OPERATOR(PASN_Integer)
2164 CHOICE_CAST_OPERATOR(PASN_Enumeration)
2165 CHOICE_CAST_OPERATOR(PASN_Real)
2166 CHOICE_CAST_OPERATOR(PASN_ObjectId)
2167 CHOICE_CAST_OPERATOR(PASN_BitString)
2168 CHOICE_CAST_OPERATOR(PASN_OctetString)
2169 CHOICE_CAST_OPERATOR(PASN_NumericString)
2170 CHOICE_CAST_OPERATOR(PASN_PrintableString)
2171 CHOICE_CAST_OPERATOR(PASN_VisibleString)
2172 CHOICE_CAST_OPERATOR(PASN_IA5String)
2173 CHOICE_CAST_OPERATOR(PASN_GeneralString)
2174 CHOICE_CAST_OPERATOR(PASN_BMPString)
2175 CHOICE_CAST_OPERATOR(PASN_Sequence)
2178 PObject::Comparison PASN_Choice::Compare(const PObject & obj) const
2180 PAssert(PIsDescendant(&obj, PASN_Choice), PInvalidCast);
2181 const PASN_Choice & other = (const PASN_Choice &)obj;
2183 CheckCreate();
2184 other.CheckCreate();
2186 if (choice == other.choice)
2187 return EqualTo;
2189 if (choice == NULL)
2190 return LessThan;
2192 if (other.choice == NULL)
2193 return GreaterThan;
2195 if (tag < other.tag)
2196 return LessThan;
2198 if (tag > other.tag)
2199 return GreaterThan;
2201 return choice->Compare(*other.choice);
2205 void PASN_Choice::PrintOn(ostream & strm) const
2207 strm << GetTagName();
2209 if (choice != NULL)
2210 strm << ' ' << *choice;
2211 else
2212 strm << " (NULL)";
2216 PString PASN_Choice::GetTypeAsString() const
2218 return "Choice";
2222 PINDEX PASN_Choice::GetDataLength() const
2224 if (CheckCreate())
2225 return choice->GetDataLength();
2227 return 0;
2231 BOOL PASN_Choice::IsPrimitive() const
2233 if (CheckCreate())
2234 return choice->IsPrimitive();
2235 return FALSE;
2239 BOOL PASN_Choice::Decode(PASN_Stream & strm)
2241 return strm.ChoiceDecode(*this);
2245 void PASN_Choice::Encode(PASN_Stream & strm) const
2247 strm.ChoiceEncode(*this);
2251 ///////////////////////////////////////////////////////////////////////
2253 PASN_Sequence::PASN_Sequence(unsigned tag, TagClass tagClass,
2254 unsigned nOpts, BOOL extend, unsigned nExtend)
2255 : PASN_Object(tag, tagClass, extend)
2257 optionMap.SetConstraints(PASN_ConstrainedObject::FixedConstraint, nOpts);
2258 knownExtensions = nExtend;
2259 totalExtensions = 0;
2260 endBasicEncoding = 0;
2264 PASN_Sequence::PASN_Sequence(const PASN_Sequence & other)
2265 : PASN_Object(other),
2266 fields(other.fields.GetSize()),
2267 optionMap(other.optionMap),
2268 extensionMap(other.extensionMap)
2270 for (PINDEX i = 0; i < other.fields.GetSize(); i++)
2271 fields.SetAt(i, other.fields[i].Clone());
2273 knownExtensions = other.knownExtensions;
2274 totalExtensions = other.totalExtensions;
2275 endBasicEncoding = 0;
2279 PASN_Sequence & PASN_Sequence::operator=(const PASN_Sequence & other)
2281 PASN_Object::operator=(other);
2283 fields.SetSize(other.fields.GetSize());
2284 for (PINDEX i = 0; i < other.fields.GetSize(); i++)
2285 fields.SetAt(i, other.fields[i].Clone());
2287 optionMap = other.optionMap;
2288 knownExtensions = other.knownExtensions;
2289 totalExtensions = other.totalExtensions;
2290 extensionMap = other.extensionMap;
2292 return *this;
2296 BOOL PASN_Sequence::HasOptionalField(PINDEX opt) const
2298 if (opt < (PINDEX)optionMap.GetSize())
2299 return optionMap[opt];
2300 else
2301 return extensionMap[opt - optionMap.GetSize()];
2305 void PASN_Sequence::IncludeOptionalField(PINDEX opt)
2307 if (opt < (PINDEX)optionMap.GetSize())
2308 optionMap.Set(opt);
2309 else {
2310 PAssert(extendable, "Must be extendable type");
2311 opt -= optionMap.GetSize();
2312 if (opt >= (PINDEX)extensionMap.GetSize())
2313 extensionMap.SetSize(opt+1);
2314 extensionMap.Set(opt);
2319 void PASN_Sequence::RemoveOptionalField(PINDEX opt)
2321 if (opt < (PINDEX)optionMap.GetSize())
2322 optionMap.Clear(opt);
2323 else {
2324 PAssert(extendable, "Must be extendable type");
2325 opt -= optionMap.GetSize();
2326 extensionMap.Clear(opt);
2331 PObject::Comparison PASN_Sequence::Compare(const PObject & obj) const
2333 PAssert(PIsDescendant(&obj, PASN_Sequence), PInvalidCast);
2334 const PASN_Sequence & other = (const PASN_Sequence &)obj;
2335 return fields.Compare(other.fields);
2339 PObject * PASN_Sequence::Clone() const
2341 PAssert(IsClass(PASN_Sequence::Class()), PInvalidCast);
2342 return new PASN_Sequence(*this);
2346 void PASN_Sequence::PrintOn(ostream & strm) const
2348 int indent = strm.precision() + 2;
2349 strm << "{\n";
2350 for (PINDEX i = 0; i < fields.GetSize(); i++) {
2351 strm << setw(indent+6) << "field[" << i << "] <";
2352 switch (fields[i].GetTagClass()) {
2353 case UniversalTagClass :
2354 strm << "Universal";
2355 break;
2356 case ApplicationTagClass :
2357 strm << "Application";
2358 break;
2359 case ContextSpecificTagClass :
2360 strm << "ContextSpecific";
2361 break;
2362 case PrivateTagClass :
2363 strm << "Private";
2364 default :
2365 break;
2367 strm << '-' << fields[i].GetTag() << '-'
2368 << fields[i].GetTypeAsString() << "> = "
2369 << fields[i] << '\n';
2371 strm << setw(indent-1) << "}";
2375 PString PASN_Sequence::GetTypeAsString() const
2377 return "Sequence";
2381 PINDEX PASN_Sequence::GetDataLength() const
2383 PINDEX len = 0;
2384 for (PINDEX i = 0; i < fields.GetSize(); i++)
2385 len += fields[i].GetObjectLength();
2386 return len;
2390 BOOL PASN_Sequence::IsPrimitive() const
2392 return FALSE;
2396 BOOL PASN_Sequence::Decode(PASN_Stream & strm)
2398 return PreambleDecode(strm) && UnknownExtensionsDecode(strm);
2402 void PASN_Sequence::Encode(PASN_Stream & strm) const
2404 PreambleEncode(strm);
2405 UnknownExtensionsEncode(strm);
2409 BOOL PASN_Sequence::PreambleDecode(PASN_Stream & strm)
2411 return strm.SequencePreambleDecode(*this);
2415 void PASN_Sequence::PreambleEncode(PASN_Stream & strm) const
2417 strm.SequencePreambleEncode(*this);
2421 BOOL PASN_Sequence::KnownExtensionDecode(PASN_Stream & strm, PINDEX fld, PASN_Object & field)
2423 return strm.SequenceKnownDecode(*this, fld, field);
2427 void PASN_Sequence::KnownExtensionEncode(PASN_Stream & strm, PINDEX fld, const PASN_Object & field) const
2429 strm.SequenceKnownEncode(*this, fld, field);
2433 BOOL PASN_Sequence::UnknownExtensionsDecode(PASN_Stream & strm)
2435 return strm.SequenceUnknownDecode(*this);
2439 void PASN_Sequence::UnknownExtensionsEncode(PASN_Stream & strm) const
2441 strm.SequenceUnknownEncode(*this);
2445 ///////////////////////////////////////////////////////////////////////
2447 PASN_Set::PASN_Set(unsigned tag, TagClass tagClass,
2448 unsigned nOpts, BOOL extend, unsigned nExtend)
2449 : PASN_Sequence(tag, tagClass, nOpts, extend, nExtend)
2454 PObject * PASN_Set::Clone() const
2456 PAssert(IsClass(PASN_Set::Class()), PInvalidCast);
2457 return new PASN_Set(*this);
2461 PString PASN_Set::GetTypeAsString() const
2463 return "Set";
2466 ///////////////////////////////////////////////////////////////////////
2468 PASN_Array::PASN_Array(unsigned tag, TagClass tagClass)
2469 : PASN_ConstrainedObject(tag, tagClass)
2474 PASN_Array::PASN_Array(const PASN_Array & other)
2475 : PASN_ConstrainedObject(other),
2476 array(other.array.GetSize())
2478 for (PINDEX i = 0; i < other.array.GetSize(); i++)
2479 array.SetAt(i, other.array[i].Clone());
2483 PASN_Array & PASN_Array::operator=(const PASN_Array & other)
2485 PASN_ConstrainedObject::operator=(other);
2487 array.SetSize(other.array.GetSize());
2488 for (PINDEX i = 0; i < other.array.GetSize(); i++)
2489 array.SetAt(i, other.array[i].Clone());
2491 return *this;
2495 BOOL PASN_Array::SetSize(PINDEX newSize)
2497 if (newSize > MaximumArraySize)
2498 return FALSE;
2500 PINDEX originalSize = array.GetSize();
2501 if (!array.SetSize(newSize))
2502 return FALSE;
2504 for (PINDEX i = originalSize; i < newSize; i++) {
2505 PASN_Object * obj = CreateObject();
2506 if (obj == NULL)
2507 return FALSE;
2509 array.SetAt(i, obj);
2512 return TRUE;
2516 PObject::Comparison PASN_Array::Compare(const PObject & obj) const
2518 PAssert(PIsDescendant(&obj, PASN_Array), PInvalidCast);
2519 const PASN_Array & other = (const PASN_Array &)obj;
2520 return array.Compare(other.array);
2524 void PASN_Array::PrintOn(ostream & strm) const
2526 int indent = strm.precision() + 2;
2527 strm << array.GetSize() << " entries {\n";
2528 for (PINDEX i = 0; i < array.GetSize(); i++)
2529 strm << setw(indent+1) << "[" << i << "]=" << setprecision(indent) << array[i] << '\n';
2530 strm << setw(indent-1) << "}";
2534 void PASN_Array::SetConstraintBounds(ConstraintType type, int lower, unsigned upper)
2536 if (lower < 0)
2537 return;
2539 PASN_ConstrainedObject::SetConstraintBounds(type, lower, upper);
2540 if (constraint != Unconstrained) {
2541 if (GetSize() < (PINDEX)lowerLimit)
2542 SetSize(lowerLimit);
2543 else if (GetSize() > (PINDEX)upperLimit)
2544 SetSize(upperLimit);
2549 PString PASN_Array::GetTypeAsString() const
2551 return "Array";
2555 PINDEX PASN_Array::GetDataLength() const
2557 PINDEX len = 0;
2558 for (PINDEX i = 0; i < array.GetSize(); i++)
2559 len += array[i].GetObjectLength();
2560 return len;
2564 BOOL PASN_Array::IsPrimitive() const
2566 return FALSE;
2570 BOOL PASN_Array::Decode(PASN_Stream & strm)
2572 return strm.ArrayDecode(*this);
2576 void PASN_Array::Encode(PASN_Stream & strm) const
2578 strm.ArrayEncode(*this);
2582 ///////////////////////////////////////////////////////////////////////
2584 PASN_Stream::PASN_Stream()
2586 Construct();
2590 PASN_Stream::PASN_Stream(const PBYTEArray & bytes)
2591 : PBYTEArray(bytes)
2593 Construct();
2597 PASN_Stream::PASN_Stream(const BYTE * buf, PINDEX size)
2598 : PBYTEArray(buf, size)
2600 Construct();
2604 void PASN_Stream::Construct()
2606 byteOffset = 0;
2607 bitOffset = 8;
2611 void PASN_Stream::PrintOn(ostream & strm) const
2613 int indent = strm.precision() + 2;
2614 strm << " size=" << GetSize()
2615 << " pos=" << byteOffset << '.' << (8-bitOffset)
2616 << " {\n";
2617 PINDEX i = 0;
2618 while (i < GetSize()) {
2619 strm << setw(indent) << " " << hex << setfill('0');
2620 PINDEX j;
2621 for (j = 0; j < 16; j++)
2622 if (i+j < GetSize())
2623 strm << setw(2) << (unsigned)(BYTE)theArray[i+j] << ' ';
2624 else
2625 strm << " ";
2626 strm << " ";
2627 for (j = 0; j < 16; j++) {
2628 if (i+j < GetSize()) {
2629 BYTE c = theArray[i+j];
2630 if (c < 128 && isprint(c))
2631 strm << c;
2632 else
2633 strm << ' ';
2636 strm << dec << setfill(' ') << '\n';
2637 i += 16;
2639 strm << setw(indent-1) << "}";
2643 void PASN_Stream::SetPosition(PINDEX newPos)
2645 if (!CheckByteOffset(byteOffset))
2646 return;
2648 if (newPos > GetSize())
2649 byteOffset = GetSize();
2650 else
2651 byteOffset = newPos;
2652 bitOffset = 8;
2656 void PASN_Stream::ResetDecoder()
2658 byteOffset = 0;
2659 bitOffset = 8;
2663 void PASN_Stream::BeginEncoding()
2665 bitOffset = 8;
2666 byteOffset = 0;
2667 PBYTEArray::operator=(PBYTEArray(20));
2671 void PASN_Stream::CompleteEncoding()
2673 if (byteOffset != P_MAX_INDEX) {
2674 if (bitOffset != 8) {
2675 bitOffset = 8;
2676 byteOffset++;
2678 SetSize(byteOffset);
2679 byteOffset = P_MAX_INDEX;
2684 BYTE PASN_Stream::ByteDecode()
2686 if (!CheckByteOffset(byteOffset, GetSize()))
2687 return 0;
2689 bitOffset = 8;
2690 return theArray[byteOffset++];
2694 void PASN_Stream::ByteEncode(unsigned value)
2696 if (!CheckByteOffset(byteOffset))
2697 return;
2699 if (bitOffset != 8) {
2700 bitOffset = 8;
2701 byteOffset++;
2703 if (byteOffset >= GetSize())
2704 SetSize(byteOffset+10);
2705 theArray[byteOffset++] = (BYTE)value;
2709 unsigned PASN_Stream::BlockDecode(BYTE * bufptr, unsigned nBytes)
2711 if (nBytes == 0 || bufptr == NULL || !CheckByteOffset(byteOffset+nBytes))
2712 return 0;
2714 ByteAlign();
2716 if (byteOffset+nBytes > (unsigned)GetSize()) {
2717 nBytes = GetSize() - byteOffset;
2718 if (nBytes <= 0)
2719 return 0;
2722 memcpy(bufptr, &theArray[byteOffset], nBytes);
2723 byteOffset += nBytes;
2724 return nBytes;
2728 void PASN_Stream::BlockEncode(const BYTE * bufptr, PINDEX nBytes)
2730 if (!CheckByteOffset(byteOffset, GetSize()))
2731 return;
2733 if (nBytes == 0)
2734 return;
2736 ByteAlign();
2738 if (byteOffset+nBytes >= GetSize())
2739 SetSize(byteOffset+nBytes+10);
2741 memcpy(theArray+byteOffset, bufptr, nBytes);
2742 byteOffset += nBytes;
2746 void PASN_Stream::ByteAlign()
2748 if (!CheckByteOffset(byteOffset, GetSize()))
2749 return;
2751 if (bitOffset != 8) {
2752 bitOffset = 8;
2753 byteOffset++;
2758 ///////////////////////////////////////////////////////////////////////
2760 #ifdef P_INCLUDE_PER
2761 #include "asnper.cxx"
2762 #endif
2764 #ifdef P_INCLUDE_BER
2765 #include "asnber.cxx"
2766 #endif
2768 #ifdef P_INCLUDE_XER
2769 #include "asnxer.cxx"
2770 #endif
2772 // End of file ////////////////////////////////////////////////////////////////