Fixed incorrect usage of result (now object rather than scalar), thanks Michal Zygmun...
[pwlib.git] / src / ptclib / asner.cxx
blobfe73031b106cb2ce1b3f7fedc91690472fdb8e2d
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.86 2004/04/22 07:54:01 csoutheren
28 * Fix problem with VS.net asserting on in isprint when chars outside normal range
30 * Revision 1.85 2004/04/18 04:33:37 rjongbloed
31 * Changed all operators that return BOOL to return standard type bool. This is primarily
32 * for improved compatibility with std STL usage removing many warnings.
34 * Revision 1.84 2004/04/03 08:22:20 csoutheren
35 * Remove pseudo-RTTI and replaced with real RTTI
37 * Revision 1.83 2004/01/17 09:21:21 csoutheren
38 * Added protection against NULL ptr to PASN_Stream::BlockDecode
40 * Revision 1.82 2003/08/01 02:11:38 csoutheren
41 * Changed to allow easy isolation of PER, BER and XER encoding/decoding routines
43 * Revision 1.81 2003/04/28 02:50:33 robertj
44 * Fixed problem with spaces in type name, thanks Federico Pinna
46 * Revision 1.80 2003/02/26 04:37:21 robertj
47 * Tidied some comments
49 * Revision 1.79 2003/02/26 01:57:44 robertj
50 * Added XML encoding rules to ASN system, thanks Federico Pinna
52 * Revision 1.78 2003/01/24 23:43:43 robertj
53 * Fixed subtle problems with the use of MAX keyword for unsigned numbers,
54 * should beUINT_MAX not INT_MAX, thanks Stevie Gray for pointing it out.
56 * Revision 1.77 2002/12/17 07:00:15 robertj
57 * Fixed incorrect encoding of arrays greater than 8192 and less than 16384
59 * Revision 1.76 2002/12/13 03:57:17 robertj
60 * Fixed crash if enable extension fields beyond the "known" extensions.
62 * Revision 1.75 2002/12/02 01:03:33 robertj
63 * Fixed bug were if setting the size of a constrained bit string, it
64 * actually sets the size of the underlying byte array correctly.
66 * Revision 1.74 2002/11/26 23:29:32 robertj
67 * Added missing const to DecodeSubType() function.
69 * Revision 1.73 2002/11/22 09:43:32 robertj
70 * Fixed encoding of a ASN NULL sequence extension field, eg fastConnectRefused
72 * Revision 1.72 2002/11/21 03:46:22 robertj
73 * Changed to encode only the minimum number of bits required, this improves
74 * compatibility with some brain dead ASN decoders.
76 * Revision 1.71 2002/11/06 22:47:24 robertj
77 * Fixed header comment (copyright etc)
79 * Revision 1.70 2002/10/31 05:51:10 robertj
80 * Changed to use new UTF-8/UCS-2 conversion functions on PString.
82 * Revision 1.69 2002/10/29 08:12:44 robertj
83 * Fixed MSVC warnings.
85 * Revision 1.68 2002/10/29 07:26:45 robertj
86 * Fixed subtle bug when encoding or decoding Octet String with 1 or 2 bytes
87 * in it, was not byte aligned correctly.
89 * Revision 1.67 2002/09/26 23:53:20 robertj
90 * Fixed incorrect asserts in PASN_Enumerated, thanks Platzer Wolfgang
92 * Revision 1.66 2002/09/13 08:16:15 robertj
93 * Fixed missing line feed when dumping hex octet strings.
95 * Revision 1.65 2002/08/06 02:27:58 robertj
96 * GNU C++ v3 compatibility.
98 * Revision 1.64 2002/07/25 10:52:49 robertj
99 * Changes to allow more granularity in PDU dumps, hex output increasing
100 * with increasing trace level.
102 * Revision 1.63 2002/06/05 12:29:15 craigs
103 * Changes for gcc 3.1
105 * Revision 1.62 2002/05/29 01:22:35 robertj
106 * Added ability to set object id from unsigned integer arrays.
108 * Revision 1.61 2002/05/21 04:23:40 robertj
109 * Fixed problem with ASN encoding/decoding unsconstrained negative numbers,
111 * Revision 1.60 2002/05/14 08:34:29 robertj
112 * Fixed problem encoding unsigned where value==lower bound, thanks Greg Adams.
114 * Revision 1.59 2002/05/14 06:59:50 robertj
115 * Added more bullet proofing so a malformed PDU cannot cause teh decoder
116 * to try and allocate huge arrays and consume all CPU and memory on a
117 * system. A configurable limit of 100 is set for things like SEQUENCE OF.
119 * Revision 1.58 2002/02/08 12:47:19 robertj
120 * Fixed incorrect encoding of integer, did not allow for sign bit, thanks Kevin Tran.
122 * Revision 1.57 2002/02/01 01:17:36 robertj
123 * Fixed bug in encoding empty strings (H.450 issue), thanks Frans Dams, Frank Derks et al.
125 * Revision 1.56 2002/01/30 08:40:55 robertj
126 * Fixed incorrect decode function in BER string decode, thanks ct_dev@sohu.com
128 * Revision 1.55 2001/12/13 09:13:57 robertj
129 * Added function get get oid as a string.
131 * Revision 1.54 2001/11/26 03:07:13 robertj
132 * Fixed decode of extendable constrained integer types.
134 * Revision 1.53 2001/09/14 05:26:11 robertj
135 * Fixed problem with assigning a PASN_Choice to itself, thanks Chih-Wei Huang
137 * Revision 1.52 2001/09/14 01:59:59 robertj
138 * Fixed problem with incorrectly initialised PASN_Choice sub-object.
140 * Revision 1.51 2001/08/08 04:19:28 robertj
141 * Fixed PString<->BMPString conversion so can have embedded nulls.
143 * Revision 1.50 2001/08/07 04:37:03 robertj
144 * Simplified &#num; parsing.
146 * Revision 1.49 2001/08/07 02:49:05 robertj
147 * Fixed incorrect alignment if constrained string upper bound is exactly
148 * 16 bits long. thanks Guntram Diehl & Thomas Arimont.
150 * Revision 1.48 2001/08/06 09:35:25 robertj
151 * Fixed GNU compatibility.
153 * Revision 1.47 2001/08/06 09:31:48 robertj
154 * Added conversion of BMPString to PString without losing special characters.
156 * Revision 1.46 2001/08/06 01:39:02 robertj
157 * Added assignement operator with RHS of PASN_BMPString to classes
158 * descended from PASN_BMPString.
160 * Revision 1.45 2001/06/14 02:14:12 robertj
161 * Added functions to encode and decode another ASN type that is inside
162 * an octet string, useful for ANY or EXTERNAL types etc.
164 * Revision 1.44 2001/05/29 00:59:16 robertj
165 * Fixed excessive padding on constrained strings.
167 * Revision 1.43 2001/05/22 23:37:42 robertj
168 * Fixed problem with assigning a constrained string value to itself, which
169 * can occur when changing constraints.
171 * Revision 1.42 2001/04/30 10:47:33 robertj
172 * Fixed stupid error in last patch.
174 * Revision 1.41 2001/04/30 06:47:04 robertj
175 * Fixed problem with en/decoding more than 16 extension fields in a sequence.
177 * Revision 1.40 2001/04/26 08:15:58 robertj
178 * Fixed problem with ASN compile of single constraints on enumerations.
180 * Revision 1.39 2001/04/23 05:46:06 robertj
181 * Fixed problem with unconstrained PASN_NumericString coding in 8 bits
182 * instead of 4, thanks Chew Kuan.
184 * Revision 1.38 2001/04/23 04:40:14 robertj
185 * Added ASN standard types GeneralizedTime and UTCTime
187 * Revision 1.37 2001/04/12 03:26:59 robertj
188 * Fixed PASN_Boolean cosntructor to be compatible with usage in ASN parser.
189 * Changed all PASN_xxx types so constructor can take real type as only
190 * parameter. eg PASN_OctetString s = "fred";
191 * Changed block encode/decode so does not do a ByteAlign() if zero
192 * length, required for interoperability even though spec implies otherwise..
194 * Revision 1.36 2001/01/24 04:37:07 robertj
195 * Added more bulletproofing to ASN structures to obey constraints.
197 * Revision 1.35 2001/01/03 01:20:13 robertj
198 * Fixed error in BlockEncode, should ByteAlign() even on zero length strings.
200 * Revision 1.34 2000/10/26 11:09:16 robertj
201 * More bullet proofing of PER decoder, changed bit type to be unsigned.
203 * Revision 1.33 2000/10/26 01:29:32 robertj
204 * Fixed MSVC warning.
206 * Revision 1.32 2000/10/25 04:05:38 robertj
207 * More bullet proofing of PER decoder.
209 * Revision 1.31 2000/09/29 04:11:51 robertj
210 * Fixed possible out of range memory access, thanks Petr Parýzek <paryzek@wo.cz>
212 * Revision 1.30 2000/02/29 06:32:12 robertj
213 * Added ability to remove optional field in sequence, thanks Dave Harvey.
215 * Revision 1.29 2000/01/20 06:22:22 robertj
216 * Fixed boundary condition error for constrained integer encoding (values 1, 256 etc)
218 * Revision 1.28 1999/11/22 23:15:43 robertj
219 * Fixed bug in PASN_Choice::Compare(), should make sure choices are the same before comparing.
221 * Revision 1.27 1999/08/19 15:43:07 robertj
222 * Fixed incorrect size of OID if zero length encoded.
224 * Revision 1.26 1999/08/09 13:02:45 robertj
225 * dded ASN compiler #defines for backward support of pre GCC 2.9 compilers.
226 * Added ASN compiler #defines to reduce its memory footprint.
228 * Revision 1.25 1999/08/08 15:45:59 robertj
229 * Fixed incorrect encoding of unknown extensions.
231 * Revision 1.24 1999/08/05 00:44:28 robertj
232 * Fixed PER encoding problems for large integer values.
234 * Revision 1.23 1999/07/22 06:48:54 robertj
235 * Added comparison operation to base ASN classes and compiled ASN code.
236 * Added support for ANY type in ASN parser.
238 * Revision 1.22 1999/07/08 08:39:12 robertj
239 * Fixed bug when assigning negative number ot cosntrained PASN_Integer
241 * Revision 1.21 1999/06/30 08:58:12 robertj
242 * Fixed bug in encoding/decoding OID greater than 2.39
244 * Revision 1.20 1999/06/17 13:27:09 robertj
245 * Fixed bug causing crashes on pass through of unknown extensions.
247 * Revision 1.19 1999/06/07 00:31:25 robertj
248 * Fixed signed/unsigned problem with number of unknown extensions check.
250 * Revision 1.18 1999/04/26 05:58:48 craigs
251 * Fixed problems with encoding of extensions
253 * Revision 1.17 1999/03/09 08:12:38 robertj
254 * Fixed problem with closing a steam encoding twice.
256 * Revision 1.16 1999/01/16 01:28:25 robertj
257 * Fixed problems with reading stream multiple times.
259 * Revision 1.15 1998/11/30 04:50:44 robertj
260 * New directory structure
262 * Revision 1.14 1998/10/22 04:33:11 robertj
263 * Fixed bug in constrained strings and PER, incorrect order of character set.
265 * Revision 1.13 1998/09/23 06:21:49 robertj
266 * Added open source copyright license.
268 * Revision 1.12 1998/05/26 05:29:23 robertj
269 * Workaroung for g++ iostream bug.
271 * Revision 1.11 1998/05/21 04:58:54 robertj
272 * GCC comptaibility.
274 * Revision 1.10 1998/05/21 04:26:54 robertj
275 * Fixed numerous PER problems.
277 * Revision 1.9 1998/05/11 06:01:55 robertj
278 * Why did this compile under MSC?
280 * Revision 1.8 1998/05/07 05:19:29 robertj
281 * Fixed problems with using copy constructor/assignment oeprator on PASN_Objects.
283 * Revision 1.7 1998/03/05 12:49:50 robertj
284 * MemCheck fixes.
286 * Revision 1.6 1998/02/03 06:28:27 robertj
287 * Fixed length calculation of integers in BER.
288 * Added new function to read a block with minimum number of bytes.
290 * Revision 1.5 1998/01/26 01:51:20 robertj
291 * Removed uninitialised variable warnings.
293 * Revision 1.4 1997/12/18 05:07:56 robertj
294 * Fixed bug in choice name display.
295 * Added function to get choice discriminator name.
296 * Fixed bug in encoding extensions.
298 * Revision 1.3 1997/12/11 10:36:22 robertj
299 * Support for new ASN parser.
303 #include <ptlib.h>
305 #ifdef __GNUC__
306 #pragma implementation "asner.h"
307 #endif
309 #include <ptclib/asner.h>
311 #if P_EXPAT
312 #include <ptclib/pxml.h>
313 #endif
315 #define new PNEW
318 static PINDEX MaximumArraySize = 128;
319 static PINDEX MaximumStringSize = 16*1024;
322 static PINDEX CountBits(unsigned range)
324 switch (range) {
325 case 0 :
326 return sizeof(unsigned)*8;
327 case 1:
328 return 1;
331 size_t nBits = 0;
332 while (nBits < (sizeof(unsigned)*8) && range > (unsigned)(1 << nBits))
333 nBits++;
334 return nBits;
338 ///////////////////////////////////////////////////////////////////////
340 PASN_Object::PASN_Object(unsigned theTag, TagClass theTagClass, BOOL extend)
342 extendable = extend;
344 tag = theTag;
346 if (theTagClass != DefaultTagClass)
347 tagClass = theTagClass;
348 else
349 tagClass = ContextSpecificTagClass;
353 void PASN_Object::SetTag(unsigned newTag, TagClass tagClass_)
355 tag = newTag;
356 if (tagClass_ != DefaultTagClass)
357 tagClass = tagClass_;
361 PINDEX PASN_Object::GetObjectLength() const
363 PINDEX len = 1;
365 if (tag >= 31)
366 len += (CountBits(tag)+6)/7;
368 PINDEX dataLen = GetDataLength();
369 if (dataLen < 128)
370 len++;
371 else
372 len += (CountBits(dataLen)+7)/8 + 1;
374 return len + dataLen;
378 void PASN_Object::SetConstraintBounds(ConstraintType, int, unsigned)
383 void PASN_Object::SetCharacterSet(ConstraintType, const char *)
388 void PASN_Object::SetCharacterSet(ConstraintType, unsigned, unsigned)
393 PINDEX PASN_Object::GetMaximumArraySize()
395 return MaximumArraySize;
399 void PASN_Object::SetMaximumArraySize(PINDEX sz)
401 MaximumArraySize = sz;
405 PINDEX PASN_Object::GetMaximumStringSize()
407 return MaximumStringSize;
411 void PASN_Object::SetMaximumStringSize(PINDEX sz)
413 MaximumStringSize = sz;
417 ///////////////////////////////////////////////////////////////////////
419 PASN_ConstrainedObject::PASN_ConstrainedObject(unsigned tag, TagClass tagClass)
420 : PASN_Object(tag, tagClass)
422 constraint = Unconstrained;
423 lowerLimit = 0;
424 upperLimit = UINT_MAX;
428 void PASN_ConstrainedObject::SetConstraintBounds(ConstraintType ctype,
429 int lower, unsigned upper)
431 constraint = ctype;
432 if (constraint == Unconstrained) {
433 lower = 0;
434 upper = UINT_MAX;
437 extendable = ctype == ExtendableConstraint;
438 PAssert((lower >= 0 || upper < 0x7fffffff) &&
439 (lower < 0 || (unsigned)lower <= upper), PInvalidParameter);
440 lowerLimit = lower;
441 upperLimit = upper;
445 ///////////////////////////////////////////////////////////////////////
447 PASN_Null::PASN_Null(unsigned tag, TagClass tagClass)
448 : PASN_Object(tag, tagClass)
453 PObject::Comparison PASN_Null::Compare(const PObject & obj) const
455 PAssert(PIsDescendant(&obj, PASN_Null), PInvalidCast);
456 return EqualTo;
460 PObject * PASN_Null::Clone() const
462 PAssert(IsClass(PASN_Null::Class()), PInvalidCast);
463 return new PASN_Null(*this);
467 void PASN_Null::PrintOn(ostream & strm) const
469 strm << "<<null>>";
473 PString PASN_Null::GetTypeAsString() const
475 return "Null";
479 PINDEX PASN_Null::GetDataLength() const
481 return 0;
485 BOOL PASN_Null::Decode(PASN_Stream & strm)
487 return strm.NullDecode(*this);
491 void PASN_Null::Encode(PASN_Stream & strm) const
493 strm.NullEncode(*this);
497 ///////////////////////////////////////////////////////////////////////
499 PASN_Boolean::PASN_Boolean(BOOL val)
500 : PASN_Object(UniversalBoolean, UniversalTagClass)
502 value = val;
506 PASN_Boolean::PASN_Boolean(unsigned tag, TagClass tagClass, BOOL val)
507 : PASN_Object(tag, tagClass)
509 value = val;
513 PObject::Comparison PASN_Boolean::Compare(const PObject & obj) const
515 PAssert(PIsDescendant(&obj, PASN_Boolean), PInvalidCast);
516 return value == ((const PASN_Boolean &)obj).value ? EqualTo : GreaterThan;
520 PObject * PASN_Boolean::Clone() const
522 PAssert(IsClass(PASN_Boolean::Class()), PInvalidCast);
523 return new PASN_Boolean(*this);
527 void PASN_Boolean::PrintOn(ostream & strm) const
529 if (value)
530 strm << "TRUE";
531 else
532 strm << "FALSE";
536 PString PASN_Boolean::GetTypeAsString() const
538 return "Boolean";
542 PINDEX PASN_Boolean::GetDataLength() const
544 return 1;
548 BOOL PASN_Boolean::Decode(PASN_Stream & strm)
550 return strm.BooleanDecode(*this);
554 void PASN_Boolean::Encode(PASN_Stream & strm) const
556 strm.BooleanEncode(*this);
560 ///////////////////////////////////////////////////////////////////////
562 PASN_Integer::PASN_Integer(unsigned val)
563 : PASN_ConstrainedObject(UniversalInteger, UniversalTagClass)
565 value = val;
569 PASN_Integer::PASN_Integer(unsigned tag, TagClass tagClass, unsigned val)
570 : PASN_ConstrainedObject(tag, tagClass)
572 value = val;
576 BOOL PASN_Integer::IsUnsigned() const
578 return constraint != Unconstrained && lowerLimit >= 0;
582 PASN_Integer & PASN_Integer::operator=(unsigned val)
584 if (constraint == Unconstrained)
585 value = val;
586 else if (lowerLimit >= 0) { // Is unsigned integer
587 if (val < (unsigned)lowerLimit)
588 value = lowerLimit;
589 else if (val > upperLimit)
590 value = upperLimit;
591 else
592 value = val;
594 else {
595 int ival = (int)val;
596 if (ival < lowerLimit)
597 value = lowerLimit;
598 else if (upperLimit < INT_MAX && ival > (int)upperLimit)
599 value = upperLimit;
600 else
601 value = val;
604 return *this;
608 PObject::Comparison PASN_Integer::Compare(const PObject & obj) const
610 PAssert(PIsDescendant(&obj, PASN_Integer), PInvalidCast);
611 const PASN_Integer & other = (const PASN_Integer &)obj;
613 if (IsUnsigned()) {
614 if (value < other.value)
615 return LessThan;
616 if (value > other.value)
617 return GreaterThan;
619 else {
620 if ((int)value < (int)other.value)
621 return LessThan;
622 if ((int)value > (int)other.value)
623 return GreaterThan;
625 return EqualTo;
629 PObject * PASN_Integer::Clone() const
631 PAssert(IsClass(PASN_Integer::Class()), PInvalidCast);
632 return new PASN_Integer(*this);
636 void PASN_Integer::PrintOn(ostream & strm) const
638 if (constraint == Unconstrained || lowerLimit < 0)
639 strm << (int)value;
640 else
641 strm << value;
645 void PASN_Integer::SetConstraintBounds(ConstraintType type, int lower, unsigned upper)
647 PASN_ConstrainedObject::SetConstraintBounds(type, lower, upper);
648 operator=(value);
652 PString PASN_Integer::GetTypeAsString() const
654 return "Integer";
658 static PINDEX GetIntegerDataLength(int value)
660 // create a mask which is the top nine bits of a DWORD, or 0xFF800000
661 // on a big endian machine
662 int shift = (sizeof(value)-1)*8-1;
664 // remove all sequences of nine 0's or 1's at the start of the value
665 while (shift > 0 && ((value >> shift)&0x1ff) == (value < 0 ? 0x1ff : 0))
666 shift -= 8;
668 return (shift+9)/8;
672 PINDEX PASN_Integer::GetDataLength() const
674 return GetIntegerDataLength(value);
678 BOOL PASN_Integer::Decode(PASN_Stream & strm)
680 return strm.IntegerDecode(*this);
684 void PASN_Integer::Encode(PASN_Stream & strm) const
686 strm.IntegerEncode(*this);
690 ///////////////////////////////////////////////////////////////////////
692 PASN_Enumeration::PASN_Enumeration(unsigned val)
693 : PASN_Object(UniversalEnumeration, UniversalTagClass, FALSE)
695 value = val;
696 maxEnumValue = P_MAX_INDEX;
700 PASN_Enumeration::PASN_Enumeration(unsigned tag, TagClass tagClass,
701 unsigned maxEnum, BOOL extend,
702 unsigned val)
703 : PASN_Object(tag, tagClass, extend)
705 value = val;
706 maxEnumValue = maxEnum;
710 static POrdinalToString BuildNamesDict(const PString & nameSpec)
712 POrdinalToString names;
714 PStringArray nameList = nameSpec.Tokenise(' ', FALSE);
716 int num = 0;
717 for (PINDEX i = 0; i < nameList.GetSize(); i++) {
718 const PString & thisName = nameList[i];
719 if (!thisName) {
720 PINDEX equalPos = thisName.Find('=');
721 if (equalPos != P_MAX_INDEX)
722 num = (int)thisName.Mid(equalPos+1).AsInteger();
723 names.SetAt(POrdinalKey(num), thisName.Left(equalPos));
724 num++;
728 return names;
732 PASN_Enumeration::PASN_Enumeration(unsigned tag, TagClass tagClass,
733 unsigned maxEnum, BOOL extend,
734 const PString & nameSpec,
735 unsigned val)
736 : PASN_Object(tag, tagClass, extend),
737 names(BuildNamesDict(nameSpec))
739 maxEnumValue = maxEnum;
741 PAssert(val <= maxEnum, PInvalidParameter);
742 value = val;
746 PObject::Comparison PASN_Enumeration::Compare(const PObject & obj) const
748 PAssert(PIsDescendant(&obj, PASN_Enumeration), PInvalidCast);
749 const PASN_Enumeration & other = (const PASN_Enumeration &)obj;
751 if (value < other.value)
752 return LessThan;
754 if (value > other.value)
755 return GreaterThan;
757 return EqualTo;
761 PObject * PASN_Enumeration::Clone() const
763 PAssert(IsClass(PASN_Enumeration::Class()), PInvalidCast);
764 return new PASN_Enumeration(*this);
768 void PASN_Enumeration::PrintOn(ostream & strm) const
770 if (names.Contains(value))
771 strm << names[value];
772 else
773 strm << '<' << value << '>';
777 PString PASN_Enumeration::GetTypeAsString() const
779 return "Enumeration";
783 PINDEX PASN_Enumeration::GetDataLength() const
785 return GetIntegerDataLength(value);
789 BOOL PASN_Enumeration::Decode(PASN_Stream & strm)
791 return strm.EnumerationDecode(*this);
795 void PASN_Enumeration::Encode(PASN_Stream & strm) const
797 strm.EnumerationEncode(*this);
801 ///////////////////////////////////////////////////////////////////////
803 PASN_Real::PASN_Real(double val)
804 : PASN_Object(UniversalReal, UniversalTagClass)
806 value = val;
810 PASN_Real::PASN_Real(unsigned tag, TagClass tagClass, double val)
811 : PASN_Object(tag, tagClass)
813 value = val;
817 PObject::Comparison PASN_Real::Compare(const PObject & obj) const
819 PAssert(PIsDescendant(&obj, PASN_Real), PInvalidCast);
820 const PASN_Real & other = (const PASN_Real &)obj;
822 if (value < other.value)
823 return LessThan;
825 if (value > other.value)
826 return GreaterThan;
828 return EqualTo;
832 PObject * PASN_Real::Clone() const
834 PAssert(IsClass(PASN_Real::Class()), PInvalidCast);
835 return new PASN_Real(*this);
839 void PASN_Real::PrintOn(ostream & strm) const
841 strm << value;
845 PString PASN_Real::GetTypeAsString() const
847 return "Real";
851 PINDEX PASN_Real::GetDataLength() const
853 PAssertAlways(PUnimplementedFunction);
854 return 0;
858 BOOL PASN_Real::Decode(PASN_Stream & strm)
860 return strm.RealDecode(*this);
864 void PASN_Real::Encode(PASN_Stream & strm) const
866 strm.RealEncode(*this);
870 ///////////////////////////////////////////////////////////////////////
872 PASN_ObjectId::PASN_ObjectId(const char * dotstr)
873 : PASN_Object(UniversalObjectId, UniversalTagClass)
875 if (dotstr != NULL)
876 SetValue(dotstr);
880 PASN_ObjectId::PASN_ObjectId(unsigned tag, TagClass tagClass)
881 : PASN_Object(tag, tagClass)
886 PASN_ObjectId::PASN_ObjectId(const PASN_ObjectId & other)
887 : PASN_Object(other),
888 value(other.value, other.GetSize())
893 PASN_ObjectId & PASN_ObjectId::operator=(const PASN_ObjectId & other)
895 PASN_Object::operator=(other);
896 value = PUnsignedArray(other.value, other.GetSize());
897 return *this;
901 PASN_ObjectId & PASN_ObjectId::operator=(const char * dotstr)
903 if (dotstr != NULL)
904 SetValue(dotstr);
905 else
906 value.SetSize(0);
907 return *this;
911 PASN_ObjectId & PASN_ObjectId::operator=(const PString & dotstr)
913 SetValue(dotstr);
914 return *this;
918 PASN_ObjectId & PASN_ObjectId::operator=(const PUnsignedArray & numbers)
920 SetValue(numbers);
921 return *this;
925 void PASN_ObjectId::SetValue(const PString & dotstr)
927 PStringArray parts = dotstr.Tokenise('.');
928 value.SetSize(parts.GetSize());
929 for (PINDEX i = 0; i < parts.GetSize(); i++)
930 value[i] = parts[i].AsUnsigned();
934 void PASN_ObjectId::SetValue(const unsigned * numbers, PINDEX size)
936 value = PUnsignedArray(numbers, size);
940 bool PASN_ObjectId::operator==(const char * dotstr) const
942 PASN_ObjectId id;
943 id.SetValue(dotstr);
944 return *this == id;
948 PObject::Comparison PASN_ObjectId::Compare(const PObject & obj) const
950 PAssert(PIsDescendant(&obj, PASN_ObjectId), PInvalidCast);
951 const PASN_ObjectId & other = (const PASN_ObjectId &)obj;
952 return value.Compare(other.value);
956 PObject * PASN_ObjectId::Clone() const
958 PAssert(IsClass(PASN_ObjectId::Class()), PInvalidCast);
959 return new PASN_ObjectId(*this);
963 void PASN_ObjectId::PrintOn(ostream & strm) const
965 for (PINDEX i = 0; i < value.GetSize(); i++) {
966 strm << (unsigned)value[i];
967 if (i < value.GetSize()-1)
968 strm << '.';
973 PString PASN_ObjectId::AsString() const
975 PStringStream s;
976 PrintOn(s);
977 return s;
981 PString PASN_ObjectId::GetTypeAsString() const
983 return "Object ID";
987 BOOL PASN_ObjectId::CommonDecode(PASN_Stream & strm, unsigned dataLen)
989 value.SetSize(0);
991 // handle zero length strings correctly
992 if (dataLen == 0)
993 return TRUE;
995 unsigned subId;
997 // start at the second identifier in the buffer, because we will later
998 // expand the first number into the first two IDs
999 PINDEX i = 1;
1000 while (dataLen > 0) {
1001 unsigned byte;
1002 subId = 0;
1003 do { /* shift and add in low order 7 bits */
1004 if (strm.IsAtEnd())
1005 return FALSE;
1006 byte = strm.ByteDecode();
1007 subId = (subId << 7) + (byte & 0x7f);
1008 dataLen--;
1009 } while ((byte & 0x80) != 0);
1010 value.SetAt(i++, subId);
1014 * The first two subidentifiers are encoded into the first component
1015 * with the value (X * 40) + Y, where:
1016 * X is the value of the first subidentifier.
1017 * Y is the value of the second subidentifier.
1019 subId = value[1];
1020 if (subId < 40) {
1021 value[0] = 0;
1022 value[1] = subId;
1024 else if (subId < 80) {
1025 value[0] = 1;
1026 value[1] = subId-40;
1028 else {
1029 value[0] = 2;
1030 value[1] = subId-80;
1033 return TRUE;
1037 void PASN_ObjectId::CommonEncode(PBYTEArray & encodecObjectId) const
1039 PINDEX length = value.GetSize();
1040 const unsigned * objId = value;
1042 if (length < 2) {
1043 // Thise case is really illegal, but we have to do SOMETHING
1044 encodecObjectId.SetSize(0);
1045 return;
1048 unsigned subId = (objId[0] * 40) + objId[1];
1049 objId += 2;
1051 PINDEX outputPosition = 0;
1053 while (--length > 0) {
1054 if (subId < 128)
1055 encodecObjectId[outputPosition++] = (BYTE)subId;
1056 else {
1057 unsigned mask = 0x7F; /* handle subid == 0 case */
1058 int bits = 0;
1060 /* testmask *MUST* !!!! be of an unsigned type */
1061 unsigned testmask = 0x7F;
1062 int testbits = 0;
1063 while (testmask != 0) {
1064 if (subId & testmask) { /* if any bits set */
1065 mask = testmask;
1066 bits = testbits;
1068 testmask <<= 7;
1069 testbits += 7;
1072 /* mask can't be zero here */
1073 while (mask != 0x7F) {
1074 /* fix a mask that got truncated above */
1075 if (mask == 0x1E00000)
1076 mask = 0xFE00000;
1078 encodecObjectId[outputPosition++] = (BYTE)(((subId & mask) >> bits) | 0x80);
1080 mask >>= 7;
1081 bits -= 7;
1084 encodecObjectId[outputPosition++] = (BYTE)(subId & mask);
1087 if (length > 1)
1088 subId = *objId++;
1093 PINDEX PASN_ObjectId::GetDataLength() const
1095 PBYTEArray dummy;
1096 CommonEncode(dummy);
1097 return dummy.GetSize();
1101 BOOL PASN_ObjectId::Decode(PASN_Stream & strm)
1103 return strm.ObjectIdDecode(*this);
1107 void PASN_ObjectId::Encode(PASN_Stream & strm) const
1109 strm.ObjectIdEncode(*this);
1113 ///////////////////////////////////////////////////////////////////////
1115 PASN_BitString::PASN_BitString(unsigned nBits, const BYTE * buf)
1116 : PASN_ConstrainedObject(UniversalBitString, UniversalTagClass),
1117 totalBits(nBits),
1118 bitData((totalBits+7)/8)
1120 if (buf != NULL)
1121 memcpy(bitData.GetPointer(), buf, bitData.GetSize());
1125 PASN_BitString::PASN_BitString(unsigned tag, TagClass tagClass, unsigned nBits)
1126 : PASN_ConstrainedObject(tag, tagClass),
1127 totalBits(nBits),
1128 bitData((totalBits+7)/8)
1133 PASN_BitString::PASN_BitString(const PASN_BitString & other)
1134 : PASN_ConstrainedObject(other),
1135 bitData(other.bitData, other.bitData.GetSize())
1137 totalBits = other.totalBits;
1141 PASN_BitString & PASN_BitString::operator=(const PASN_BitString & other)
1143 PASN_ConstrainedObject::operator=(other);
1144 totalBits = other.totalBits;
1145 bitData = PBYTEArray(other.bitData, other.bitData.GetSize());
1146 return *this;
1150 void PASN_BitString::SetData(unsigned nBits, const PBYTEArray & bytes)
1152 PAssert((PINDEX)nBits < MaximumStringSize, PInvalidParameter);
1154 bitData = bytes;
1155 SetSize(nBits);
1159 void PASN_BitString::SetData(unsigned nBits, const BYTE * buf, PINDEX size)
1161 PAssert((PINDEX)nBits < MaximumStringSize, PInvalidParameter);
1163 if (size == 0)
1164 size = (nBits+7)/8;
1165 memcpy(bitData.GetPointer(size), buf, size);
1166 SetSize(nBits);
1170 BOOL PASN_BitString::SetSize(unsigned nBits)
1172 if ((PINDEX)nBits > MaximumStringSize)
1173 return FALSE;
1175 if (constraint == Unconstrained)
1176 totalBits = nBits;
1177 else if (totalBits < (unsigned)lowerLimit)
1178 totalBits = lowerLimit;
1179 else if ((unsigned)totalBits > upperLimit)
1180 totalBits = upperLimit;
1181 else
1182 totalBits = nBits;
1183 return bitData.SetSize((totalBits+7)/8);
1187 bool PASN_BitString::operator[](PINDEX bit) const
1189 if ((unsigned)bit < totalBits)
1190 return (bitData[bit>>3] & (1 << (7 - (bit&7)))) != 0;
1191 return FALSE;
1195 void PASN_BitString::Set(unsigned bit)
1197 if (bit < totalBits)
1198 bitData[(PINDEX)(bit>>3)] |= 1 << (7 - (bit&7));
1202 void PASN_BitString::Clear(unsigned bit)
1204 if (bit < totalBits)
1205 bitData[(PINDEX)(bit>>3)] &= ~(1 << (7 - (bit&7)));
1209 void PASN_BitString::Invert(unsigned bit)
1211 if (bit < totalBits)
1212 bitData[(PINDEX)(bit>>3)] ^= 1 << (7 - (bit&7));
1216 PObject::Comparison PASN_BitString::Compare(const PObject & obj) const
1218 PAssert(PIsDescendant(&obj, PASN_BitString), PInvalidCast);
1219 const PASN_BitString & other = (const PASN_BitString &)obj;
1220 if (totalBits < other.totalBits)
1221 return LessThan;
1222 if (totalBits > other.totalBits)
1223 return GreaterThan;
1224 return bitData.Compare(other.bitData);
1228 PObject * PASN_BitString::Clone() const
1230 PAssert(IsClass(PASN_BitString::Class()), PInvalidCast);
1231 return new PASN_BitString(*this);
1235 void PASN_BitString::PrintOn(ostream & strm) const
1237 int indent = strm.precision() + 2;
1238 _Ios_Fmtflags flags = strm.flags();
1240 if (totalBits > 128)
1241 strm << "Hex {\n"
1242 << hex << setfill('0') << resetiosflags(ios::floatfield) << setiosflags(ios::fixed)
1243 << setw(16) << setprecision(indent) << bitData
1244 << dec << setfill(' ') << resetiosflags(ios::floatfield)
1245 << setw(indent-1) << "}";
1246 else if (totalBits > 32)
1247 strm << "Hex:"
1248 << hex << setfill('0') << resetiosflags(ios::floatfield) << setiosflags(ios::fixed)
1249 << setprecision(2) << setw(16) << bitData
1250 << dec << setfill(' ') << resetiosflags(ios::floatfield);
1251 else {
1252 BYTE mask = 0x80;
1253 PINDEX offset = 0;
1254 for (unsigned i = 0; i < totalBits; i++) {
1255 strm << ((bitData[offset]&mask) != 0 ? '1' : '0');
1256 mask >>= 1;
1257 if (mask == 0) {
1258 mask = 0x80;
1259 offset++;
1264 strm.flags(flags);
1268 void PASN_BitString::SetConstraintBounds(ConstraintType type, int lower, unsigned upper)
1270 PAssert(lower >= 0, PInvalidParameter);
1271 PASN_ConstrainedObject::SetConstraintBounds(type, lower, upper);
1272 SetSize(GetSize());
1276 PString PASN_BitString::GetTypeAsString() const
1278 return "Bit String";
1282 PINDEX PASN_BitString::GetDataLength() const
1284 return (totalBits+7)/8 + 1;
1288 BOOL PASN_BitString::Decode(PASN_Stream & strm)
1290 return strm.BitStringDecode(*this);
1294 void PASN_BitString::Encode(PASN_Stream & strm) const
1296 strm.BitStringEncode(*this);
1300 ///////////////////////////////////////////////////////////////////////
1302 PASN_OctetString::PASN_OctetString(const char * str, PINDEX size)
1303 : PASN_ConstrainedObject(UniversalOctetString, UniversalTagClass)
1305 if (str != NULL) {
1306 if (size == 0)
1307 size = ::strlen(str);
1308 SetValue((const BYTE *)str, size);
1313 PASN_OctetString::PASN_OctetString(unsigned tag, TagClass tagClass)
1314 : PASN_ConstrainedObject(tag, tagClass)
1319 PASN_OctetString::PASN_OctetString(const PASN_OctetString & other)
1320 : PASN_ConstrainedObject(other),
1321 value(other.value, other.GetSize())
1326 PASN_OctetString & PASN_OctetString::operator=(const PASN_OctetString & other)
1328 PASN_ConstrainedObject::operator=(other);
1329 value = PBYTEArray(other.value, other.GetSize());
1330 return *this;
1334 PASN_OctetString & PASN_OctetString::operator=(const char * str)
1336 if (str == NULL)
1337 value.SetSize(lowerLimit);
1338 else
1339 SetValue((const BYTE *)str, strlen(str));
1340 return *this;
1344 PASN_OctetString & PASN_OctetString::operator=(const PString & str)
1346 SetValue((const BYTE *)(const char *)str, str.GetSize()-1);
1347 return *this;
1351 PASN_OctetString & PASN_OctetString::operator=(const PBYTEArray & arr)
1353 PINDEX len = arr.GetSize();
1354 if ((unsigned)len > upperLimit || (int)len < lowerLimit)
1355 SetValue(arr, len);
1356 else
1357 value = arr;
1358 return *this;
1362 void PASN_OctetString::SetValue(const BYTE * data, PINDEX len)
1364 if ((unsigned)len > upperLimit)
1365 len = upperLimit;
1366 if (SetSize((int)len < lowerLimit ? lowerLimit : len))
1367 memcpy(value.GetPointer(), data, len);
1371 PString PASN_OctetString::AsString() const
1373 if (value.IsEmpty())
1374 return PString();
1375 return PString((const char *)(const BYTE *)value, value.GetSize());
1379 PObject::Comparison PASN_OctetString::Compare(const PObject & obj) const
1381 PAssert(PIsDescendant(&obj, PASN_OctetString), PInvalidCast);
1382 const PASN_OctetString & other = (const PASN_OctetString &)obj;
1383 return value.Compare(other.value);
1387 PObject * PASN_OctetString::Clone() const
1389 PAssert(IsClass(PASN_OctetString::Class()), PInvalidCast);
1390 return new PASN_OctetString(*this);
1394 void PASN_OctetString::PrintOn(ostream & strm) const
1396 int indent = strm.precision() + 2;
1397 _Ios_Fmtflags flags = strm.flags();
1399 strm << ' ' << value.GetSize() << " octets {\n"
1400 << hex << setfill('0') << resetiosflags(ios::floatfield)
1401 << setprecision(indent) << setw(16);
1403 if (value.GetSize() <= 32 || (flags&ios::floatfield) != ios::fixed)
1404 strm << value << '\n';
1405 else {
1406 PBYTEArray truncatedArray(value, 32);
1407 strm << truncatedArray << '\n'
1408 << setfill(' ')
1409 << setw(indent+4) << "...\n";
1412 strm << dec << setfill(' ')
1413 << setw(indent-1) << "}";
1415 strm.flags(flags);
1419 void PASN_OctetString::SetConstraintBounds(ConstraintType type, int lower, unsigned upper)
1421 PAssert(lower >= 0, PInvalidParameter);
1422 PASN_ConstrainedObject::SetConstraintBounds(type, lower, upper);
1423 SetSize(GetSize());
1427 PString PASN_OctetString::GetTypeAsString() const
1429 return "Octet String";
1433 PINDEX PASN_OctetString::GetDataLength() const
1435 return value.GetSize();
1439 BOOL PASN_OctetString::SetSize(PINDEX newSize)
1441 if (newSize > MaximumStringSize)
1442 return FALSE;
1444 if (constraint != Unconstrained) {
1445 if (newSize < (PINDEX)lowerLimit)
1446 newSize = lowerLimit;
1447 else if ((unsigned)newSize > upperLimit)
1448 newSize = upperLimit;
1451 return value.SetSize(newSize);
1455 BOOL PASN_OctetString::Decode(PASN_Stream & strm)
1457 return strm.OctetStringDecode(*this);
1461 void PASN_OctetString::Encode(PASN_Stream & strm) const
1463 strm.OctetStringEncode(*this);
1466 ///////////////////////////////////////////////////////////////////////
1468 PASN_ConstrainedString::PASN_ConstrainedString(const char * canonical, PINDEX size,
1469 unsigned tag, TagClass tagClass)
1470 : PASN_ConstrainedObject(tag, tagClass)
1472 canonicalSet = canonical;
1473 canonicalSetSize = size;
1474 canonicalSetBits = CountBits(size);
1475 SetCharacterSet(canonicalSet, canonicalSetSize, Unconstrained);
1479 PASN_ConstrainedString & PASN_ConstrainedString::operator=(const char * str)
1481 if (str == NULL)
1482 str = "";
1484 PStringStream newValue;
1486 PINDEX len = strlen(str);
1488 // Can't copy any more characters than the upper constraint
1489 if ((unsigned)len > upperLimit)
1490 len = upperLimit;
1492 // Now copy individual characters, if they are in character set constraint
1493 for (PINDEX i = 0; i < len; i++) {
1494 PINDEX sz = characterSet.GetSize();
1495 if (sz == 0 || memchr(characterSet, str[i], sz) != NULL)
1496 newValue << str[i];
1499 // Make sure string meets minimum length constraint
1500 while ((int)len < lowerLimit) {
1501 newValue << characterSet[0];
1502 len++;
1505 value = newValue;
1506 value.MakeMinimumSize();
1507 return *this;
1511 void PASN_ConstrainedString::SetCharacterSet(ConstraintType ctype, const char * set)
1513 SetCharacterSet(set, strlen(set), ctype);
1517 void PASN_ConstrainedString::SetCharacterSet(ConstraintType ctype, unsigned firstChar, unsigned lastChar)
1519 char buffer[256];
1520 for (unsigned i = firstChar; i < lastChar; i++)
1521 buffer[i] = (char)i;
1522 SetCharacterSet(buffer, lastChar - firstChar + 1, ctype);
1526 void PASN_ConstrainedString::SetCharacterSet(const char * set, PINDEX setSize, ConstraintType ctype)
1528 if (ctype == Unconstrained) {
1529 characterSet.SetSize(canonicalSetSize);
1530 memcpy(characterSet.GetPointer(), canonicalSet, canonicalSetSize);
1532 else {
1533 characterSet.SetSize(setSize);
1534 PINDEX count = 0;
1535 for (PINDEX i = 0; i < canonicalSetSize; i++) {
1536 if (memchr(set, canonicalSet[i], setSize) != NULL)
1537 characterSet[count++] = canonicalSet[i];
1539 PAssert(count > 0, PInvalidParameter);
1540 characterSet.SetSize(count);
1543 charSetUnalignedBits = CountBits(characterSet.GetSize());
1545 charSetAlignedBits = 1;
1546 while (charSetUnalignedBits > charSetAlignedBits)
1547 charSetAlignedBits <<= 1;
1549 operator=((const char *)value);
1553 PObject::Comparison PASN_ConstrainedString::Compare(const PObject & obj) const
1555 PAssert(PIsDescendant(&obj, PASN_ConstrainedString), PInvalidCast);
1556 const PASN_ConstrainedString & other = (const PASN_ConstrainedString &)obj;
1557 return value.Compare(other.value);
1561 void PASN_ConstrainedString::PrintOn(ostream & strm) const
1563 strm << value.ToLiteral();
1567 void PASN_ConstrainedString::SetConstraintBounds(ConstraintType type,
1568 int lower, unsigned upper)
1570 PAssert(lower >= 0, PInvalidParameter);
1571 PASN_ConstrainedObject::SetConstraintBounds(type, lower, upper);
1572 if (constraint != Unconstrained) {
1573 if (value.GetSize() < (PINDEX)lowerLimit)
1574 value.SetSize(lowerLimit);
1575 else if ((unsigned)value.GetSize() > upperLimit)
1576 value.SetSize(upperLimit);
1581 PINDEX PASN_ConstrainedString::GetDataLength() const
1583 return value.GetSize()-1;
1587 BOOL PASN_ConstrainedString::Decode(PASN_Stream & strm)
1589 return strm.ConstrainedStringDecode(*this);
1593 void PASN_ConstrainedString::Encode(PASN_Stream & strm) const
1595 strm.ConstrainedStringEncode(*this);
1599 #define DEFINE_STRING_CLASS(name, set) \
1600 static const char name##StringSet[] = set; \
1601 PASN_##name##String::PASN_##name##String(const char * str) \
1602 : PASN_ConstrainedString(name##StringSet, sizeof(name##StringSet)-1, \
1603 Universal##name##String, UniversalTagClass) \
1604 { PASN_ConstrainedString::SetValue(str); } \
1605 PASN_##name##String::PASN_##name##String(unsigned tag, TagClass tagClass) \
1606 : PASN_ConstrainedString(name##StringSet, sizeof(name##StringSet)-1, tag, tagClass) \
1607 { } \
1608 PASN_##name##String & PASN_##name##String::operator=(const char * str) \
1609 { PASN_ConstrainedString::SetValue(str); return *this; } \
1610 PASN_##name##String & PASN_##name##String::operator=(const PString & str) \
1611 { PASN_ConstrainedString::SetValue(str); return *this; } \
1612 PObject * PASN_##name##String::Clone() const \
1613 { PAssert(IsClass(PASN_##name##String::Class()), PInvalidCast); \
1614 return new PASN_##name##String(*this); } \
1615 PString PASN_##name##String::GetTypeAsString() const \
1616 { return #name " String"; }
1618 DEFINE_STRING_CLASS(Numeric, " 0123456789")
1619 DEFINE_STRING_CLASS(Printable, " '()+,-./0123456789:=?"
1620 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1621 "abcdefghijklmnopqrstuvwxyz")
1622 DEFINE_STRING_CLASS(Visible, " !\"#$%&'()*+,-./0123456789:;<=>?"
1623 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
1624 "`abcdefghijklmnopqrstuvwxyz{|}~")
1625 DEFINE_STRING_CLASS(IA5, "\000\001\002\003\004\005\006\007"
1626 "\010\011\012\013\014\015\016\017"
1627 "\020\021\022\023\024\025\026\027"
1628 "\030\031\032\033\034\035\036\037"
1629 " !\"#$%&'()*+,-./0123456789:;<=>?"
1630 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
1631 "`abcdefghijklmnopqrstuvwxyz{|}~\177")
1632 DEFINE_STRING_CLASS(General, "\000\001\002\003\004\005\006\007"
1633 "\010\011\012\013\014\015\016\017"
1634 "\020\021\022\023\024\025\026\027"
1635 "\030\031\032\033\034\035\036\037"
1636 " !\"#$%&'()*+,-./0123456789:;<=>?"
1637 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
1638 "`abcdefghijklmnopqrstuvwxyz{|}~\177"
1639 "\200\201\202\203\204\205\206\207"
1640 "\210\211\212\213\214\215\216\217"
1641 "\220\221\222\223\224\225\226\227"
1642 "\230\231\232\233\234\235\236\237"
1643 "\240\241\242\243\244\245\246\247"
1644 "\250\251\252\253\254\255\256\257"
1645 "\260\261\262\263\264\265\266\267"
1646 "\270\271\272\273\274\275\276\277"
1647 "\300\301\302\303\304\305\306\307"
1648 "\310\311\312\313\314\315\316\317"
1649 "\320\321\322\323\324\325\326\327"
1650 "\330\331\332\333\334\335\336\337"
1651 "\340\341\342\343\344\345\346\347"
1652 "\350\351\352\353\354\355\356\357"
1653 "\360\361\362\363\364\365\366\367"
1654 "\370\371\372\373\374\375\376\377")
1657 ///////////////////////////////////////////////////////////////////////
1659 PASN_BMPString::PASN_BMPString(const char * str)
1660 : PASN_ConstrainedObject(UniversalBMPString, UniversalTagClass)
1662 Construct();
1663 if (str != NULL)
1664 SetValue(str);
1668 PASN_BMPString::PASN_BMPString(const PWORDArray & wstr)
1669 : PASN_ConstrainedObject(UniversalBMPString, UniversalTagClass)
1671 Construct();
1672 SetValue(wstr);
1676 PASN_BMPString::PASN_BMPString(unsigned tag, TagClass tagClass)
1677 : PASN_ConstrainedObject(tag, tagClass)
1679 Construct();
1683 void PASN_BMPString::Construct()
1685 firstChar = 0;
1686 lastChar = 0xffff;
1687 charSetAlignedBits = 16;
1688 charSetUnalignedBits = 16;
1692 PASN_BMPString::PASN_BMPString(const PASN_BMPString & other)
1693 : PASN_ConstrainedObject(other),
1694 value(other.value, other.value.GetSize()),
1695 characterSet(other.characterSet)
1697 firstChar = other.firstChar;
1698 lastChar = other.lastChar;
1699 charSetAlignedBits = other.charSetAlignedBits;
1700 charSetUnalignedBits = other.charSetUnalignedBits;
1704 PASN_BMPString & PASN_BMPString::operator=(const PASN_BMPString & other)
1706 PASN_ConstrainedObject::operator=(other);
1708 value = PWORDArray(other.value, other.value.GetSize());
1709 characterSet = other.characterSet;
1710 firstChar = other.firstChar;
1711 lastChar = other.lastChar;
1712 charSetAlignedBits = other.charSetAlignedBits;
1713 charSetUnalignedBits = other.charSetUnalignedBits;
1715 return *this;
1719 BOOL PASN_BMPString::IsLegalCharacter(WORD ch)
1721 if (ch < firstChar)
1722 return FALSE;
1724 if (ch > lastChar)
1725 return FALSE;
1727 if (characterSet.IsEmpty())
1728 return TRUE;
1730 const WORD * wptr = characterSet;
1731 PINDEX count = characterSet.GetSize();
1732 while (count-- > 0) {
1733 if (*wptr == ch)
1734 return TRUE;
1735 wptr++;
1738 return FALSE;
1742 PASN_BMPString & PASN_BMPString::operator=(const PWORDArray & array)
1744 PINDEX paramSize = array.GetSize();
1746 // Can't copy any more than the upper constraint
1747 if ((unsigned)paramSize > upperLimit)
1748 paramSize = upperLimit;
1750 // Number of bytes must be at least lhe lower constraint
1751 PINDEX newSize = (int)paramSize < lowerLimit ? lowerLimit : paramSize;
1752 value.SetSize(newSize);
1754 PINDEX count = 0;
1755 for (PINDEX i = 0; i < paramSize; i++) {
1756 WORD c = array[i];
1757 if (IsLegalCharacter(c))
1758 value[count++] = c;
1761 // Pad out with the first character till required size
1762 while (count < newSize)
1763 value[count++] = firstChar;
1765 return *this;
1769 void PASN_BMPString::SetCharacterSet(ConstraintType ctype, const char * charSet)
1771 PWORDArray array(strlen(charSet));
1773 PINDEX count = 0;
1774 while (*charSet != '\0')
1775 array[count++] = (BYTE)*charSet++;
1777 SetCharacterSet(ctype, array);
1781 void PASN_BMPString::SetCharacterSet(ConstraintType ctype, const PWORDArray & charSet)
1783 if (ctype == Unconstrained) {
1784 firstChar = 0;
1785 lastChar = 0xffff;
1786 characterSet.SetSize(0);
1788 else {
1789 characterSet = charSet;
1791 charSetUnalignedBits = CountBits(lastChar - firstChar + 1);
1792 if (!charSet.IsEmpty()) {
1793 unsigned count = 0;
1794 for (PINDEX i = 0; i < charSet.GetSize(); i++) {
1795 if (characterSet[i] >= firstChar && characterSet[i] <= lastChar)
1796 count++;
1798 count = CountBits(count);
1799 if (charSetUnalignedBits > count)
1800 charSetUnalignedBits = count;
1803 charSetAlignedBits = 1;
1804 while (charSetUnalignedBits > charSetAlignedBits)
1805 charSetAlignedBits <<= 1;
1807 SetValue(value);
1812 void PASN_BMPString::SetCharacterSet(ConstraintType ctype, unsigned first, unsigned last)
1814 if (ctype != Unconstrained) {
1815 PAssert(first < 0x10000 && last < 0x10000 && last > first, PInvalidParameter);
1816 firstChar = (WORD)first;
1817 lastChar = (WORD)last;
1819 SetCharacterSet(ctype, characterSet);
1823 PObject * PASN_BMPString::Clone() const
1825 PAssert(IsClass(PASN_BMPString::Class()), PInvalidCast);
1826 return new PASN_BMPString(*this);
1830 PObject::Comparison PASN_BMPString::Compare(const PObject & obj) const
1832 PAssert(PIsDescendant(&obj, PASN_BMPString), PInvalidCast);
1833 const PASN_BMPString & other = (const PASN_BMPString &)obj;
1834 return value.Compare(other.value);
1838 void PASN_BMPString::PrintOn(ostream & strm) const
1840 int indent = strm.precision() + 2;
1841 PINDEX sz = value.GetSize();
1842 strm << ' ' << sz << " characters {\n";
1843 PINDEX i = 0;
1844 while (i < sz) {
1845 strm << setw(indent) << " " << hex << setfill('0');
1846 PINDEX j;
1847 for (j = 0; j < 8; j++)
1848 if (i+j < sz)
1849 strm << setw(4) << value[i+j] << ' ';
1850 else
1851 strm << " ";
1852 strm << " ";
1853 for (j = 0; j < 8; j++) {
1854 if (i+j < sz) {
1855 WORD c = value[i+j];
1856 if (c < 128 && isprint(c))
1857 strm << (char)c;
1858 else
1859 strm << ' ';
1862 strm << dec << setfill(' ') << '\n';
1863 i += 8;
1865 strm << setw(indent-1) << "}";
1869 PString PASN_BMPString::GetTypeAsString() const
1871 return "BMP String";
1875 PINDEX PASN_BMPString::GetDataLength() const
1877 return value.GetSize()*2;
1881 BOOL PASN_BMPString::Decode(PASN_Stream & strm)
1883 return strm.BMPStringDecode(*this);
1887 void PASN_BMPString::Encode(PASN_Stream & strm) const
1889 strm.BMPStringEncode(*this);
1893 ///////////////////////////////////////////////////////////////////////
1895 PASN_GeneralisedTime & PASN_GeneralisedTime::operator=(const PTime & time)
1897 value = time.AsString("yyyyMMddhhmmss.uz");
1898 value.Replace("GMT", "Z");
1899 return *this;
1903 PTime PASN_GeneralisedTime::GetValue() const
1905 int year = value(0,3).AsInteger();
1906 int month = value(4,5).AsInteger();
1907 int day = value(6,7).AsInteger();
1908 int hour = value(8,9).AsInteger();
1909 int minute = value(10,11).AsInteger();
1910 int seconds = 0;
1911 int zonePos = 12;
1913 if (isdigit(value[12])) {
1914 seconds = value(12,13).AsInteger();
1915 if (value[14] != '.')
1916 zonePos = 14;
1917 else {
1918 zonePos = 15;
1919 while (isdigit(value[zonePos]))
1920 zonePos++;
1924 int zone = PTime::Local;
1925 switch (value[zonePos]) {
1926 case 'Z' :
1927 zone = PTime::UTC;
1928 break;
1929 case '+' :
1930 case '-' :
1931 zone = value(zonePos+1,zonePos+2).AsInteger()*60 +
1932 value(zonePos+3,zonePos+4).AsInteger();
1935 return PTime(seconds, minute, hour, day, month, year, zone);
1939 ///////////////////////////////////////////////////////////////////////
1941 PASN_UniversalTime & PASN_UniversalTime::operator=(const PTime & time)
1943 value = time.AsString("yyMMddhhmmssz");
1944 value.Replace("GMT", "Z");
1945 value.MakeMinimumSize();
1946 return *this;
1950 PTime PASN_UniversalTime::GetValue() const
1952 int year = value(0,1).AsInteger();
1953 if (year < 36)
1954 year += 2000;
1955 else
1956 year += 1900;
1958 int month = value(2,3).AsInteger();
1959 int day = value(4,5).AsInteger();
1960 int hour = value(6,7).AsInteger();
1961 int minute = value(8,9).AsInteger();
1962 int seconds = 0;
1963 int zonePos = 10;
1965 if (isdigit(value[10])) {
1966 seconds = value(10,11).AsInteger();
1967 zonePos = 12;
1970 int zone = PTime::UTC;
1971 if (value[zonePos] != 'Z')
1972 zone = value(zonePos+1,zonePos+2).AsInteger()*60 +
1973 value(zonePos+3,zonePos+4).AsInteger();
1975 return PTime(seconds, minute, hour, day, month, year, zone);
1979 ///////////////////////////////////////////////////////////////////////
1981 PASN_Choice::PASN_Choice(unsigned nChoices, BOOL extend)
1982 : PASN_Object(0, ApplicationTagClass, extend)
1984 numChoices = nChoices;
1985 choice = NULL;
1989 PASN_Choice::PASN_Choice(unsigned tag, TagClass tagClass,
1990 unsigned upper, BOOL extend)
1991 : PASN_Object(tag, tagClass, extend)
1993 numChoices = upper;
1994 choice = NULL;
1998 PASN_Choice::PASN_Choice(unsigned tag, TagClass tagClass,
1999 unsigned upper, BOOL extend, const PString & nameSpec)
2000 : PASN_Object(tag, tagClass, extend),
2001 names(BuildNamesDict(nameSpec))
2003 numChoices = upper;
2004 choice = NULL;
2008 PASN_Choice::PASN_Choice(const PASN_Choice & other)
2009 : PASN_Object(other),
2010 names(other.names)
2012 numChoices = other.numChoices;
2014 if (other.CheckCreate())
2015 choice = (PASN_Object *)other.choice->Clone();
2016 else
2017 choice = NULL;
2021 PASN_Choice & PASN_Choice::operator=(const PASN_Choice & other)
2023 if (&other == this) // Assigning to ourself, just do nothing.
2024 return *this;
2026 delete choice;
2028 PASN_Object::operator=(other);
2030 numChoices = other.numChoices;
2031 names = other.names;
2033 if (other.CheckCreate())
2034 choice = (PASN_Object *)other.choice->Clone();
2035 else
2036 choice = NULL;
2038 return *this;
2042 PASN_Choice::~PASN_Choice()
2044 delete choice;
2048 void PASN_Choice::SetTag(unsigned newTag, TagClass tagClass)
2050 PASN_Object::SetTag(newTag, tagClass);
2052 delete choice;
2054 if (CreateObject())
2055 choice->SetTag(newTag, tagClass);
2059 PString PASN_Choice::GetTagName() const
2061 if (names.Contains(tag))
2062 return names[tag];
2064 if (CheckCreate() &&
2065 PIsDescendant(choice, PASN_Choice) &&
2066 choice->GetTag() == tag &&
2067 choice->GetTagClass() == tagClass)
2068 return PString(choice->GetClass()) + "->" + ((PASN_Choice *)choice)->GetTagName();
2070 return psprintf("<%u>", tag);
2074 BOOL PASN_Choice::CheckCreate() const
2076 if (choice != NULL)
2077 return TRUE;
2079 return ((PASN_Choice *)this)->CreateObject();
2083 PASN_Object & PASN_Choice::GetObject() const
2085 PAssert(CheckCreate(), "NULL Choice");
2086 return *choice;
2090 #if defined(__GNUC__) && __GNUC__ <= 2 && __GNUC_MINOR__ < 9
2092 #define CHOICE_CAST_OPERATOR(cls) \
2093 PASN_Choice::operator cls &() const \
2095 PAssert(CheckCreate(), "Cast of NULL choice"); \
2096 PAssert(choice->IsDescendant(cls::Class()), PInvalidCast); \
2097 return *(cls *)choice; \
2100 #else
2102 #define CHOICE_CAST_OPERATOR(cls) \
2103 PASN_Choice::operator cls &() \
2105 PAssert(CheckCreate(), "Cast of NULL choice"); \
2106 PAssert(PIsDescendant(choice, cls), PInvalidCast); \
2107 return *(cls *)choice; \
2109 PASN_Choice::operator const cls &() const \
2111 PAssert(CheckCreate(), "Cast of NULL choice"); \
2112 PAssert(PIsDescendant(choice, cls), PInvalidCast); \
2113 return *(const cls *)choice; \
2116 #endif
2119 CHOICE_CAST_OPERATOR(PASN_Null)
2120 CHOICE_CAST_OPERATOR(PASN_Boolean)
2121 CHOICE_CAST_OPERATOR(PASN_Integer)
2122 CHOICE_CAST_OPERATOR(PASN_Enumeration)
2123 CHOICE_CAST_OPERATOR(PASN_Real)
2124 CHOICE_CAST_OPERATOR(PASN_ObjectId)
2125 CHOICE_CAST_OPERATOR(PASN_BitString)
2126 CHOICE_CAST_OPERATOR(PASN_OctetString)
2127 CHOICE_CAST_OPERATOR(PASN_NumericString)
2128 CHOICE_CAST_OPERATOR(PASN_PrintableString)
2129 CHOICE_CAST_OPERATOR(PASN_VisibleString)
2130 CHOICE_CAST_OPERATOR(PASN_IA5String)
2131 CHOICE_CAST_OPERATOR(PASN_GeneralString)
2132 CHOICE_CAST_OPERATOR(PASN_BMPString)
2133 CHOICE_CAST_OPERATOR(PASN_Sequence)
2136 PObject::Comparison PASN_Choice::Compare(const PObject & obj) const
2138 PAssert(PIsDescendant(&obj, PASN_Choice), PInvalidCast);
2139 const PASN_Choice & other = (const PASN_Choice &)obj;
2141 CheckCreate();
2142 other.CheckCreate();
2144 if (choice == other.choice)
2145 return EqualTo;
2147 if (choice == NULL)
2148 return LessThan;
2150 if (other.choice == NULL)
2151 return GreaterThan;
2153 if (tag < other.tag)
2154 return LessThan;
2156 if (tag > other.tag)
2157 return GreaterThan;
2159 return choice->Compare(*other.choice);
2163 void PASN_Choice::PrintOn(ostream & strm) const
2165 strm << GetTagName();
2167 if (choice != NULL)
2168 strm << ' ' << *choice;
2169 else
2170 strm << " (NULL)";
2174 PString PASN_Choice::GetTypeAsString() const
2176 return "Choice";
2180 PINDEX PASN_Choice::GetDataLength() const
2182 if (CheckCreate())
2183 return choice->GetDataLength();
2185 return 0;
2189 BOOL PASN_Choice::IsPrimitive() const
2191 if (CheckCreate())
2192 return choice->IsPrimitive();
2193 return FALSE;
2197 BOOL PASN_Choice::Decode(PASN_Stream & strm)
2199 return strm.ChoiceDecode(*this);
2203 void PASN_Choice::Encode(PASN_Stream & strm) const
2205 strm.ChoiceEncode(*this);
2209 ///////////////////////////////////////////////////////////////////////
2211 PASN_Sequence::PASN_Sequence(unsigned tag, TagClass tagClass,
2212 unsigned nOpts, BOOL extend, unsigned nExtend)
2213 : PASN_Object(tag, tagClass, extend)
2215 optionMap.SetConstraints(PASN_ConstrainedObject::FixedConstraint, nOpts);
2216 knownExtensions = nExtend;
2217 totalExtensions = 0;
2218 endBasicEncoding = 0;
2222 PASN_Sequence::PASN_Sequence(const PASN_Sequence & other)
2223 : PASN_Object(other),
2224 fields(other.fields.GetSize()),
2225 optionMap(other.optionMap),
2226 extensionMap(other.extensionMap)
2228 for (PINDEX i = 0; i < other.fields.GetSize(); i++)
2229 fields.SetAt(i, other.fields[i].Clone());
2231 knownExtensions = other.knownExtensions;
2232 totalExtensions = other.totalExtensions;
2233 endBasicEncoding = 0;
2237 PASN_Sequence & PASN_Sequence::operator=(const PASN_Sequence & other)
2239 PASN_Object::operator=(other);
2241 fields.SetSize(other.fields.GetSize());
2242 for (PINDEX i = 0; i < other.fields.GetSize(); i++)
2243 fields.SetAt(i, other.fields[i].Clone());
2245 optionMap = other.optionMap;
2246 knownExtensions = other.knownExtensions;
2247 totalExtensions = other.totalExtensions;
2248 extensionMap = other.extensionMap;
2250 return *this;
2254 BOOL PASN_Sequence::HasOptionalField(PINDEX opt) const
2256 if (opt < (PINDEX)optionMap.GetSize())
2257 return optionMap[opt];
2258 else
2259 return extensionMap[opt - optionMap.GetSize()];
2263 void PASN_Sequence::IncludeOptionalField(PINDEX opt)
2265 if (opt < (PINDEX)optionMap.GetSize())
2266 optionMap.Set(opt);
2267 else {
2268 PAssert(extendable, "Must be extendable type");
2269 opt -= optionMap.GetSize();
2270 if (opt >= (PINDEX)extensionMap.GetSize())
2271 extensionMap.SetSize(opt+1);
2272 extensionMap.Set(opt);
2277 void PASN_Sequence::RemoveOptionalField(PINDEX opt)
2279 if (opt < (PINDEX)optionMap.GetSize())
2280 optionMap.Clear(opt);
2281 else {
2282 PAssert(extendable, "Must be extendable type");
2283 opt -= optionMap.GetSize();
2284 extensionMap.Clear(opt);
2289 PObject::Comparison PASN_Sequence::Compare(const PObject & obj) const
2291 PAssert(PIsDescendant(&obj, PASN_Sequence), PInvalidCast);
2292 const PASN_Sequence & other = (const PASN_Sequence &)obj;
2293 return fields.Compare(other.fields);
2297 PObject * PASN_Sequence::Clone() const
2299 PAssert(IsClass(PASN_Sequence::Class()), PInvalidCast);
2300 return new PASN_Sequence(*this);
2304 void PASN_Sequence::PrintOn(ostream & strm) const
2306 int indent = strm.precision() + 2;
2307 strm << "{\n";
2308 for (PINDEX i = 0; i < fields.GetSize(); i++) {
2309 strm << setw(indent+6) << "field[" << i << "] <";
2310 switch (fields[i].GetTagClass()) {
2311 case UniversalTagClass :
2312 strm << "Universal";
2313 break;
2314 case ApplicationTagClass :
2315 strm << "Application";
2316 break;
2317 case ContextSpecificTagClass :
2318 strm << "ContextSpecific";
2319 break;
2320 case PrivateTagClass :
2321 strm << "Private";
2322 default :
2323 break;
2325 strm << '-' << fields[i].GetTag() << '-'
2326 << fields[i].GetTypeAsString() << "> = "
2327 << fields[i] << '\n';
2329 strm << setw(indent-1) << "}";
2333 PString PASN_Sequence::GetTypeAsString() const
2335 return "Sequence";
2339 PINDEX PASN_Sequence::GetDataLength() const
2341 PINDEX len = 0;
2342 for (PINDEX i = 0; i < fields.GetSize(); i++)
2343 len += fields[i].GetObjectLength();
2344 return len;
2348 BOOL PASN_Sequence::IsPrimitive() const
2350 return FALSE;
2354 BOOL PASN_Sequence::Decode(PASN_Stream & strm)
2356 return PreambleDecode(strm) && UnknownExtensionsDecode(strm);
2360 void PASN_Sequence::Encode(PASN_Stream & strm) const
2362 PreambleEncode(strm);
2363 UnknownExtensionsEncode(strm);
2367 BOOL PASN_Sequence::PreambleDecode(PASN_Stream & strm)
2369 return strm.SequencePreambleDecode(*this);
2373 void PASN_Sequence::PreambleEncode(PASN_Stream & strm) const
2375 strm.SequencePreambleEncode(*this);
2379 BOOL PASN_Sequence::KnownExtensionDecode(PASN_Stream & strm, PINDEX fld, PASN_Object & field)
2381 return strm.SequenceKnownDecode(*this, fld, field);
2385 void PASN_Sequence::KnownExtensionEncode(PASN_Stream & strm, PINDEX fld, const PASN_Object & field) const
2387 strm.SequenceKnownEncode(*this, fld, field);
2391 BOOL PASN_Sequence::UnknownExtensionsDecode(PASN_Stream & strm)
2393 return strm.SequenceUnknownDecode(*this);
2397 void PASN_Sequence::UnknownExtensionsEncode(PASN_Stream & strm) const
2399 strm.SequenceUnknownEncode(*this);
2403 ///////////////////////////////////////////////////////////////////////
2405 PASN_Set::PASN_Set(unsigned tag, TagClass tagClass,
2406 unsigned nOpts, BOOL extend, unsigned nExtend)
2407 : PASN_Sequence(tag, tagClass, nOpts, extend, nExtend)
2412 PObject * PASN_Set::Clone() const
2414 PAssert(IsClass(PASN_Set::Class()), PInvalidCast);
2415 return new PASN_Set(*this);
2419 PString PASN_Set::GetTypeAsString() const
2421 return "Set";
2424 ///////////////////////////////////////////////////////////////////////
2426 PASN_Array::PASN_Array(unsigned tag, TagClass tagClass)
2427 : PASN_ConstrainedObject(tag, tagClass)
2432 PASN_Array::PASN_Array(const PASN_Array & other)
2433 : PASN_ConstrainedObject(other),
2434 array(other.array.GetSize())
2436 for (PINDEX i = 0; i < other.array.GetSize(); i++)
2437 array.SetAt(i, other.array[i].Clone());
2441 PASN_Array & PASN_Array::operator=(const PASN_Array & other)
2443 PASN_ConstrainedObject::operator=(other);
2445 array.SetSize(other.array.GetSize());
2446 for (PINDEX i = 0; i < other.array.GetSize(); i++)
2447 array.SetAt(i, other.array[i].Clone());
2449 return *this;
2453 BOOL PASN_Array::SetSize(PINDEX newSize)
2455 if (newSize > MaximumArraySize)
2456 return FALSE;
2458 PINDEX originalSize = array.GetSize();
2459 if (!array.SetSize(newSize))
2460 return FALSE;
2462 for (PINDEX i = originalSize; i < newSize; i++) {
2463 PASN_Object * obj = CreateObject();
2464 if (obj == NULL)
2465 return FALSE;
2467 array.SetAt(i, obj);
2470 return TRUE;
2474 PObject::Comparison PASN_Array::Compare(const PObject & obj) const
2476 PAssert(PIsDescendant(&obj, PASN_Array), PInvalidCast);
2477 const PASN_Array & other = (const PASN_Array &)obj;
2478 return array.Compare(other.array);
2482 void PASN_Array::PrintOn(ostream & strm) const
2484 int indent = strm.precision() + 2;
2485 strm << array.GetSize() << " entries {\n";
2486 for (PINDEX i = 0; i < array.GetSize(); i++)
2487 strm << setw(indent+1) << "[" << i << "]=" << setprecision(indent) << array[i] << '\n';
2488 strm << setw(indent-1) << "}";
2492 void PASN_Array::SetConstraintBounds(ConstraintType type, int lower, unsigned upper)
2494 PAssert(lower >= 0, PInvalidParameter);
2495 PASN_ConstrainedObject::SetConstraintBounds(type, lower, upper);
2496 if (constraint != Unconstrained) {
2497 if (GetSize() < (PINDEX)lowerLimit)
2498 SetSize(lowerLimit);
2499 else if (GetSize() > (PINDEX)upperLimit)
2500 SetSize(upperLimit);
2505 PString PASN_Array::GetTypeAsString() const
2507 return "Array";
2511 PINDEX PASN_Array::GetDataLength() const
2513 PINDEX len = 0;
2514 for (PINDEX i = 0; i < array.GetSize(); i++)
2515 len += array[i].GetObjectLength();
2516 return len;
2520 BOOL PASN_Array::IsPrimitive() const
2522 return FALSE;
2526 BOOL PASN_Array::Decode(PASN_Stream & strm)
2528 return strm.ArrayDecode(*this);
2532 void PASN_Array::Encode(PASN_Stream & strm) const
2534 strm.ArrayEncode(*this);
2538 ///////////////////////////////////////////////////////////////////////
2540 PASN_Stream::PASN_Stream()
2542 Construct();
2546 PASN_Stream::PASN_Stream(const PBYTEArray & bytes)
2547 : PBYTEArray(bytes)
2549 Construct();
2553 PASN_Stream::PASN_Stream(const BYTE * buf, PINDEX size)
2554 : PBYTEArray(buf, size)
2556 Construct();
2560 void PASN_Stream::Construct()
2562 byteOffset = 0;
2563 bitOffset = 8;
2567 void PASN_Stream::PrintOn(ostream & strm) const
2569 int indent = strm.precision() + 2;
2570 strm << " size=" << GetSize()
2571 << " pos=" << byteOffset << '.' << (8-bitOffset)
2572 << " {\n";
2573 PINDEX i = 0;
2574 while (i < GetSize()) {
2575 strm << setw(indent) << " " << hex << setfill('0');
2576 PINDEX j;
2577 for (j = 0; j < 16; j++)
2578 if (i+j < GetSize())
2579 strm << setw(2) << (unsigned)(BYTE)theArray[i+j] << ' ';
2580 else
2581 strm << " ";
2582 strm << " ";
2583 for (j = 0; j < 16; j++) {
2584 if (i+j < GetSize()) {
2585 BYTE c = theArray[i+j];
2586 if (c < 128 && isprint(c))
2587 strm << c;
2588 else
2589 strm << ' ';
2592 strm << dec << setfill(' ') << '\n';
2593 i += 16;
2595 strm << setw(indent-1) << "}";
2599 void PASN_Stream::SetPosition(PINDEX newPos)
2601 PAssert(byteOffset != P_MAX_INDEX, PLogicError);
2603 if (newPos > GetSize())
2604 byteOffset = GetSize();
2605 else
2606 byteOffset = newPos;
2607 bitOffset = 8;
2611 void PASN_Stream::ResetDecoder()
2613 byteOffset = 0;
2614 bitOffset = 8;
2618 void PASN_Stream::BeginEncoding()
2620 bitOffset = 8;
2621 byteOffset = 0;
2622 PBYTEArray::operator=(PBYTEArray(20));
2626 void PASN_Stream::CompleteEncoding()
2628 if (byteOffset != P_MAX_INDEX) {
2629 if (bitOffset != 8) {
2630 bitOffset = 8;
2631 byteOffset++;
2633 SetSize(byteOffset);
2634 byteOffset = P_MAX_INDEX;
2639 BYTE PASN_Stream::ByteDecode()
2641 if (byteOffset >= GetSize())
2642 return 0;
2644 bitOffset = 8;
2645 return theArray[byteOffset++];
2649 void PASN_Stream::ByteEncode(unsigned value)
2651 PAssert(byteOffset != P_MAX_INDEX, PLogicError);
2653 if (bitOffset != 8) {
2654 bitOffset = 8;
2655 byteOffset++;
2657 if (byteOffset >= GetSize())
2658 SetSize(byteOffset+10);
2659 theArray[byteOffset++] = (BYTE)value;
2663 unsigned PASN_Stream::BlockDecode(BYTE * bufptr, unsigned nBytes)
2665 if (nBytes == 0 || bufptr == NULL)
2666 return 0;
2668 ByteAlign();
2670 if (byteOffset+nBytes > (unsigned)GetSize()) {
2671 nBytes = GetSize() - byteOffset;
2672 if (nBytes == 0)
2673 return 0;
2676 memcpy(bufptr, &theArray[byteOffset], nBytes);
2677 byteOffset += nBytes;
2678 return nBytes;
2682 void PASN_Stream::BlockEncode(const BYTE * bufptr, PINDEX nBytes)
2684 PAssert(byteOffset != P_MAX_INDEX, PLogicError);
2686 if (nBytes == 0)
2687 return;
2689 ByteAlign();
2691 if (byteOffset+nBytes >= GetSize())
2692 SetSize(byteOffset+nBytes+10);
2694 memcpy(theArray+byteOffset, bufptr, nBytes);
2695 byteOffset += nBytes;
2699 void PASN_Stream::ByteAlign()
2701 PAssert(byteOffset != P_MAX_INDEX, PLogicError);
2703 if (bitOffset != 8) {
2704 bitOffset = 8;
2705 byteOffset++;
2710 ///////////////////////////////////////////////////////////////////////
2712 #ifdef P_INCLUDE_PER
2713 #include "asnper.cxx"
2714 #endif
2716 #ifdef P_INCLUDE_BER
2717 #include "asnber.cxx"
2718 #endif
2720 #ifdef P_INCLUDE_XER
2721 #include "asnxer.cxx"
2722 #endif
2724 // End of file ////////////////////////////////////////////////////////////////