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
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
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
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
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.
306 #pragma implementation "asner.h"
309 #include <ptclib/asner.h>
312 #include <ptclib/pxml.h>
318 static PINDEX MaximumArraySize
= 128;
319 static PINDEX MaximumStringSize
= 16*1024;
322 static PINDEX
CountBits(unsigned range
)
326 return sizeof(unsigned)*8;
332 while (nBits
< (sizeof(unsigned)*8) && range
> (unsigned)(1 << nBits
))
338 ///////////////////////////////////////////////////////////////////////
340 PASN_Object::PASN_Object(unsigned theTag
, TagClass theTagClass
, BOOL extend
)
346 if (theTagClass
!= DefaultTagClass
)
347 tagClass
= theTagClass
;
349 tagClass
= ContextSpecificTagClass
;
353 void PASN_Object::SetTag(unsigned newTag
, TagClass tagClass_
)
356 if (tagClass_
!= DefaultTagClass
)
357 tagClass
= tagClass_
;
361 PINDEX
PASN_Object::GetObjectLength() const
366 len
+= (CountBits(tag
)+6)/7;
368 PINDEX dataLen
= GetDataLength();
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
;
424 upperLimit
= UINT_MAX
;
428 void PASN_ConstrainedObject::SetConstraintBounds(ConstraintType ctype
,
429 int lower
, unsigned upper
)
432 if (constraint
== Unconstrained
) {
437 extendable
= ctype
== ExtendableConstraint
;
438 PAssert((lower
>= 0 || upper
< 0x7fffffff) &&
439 (lower
< 0 || (unsigned)lower
<= upper
), PInvalidParameter
);
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
);
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
473 PString
PASN_Null::GetTypeAsString() const
479 PINDEX
PASN_Null::GetDataLength() const
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
)
506 PASN_Boolean::PASN_Boolean(unsigned tag
, TagClass tagClass
, BOOL val
)
507 : PASN_Object(tag
, tagClass
)
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
536 PString
PASN_Boolean::GetTypeAsString() const
542 PINDEX
PASN_Boolean::GetDataLength() const
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
)
569 PASN_Integer::PASN_Integer(unsigned tag
, TagClass tagClass
, unsigned val
)
570 : PASN_ConstrainedObject(tag
, tagClass
)
576 BOOL
PASN_Integer::IsUnsigned() const
578 return constraint
!= Unconstrained
&& lowerLimit
>= 0;
582 PASN_Integer
& PASN_Integer::operator=(unsigned val
)
584 if (constraint
== Unconstrained
)
586 else if (lowerLimit
>= 0) { // Is unsigned integer
587 if (val
< (unsigned)lowerLimit
)
589 else if (val
> upperLimit
)
596 if (ival
< lowerLimit
)
598 else if (upperLimit
< INT_MAX
&& ival
> (int)upperLimit
)
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
;
614 if (value
< other
.value
)
616 if (value
> other
.value
)
620 if ((int)value
< (int)other
.value
)
622 if ((int)value
> (int)other
.value
)
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)
645 void PASN_Integer::SetConstraintBounds(ConstraintType type
, int lower
, unsigned upper
)
647 PASN_ConstrainedObject::SetConstraintBounds(type
, lower
, upper
);
652 PString
PASN_Integer::GetTypeAsString() const
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))
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
)
696 maxEnumValue
= P_MAX_INDEX
;
700 PASN_Enumeration::PASN_Enumeration(unsigned tag
, TagClass tagClass
,
701 unsigned maxEnum
, BOOL extend
,
703 : PASN_Object(tag
, tagClass
, extend
)
706 maxEnumValue
= maxEnum
;
710 static POrdinalToString
BuildNamesDict(const PString
& nameSpec
)
712 POrdinalToString names
;
714 PStringArray nameList
= nameSpec
.Tokenise(' ', FALSE
);
717 for (PINDEX i
= 0; i
< nameList
.GetSize(); i
++) {
718 const PString
& thisName
= nameList
[i
];
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
));
732 PASN_Enumeration::PASN_Enumeration(unsigned tag
, TagClass tagClass
,
733 unsigned maxEnum
, BOOL extend
,
734 const PString
& nameSpec
,
736 : PASN_Object(tag
, tagClass
, extend
),
737 names(BuildNamesDict(nameSpec
))
739 maxEnumValue
= maxEnum
;
741 PAssert(val
<= maxEnum
, PInvalidParameter
);
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
)
754 if (value
> other
.value
)
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
];
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
)
810 PASN_Real::PASN_Real(unsigned tag
, TagClass tagClass
, double val
)
811 : PASN_Object(tag
, tagClass
)
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
)
825 if (value
> other
.value
)
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
845 PString
PASN_Real::GetTypeAsString() const
851 PINDEX
PASN_Real::GetDataLength() const
853 PAssertAlways(PUnimplementedFunction
);
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
)
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());
901 PASN_ObjectId
& PASN_ObjectId::operator=(const char * dotstr
)
911 PASN_ObjectId
& PASN_ObjectId::operator=(const PString
& dotstr
)
918 PASN_ObjectId
& PASN_ObjectId::operator=(const PUnsignedArray
& numbers
)
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
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)
973 PString
PASN_ObjectId::AsString() const
981 PString
PASN_ObjectId::GetTypeAsString() const
987 BOOL
PASN_ObjectId::CommonDecode(PASN_Stream
& strm
, unsigned dataLen
)
991 // handle zero length strings correctly
997 // start at the second identifier in the buffer, because we will later
998 // expand the first number into the first two IDs
1000 while (dataLen
> 0) {
1003 do { /* shift and add in low order 7 bits */
1006 byte
= strm
.ByteDecode();
1007 subId
= (subId
<< 7) + (byte
& 0x7f);
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.
1024 else if (subId
< 80) {
1026 value
[1] = subId
-40;
1030 value
[1] = subId
-80;
1037 void PASN_ObjectId::CommonEncode(PBYTEArray
& encodecObjectId
) const
1039 PINDEX length
= value
.GetSize();
1040 const unsigned * objId
= value
;
1043 // Thise case is really illegal, but we have to do SOMETHING
1044 encodecObjectId
.SetSize(0);
1048 unsigned subId
= (objId
[0] * 40) + objId
[1];
1051 PINDEX outputPosition
= 0;
1053 while (--length
> 0) {
1055 encodecObjectId
[outputPosition
++] = (BYTE
)subId
;
1057 unsigned mask
= 0x7F; /* handle subid == 0 case */
1060 /* testmask *MUST* !!!! be of an unsigned type */
1061 unsigned testmask
= 0x7F;
1063 while (testmask
!= 0) {
1064 if (subId
& testmask
) { /* if any bits set */
1072 /* mask can't be zero here */
1073 while (mask
!= 0x7F) {
1074 /* fix a mask that got truncated above */
1075 if (mask
== 0x1E00000)
1078 encodecObjectId
[outputPosition
++] = (BYTE
)(((subId
& mask
) >> bits
) | 0x80);
1084 encodecObjectId
[outputPosition
++] = (BYTE
)(subId
& mask
);
1093 PINDEX
PASN_ObjectId::GetDataLength() const
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
),
1118 bitData((totalBits
+7)/8)
1121 memcpy(bitData
.GetPointer(), buf
, bitData
.GetSize());
1125 PASN_BitString::PASN_BitString(unsigned tag
, TagClass tagClass
, unsigned nBits
)
1126 : PASN_ConstrainedObject(tag
, tagClass
),
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());
1150 void PASN_BitString::SetData(unsigned nBits
, const PBYTEArray
& bytes
)
1152 PAssert((PINDEX
)nBits
< MaximumStringSize
, PInvalidParameter
);
1159 void PASN_BitString::SetData(unsigned nBits
, const BYTE
* buf
, PINDEX size
)
1161 PAssert((PINDEX
)nBits
< MaximumStringSize
, PInvalidParameter
);
1165 memcpy(bitData
.GetPointer(size
), buf
, size
);
1170 BOOL
PASN_BitString::SetSize(unsigned nBits
)
1172 if ((PINDEX
)nBits
> MaximumStringSize
)
1175 if (constraint
== Unconstrained
)
1177 else if (totalBits
< (unsigned)lowerLimit
)
1178 totalBits
= lowerLimit
;
1179 else if ((unsigned)totalBits
> upperLimit
)
1180 totalBits
= upperLimit
;
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;
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
)
1222 if (totalBits
> other
.totalBits
)
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)
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)
1248 << hex
<< setfill('0') << resetiosflags(ios::floatfield
) << setiosflags(ios::fixed
)
1249 << setprecision(2) << setw(16) << bitData
1250 << dec
<< setfill(' ') << resetiosflags(ios::floatfield
);
1254 for (unsigned i
= 0; i
< totalBits
; i
++) {
1255 strm
<< ((bitData
[offset
]&mask
) != 0 ? '1' : '0');
1268 void PASN_BitString::SetConstraintBounds(ConstraintType type
, int lower
, unsigned upper
)
1270 PAssert(lower
>= 0, PInvalidParameter
);
1271 PASN_ConstrainedObject::SetConstraintBounds(type
, lower
, upper
);
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
)
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());
1334 PASN_OctetString
& PASN_OctetString::operator=(const char * str
)
1337 value
.SetSize(lowerLimit
);
1339 SetValue((const BYTE
*)str
, strlen(str
));
1344 PASN_OctetString
& PASN_OctetString::operator=(const PString
& str
)
1346 SetValue((const BYTE
*)(const char *)str
, str
.GetSize()-1);
1351 PASN_OctetString
& PASN_OctetString::operator=(const PBYTEArray
& arr
)
1353 PINDEX len
= arr
.GetSize();
1354 if ((unsigned)len
> upperLimit
|| (int)len
< lowerLimit
)
1362 void PASN_OctetString::SetValue(const BYTE
* data
, PINDEX len
)
1364 if ((unsigned)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())
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';
1406 PBYTEArray
truncatedArray(value
, 32);
1407 strm
<< truncatedArray
<< '\n'
1409 << setw(indent
+4) << "...\n";
1412 strm
<< dec
<< setfill(' ')
1413 << setw(indent
-1) << "}";
1419 void PASN_OctetString::SetConstraintBounds(ConstraintType type
, int lower
, unsigned upper
)
1421 PAssert(lower
>= 0, PInvalidParameter
);
1422 PASN_ConstrainedObject::SetConstraintBounds(type
, lower
, upper
);
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
)
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
)
1484 PStringStream newValue
;
1486 PINDEX len
= strlen(str
);
1488 // Can't copy any more characters than the upper constraint
1489 if ((unsigned)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
)
1499 // Make sure string meets minimum length constraint
1500 while ((int)len
< lowerLimit
) {
1501 newValue
<< characterSet
[0];
1506 value
.MakeMinimumSize();
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
)
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
);
1533 characterSet
.SetSize(setSize
);
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) \
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
)
1668 PASN_BMPString::PASN_BMPString(const PWORDArray
& wstr
)
1669 : PASN_ConstrainedObject(UniversalBMPString
, UniversalTagClass
)
1676 PASN_BMPString::PASN_BMPString(unsigned tag
, TagClass tagClass
)
1677 : PASN_ConstrainedObject(tag
, tagClass
)
1683 void PASN_BMPString::Construct()
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
;
1719 BOOL
PASN_BMPString::IsLegalCharacter(WORD ch
)
1727 if (characterSet
.IsEmpty())
1730 const WORD
* wptr
= characterSet
;
1731 PINDEX count
= characterSet
.GetSize();
1732 while (count
-- > 0) {
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
);
1755 for (PINDEX i
= 0; i
< paramSize
; i
++) {
1757 if (IsLegalCharacter(c
))
1761 // Pad out with the first character till required size
1762 while (count
< newSize
)
1763 value
[count
++] = firstChar
;
1769 void PASN_BMPString::SetCharacterSet(ConstraintType ctype
, const char * charSet
)
1771 PWORDArray
array(strlen(charSet
));
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
) {
1786 characterSet
.SetSize(0);
1789 characterSet
= charSet
;
1791 charSetUnalignedBits
= CountBits(lastChar
- firstChar
+ 1);
1792 if (!charSet
.IsEmpty()) {
1794 for (PINDEX i
= 0; i
< charSet
.GetSize(); i
++) {
1795 if (characterSet
[i
] >= firstChar
&& characterSet
[i
] <= lastChar
)
1798 count
= CountBits(count
);
1799 if (charSetUnalignedBits
> count
)
1800 charSetUnalignedBits
= count
;
1803 charSetAlignedBits
= 1;
1804 while (charSetUnalignedBits
> charSetAlignedBits
)
1805 charSetAlignedBits
<<= 1;
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";
1845 strm
<< setw(indent
) << " " << hex
<< setfill('0');
1847 for (j
= 0; j
< 8; j
++)
1849 strm
<< setw(4) << value
[i
+j
] << ' ';
1853 for (j
= 0; j
< 8; j
++) {
1855 WORD c
= value
[i
+j
];
1856 if (c
< 128 && isprint(c
))
1862 strm
<< dec
<< setfill(' ') << '\n';
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");
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();
1913 if (isdigit(value
[12])) {
1914 seconds
= value(12,13).AsInteger();
1915 if (value
[14] != '.')
1919 while (isdigit(value
[zonePos
]))
1924 int zone
= PTime::Local
;
1925 switch (value
[zonePos
]) {
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();
1950 PTime
PASN_UniversalTime::GetValue() const
1952 int year
= value(0,1).AsInteger();
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();
1965 if (isdigit(value
[10])) {
1966 seconds
= value(10,11).AsInteger();
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
;
1989 PASN_Choice::PASN_Choice(unsigned tag
, TagClass tagClass
,
1990 unsigned upper
, BOOL extend
)
1991 : PASN_Object(tag
, tagClass
, extend
)
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
))
2008 PASN_Choice::PASN_Choice(const PASN_Choice
& other
)
2009 : PASN_Object(other
),
2012 numChoices
= other
.numChoices
;
2014 if (other
.CheckCreate())
2015 choice
= (PASN_Object
*)other
.choice
->Clone();
2021 PASN_Choice
& PASN_Choice::operator=(const PASN_Choice
& other
)
2023 if (&other
== this) // Assigning to ourself, just do nothing.
2028 PASN_Object::operator=(other
);
2030 numChoices
= other
.numChoices
;
2031 names
= other
.names
;
2033 if (other
.CheckCreate())
2034 choice
= (PASN_Object
*)other
.choice
->Clone();
2042 PASN_Choice::~PASN_Choice()
2048 void PASN_Choice::SetTag(unsigned newTag
, TagClass tagClass
)
2050 PASN_Object::SetTag(newTag
, tagClass
);
2055 choice
->SetTag(newTag
, tagClass
);
2059 PString
PASN_Choice::GetTagName() const
2061 if (names
.Contains(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
2079 return ((PASN_Choice
*)this)->CreateObject();
2083 PASN_Object
& PASN_Choice::GetObject() const
2085 PAssert(CheckCreate(), "NULL 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; \
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; \
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
;
2142 other
.CheckCreate();
2144 if (choice
== other
.choice
)
2150 if (other
.choice
== NULL
)
2153 if (tag
< other
.tag
)
2156 if (tag
> other
.tag
)
2159 return choice
->Compare(*other
.choice
);
2163 void PASN_Choice::PrintOn(ostream
& strm
) const
2165 strm
<< GetTagName();
2168 strm
<< ' ' << *choice
;
2174 PString
PASN_Choice::GetTypeAsString() const
2180 PINDEX
PASN_Choice::GetDataLength() const
2183 return choice
->GetDataLength();
2189 BOOL
PASN_Choice::IsPrimitive() const
2192 return choice
->IsPrimitive();
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
;
2254 BOOL
PASN_Sequence::HasOptionalField(PINDEX opt
) const
2256 if (opt
< (PINDEX
)optionMap
.GetSize())
2257 return optionMap
[opt
];
2259 return extensionMap
[opt
- optionMap
.GetSize()];
2263 void PASN_Sequence::IncludeOptionalField(PINDEX opt
)
2265 if (opt
< (PINDEX
)optionMap
.GetSize())
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
);
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;
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";
2314 case ApplicationTagClass
:
2315 strm
<< "Application";
2317 case ContextSpecificTagClass
:
2318 strm
<< "ContextSpecific";
2320 case PrivateTagClass
:
2325 strm
<< '-' << fields
[i
].GetTag() << '-'
2326 << fields
[i
].GetTypeAsString() << "> = "
2327 << fields
[i
] << '\n';
2329 strm
<< setw(indent
-1) << "}";
2333 PString
PASN_Sequence::GetTypeAsString() const
2339 PINDEX
PASN_Sequence::GetDataLength() const
2342 for (PINDEX i
= 0; i
< fields
.GetSize(); i
++)
2343 len
+= fields
[i
].GetObjectLength();
2348 BOOL
PASN_Sequence::IsPrimitive() const
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
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());
2453 BOOL
PASN_Array::SetSize(PINDEX newSize
)
2455 if (newSize
> MaximumArraySize
)
2458 PINDEX originalSize
= array
.GetSize();
2459 if (!array
.SetSize(newSize
))
2462 for (PINDEX i
= originalSize
; i
< newSize
; i
++) {
2463 PASN_Object
* obj
= CreateObject();
2467 array
.SetAt(i
, obj
);
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
2511 PINDEX
PASN_Array::GetDataLength() const
2514 for (PINDEX i
= 0; i
< array
.GetSize(); i
++)
2515 len
+= array
[i
].GetObjectLength();
2520 BOOL
PASN_Array::IsPrimitive() const
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()
2546 PASN_Stream::PASN_Stream(const PBYTEArray
& bytes
)
2553 PASN_Stream::PASN_Stream(const BYTE
* buf
, PINDEX size
)
2554 : PBYTEArray(buf
, size
)
2560 void PASN_Stream::Construct()
2567 void PASN_Stream::PrintOn(ostream
& strm
) const
2569 int indent
= strm
.precision() + 2;
2570 strm
<< " size=" << GetSize()
2571 << " pos=" << byteOffset
<< '.' << (8-bitOffset
)
2574 while (i
< GetSize()) {
2575 strm
<< setw(indent
) << " " << hex
<< setfill('0');
2577 for (j
= 0; j
< 16; j
++)
2578 if (i
+j
< GetSize())
2579 strm
<< setw(2) << (unsigned)(BYTE
)theArray
[i
+j
] << ' ';
2583 for (j
= 0; j
< 16; j
++) {
2584 if (i
+j
< GetSize()) {
2585 BYTE c
= theArray
[i
+j
];
2586 if (c
< 128 && isprint(c
))
2592 strm
<< dec
<< setfill(' ') << '\n';
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();
2606 byteOffset
= newPos
;
2611 void PASN_Stream::ResetDecoder()
2618 void PASN_Stream::BeginEncoding()
2622 PBYTEArray::operator=(PBYTEArray(20));
2626 void PASN_Stream::CompleteEncoding()
2628 if (byteOffset
!= P_MAX_INDEX
) {
2629 if (bitOffset
!= 8) {
2633 SetSize(byteOffset
);
2634 byteOffset
= P_MAX_INDEX
;
2639 BYTE
PASN_Stream::ByteDecode()
2641 if (byteOffset
>= GetSize())
2645 return theArray
[byteOffset
++];
2649 void PASN_Stream::ByteEncode(unsigned value
)
2651 PAssert(byteOffset
!= P_MAX_INDEX
, PLogicError
);
2653 if (bitOffset
!= 8) {
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
)
2670 if (byteOffset
+nBytes
> (unsigned)GetSize()) {
2671 nBytes
= GetSize() - byteOffset
;
2676 memcpy(bufptr
, &theArray
[byteOffset
], nBytes
);
2677 byteOffset
+= nBytes
;
2682 void PASN_Stream::BlockEncode(const BYTE
* bufptr
, PINDEX nBytes
)
2684 PAssert(byteOffset
!= P_MAX_INDEX
, PLogicError
);
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) {
2710 ///////////////////////////////////////////////////////////////////////
2712 #ifdef P_INCLUDE_PER
2713 #include "asnper.cxx"
2716 #ifdef P_INCLUDE_BER
2717 #include "asnber.cxx"
2720 #ifdef P_INCLUDE_XER
2721 #include "asnxer.cxx"
2724 // End of file ////////////////////////////////////////////////////////////////