Simplified &#num; parsing.
[pwlib.git] / src / ptclib / asner.cxx
blob0f52676780e59dfa1aa2a0c9a7517a3f0292df9b
1 /*
2 * asner.cxx
4 * Abstract Syntax Notation 1 Encoding Rules
6 * Portable Windows Library
8 * Copyright (c) 1993-1998 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 * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
25 * All Rights Reserved.
27 * Contributor(s): ______________________________________.
29 * $Log$
30 * Revision 1.50 2001/08/07 04:37:03 robertj
31 * Simplified &#num; parsing.
33 * Revision 1.49 2001/08/07 02:49:05 robertj
34 * Fixed incorrect alignment if constrained string upper bound is exactly
35 * 16 bits long. thanks Guntram Diehl & Thomas Arimont.
37 * Revision 1.48 2001/08/06 09:35:25 robertj
38 * Fixed GNU compatibility.
40 * Revision 1.47 2001/08/06 09:31:48 robertj
41 * Added conversion of BMPString to PString without losing special characters.
43 * Revision 1.46 2001/08/06 01:39:02 robertj
44 * Added assignement operator with RHS of PASN_BMPString to classes
45 * descended from PASN_BMPString.
47 * Revision 1.45 2001/06/14 02:14:12 robertj
48 * Added functions to encode and decode another ASN type that is inside
49 * an octet string, useful for ANY or EXTERNAL types etc.
51 * Revision 1.44 2001/05/29 00:59:16 robertj
52 * Fixed excessive padding on constrained strings.
54 * Revision 1.43 2001/05/22 23:37:42 robertj
55 * Fixed problem with assigning a constrained string value to itself, which
56 * can occur when changing constraints.
58 * Revision 1.42 2001/04/30 10:47:33 robertj
59 * Fixed stupid error in last patch.
61 * Revision 1.41 2001/04/30 06:47:04 robertj
62 * Fixed problem with en/decoding more than 16 extension fields in a sequence.
64 * Revision 1.40 2001/04/26 08:15:58 robertj
65 * Fixed problem with ASN compile of single constraints on enumerations.
67 * Revision 1.39 2001/04/23 05:46:06 robertj
68 * Fixed problem with unconstrained PASN_NumericString coding in 8 bits
69 * instead of 4, thanks Chew Kuan.
71 * Revision 1.38 2001/04/23 04:40:14 robertj
72 * Added ASN standard types GeneralizedTime and UTCTime
74 * Revision 1.37 2001/04/12 03:26:59 robertj
75 * Fixed PASN_Boolean cosntructor to be compatible with usage in ASN parser.
76 * Changed all PASN_xxx types so constructor can take real type as only
77 * parameter. eg PASN_OctetString s = "fred";
78 * Changed block encode/decode so does not do a ByteAlign() if zero
79 * length, required for interoperability even though spec implies otherwise..
81 * Revision 1.36 2001/01/24 04:37:07 robertj
82 * Added more bulletproofing to ASN structures to obey constraints.
84 * Revision 1.35 2001/01/03 01:20:13 robertj
85 * Fixed error in BlockEncode, should ByteAlign() even on zero length strings.
87 * Revision 1.34 2000/10/26 11:09:16 robertj
88 * More bullet proofing of PER decoder, changed bit type to be unsigned.
90 * Revision 1.33 2000/10/26 01:29:32 robertj
91 * Fixed MSVC warning.
93 * Revision 1.32 2000/10/25 04:05:38 robertj
94 * More bullet proofing of PER decoder.
96 * Revision 1.31 2000/09/29 04:11:51 robertj
97 * Fixed possible out of range memory access, thanks Petr Parýzek <paryzek@wo.cz>
99 * Revision 1.30 2000/02/29 06:32:12 robertj
100 * Added ability to remove optional field in sequence, thanks Dave Harvey.
102 * Revision 1.29 2000/01/20 06:22:22 robertj
103 * Fixed boundary condition error for constrained integer encoding (values 1, 256 etc)
105 * Revision 1.28 1999/11/22 23:15:43 robertj
106 * Fixed bug in PASN_Choice::Compare(), should make sure choices are the same before comparing.
108 * Revision 1.27 1999/08/19 15:43:07 robertj
109 * Fixed incorrect size of OID if zero length encoded.
111 * Revision 1.26 1999/08/09 13:02:45 robertj
112 * dded ASN compiler #defines for backward support of pre GCC 2.9 compilers.
113 * Added ASN compiler #defines to reduce its memory footprint.
115 * Revision 1.25 1999/08/08 15:45:59 robertj
116 * Fixed incorrect encoding of unknown extensions.
118 * Revision 1.24 1999/08/05 00:44:28 robertj
119 * Fixed PER encoding problems for large integer values.
121 * Revision 1.23 1999/07/22 06:48:54 robertj
122 * Added comparison operation to base ASN classes and compiled ASN code.
123 * Added support for ANY type in ASN parser.
125 * Revision 1.22 1999/07/08 08:39:12 robertj
126 * Fixed bug when assigning negative number ot cosntrained PASN_Integer
128 * Revision 1.21 1999/06/30 08:58:12 robertj
129 * Fixed bug in encoding/decoding OID greater than 2.39
131 * Revision 1.20 1999/06/17 13:27:09 robertj
132 * Fixed bug causing crashes on pass through of unknown extensions.
134 * Revision 1.19 1999/06/07 00:31:25 robertj
135 * Fixed signed/unsigned problem with number of unknown extensions check.
137 * Revision 1.18 1999/04/26 05:58:48 craigs
138 * Fixed problems with encoding of extensions
140 * Revision 1.17 1999/03/09 08:12:38 robertj
141 * Fixed problem with closing a steam encoding twice.
143 * Revision 1.16 1999/01/16 01:28:25 robertj
144 * Fixed problems with reading stream multiple times.
146 * Revision 1.15 1998/11/30 04:50:44 robertj
147 * New directory structure
149 * Revision 1.14 1998/10/22 04:33:11 robertj
150 * Fixed bug in constrained strings and PER, incorrect order of character set.
152 * Revision 1.13 1998/09/23 06:21:49 robertj
153 * Added open source copyright license.
155 * Revision 1.12 1998/05/26 05:29:23 robertj
156 * Workaroung for g++ iostream bug.
158 * Revision 1.11 1998/05/21 04:58:54 robertj
159 * GCC comptaibility.
161 * Revision 1.10 1998/05/21 04:26:54 robertj
162 * Fixed numerous PER problems.
164 * Revision 1.9 1998/05/11 06:01:55 robertj
165 * Why did this compile under MSC?
167 * Revision 1.8 1998/05/07 05:19:29 robertj
168 * Fixed problems with using copy constructor/assignment oeprator on PASN_Objects.
170 * Revision 1.7 1998/03/05 12:49:50 robertj
171 * MemCheck fixes.
173 * Revision 1.6 1998/02/03 06:28:27 robertj
174 * Fixed length calculation of integers in BER.
175 * Added new function to read a block with minimum number of bytes.
177 * Revision 1.5 1998/01/26 01:51:20 robertj
178 * Removed uninitialised variable warnings.
180 * Revision 1.4 1997/12/18 05:07:56 robertj
181 * Fixed bug in choice name display.
182 * Added function to get choice discriminator name.
183 * Fixed bug in encoding extensions.
185 * Revision 1.3 1997/12/11 10:36:22 robertj
186 * Support for new ASN parser.
190 #include <ptlib.h>
192 #ifdef __GNUC__
193 #pragma implementation "asner.h"
194 #endif
196 #include <ptclib/asner.h>
198 #define new PNEW
201 static PINDEX CountBits(unsigned range)
203 if (range == 0)
204 return sizeof(unsigned)*8;
206 PINDEX nBits = 0;
207 while (nBits < (sizeof(unsigned)*8) && range > (unsigned)(1 << nBits))
208 nBits++;
209 return nBits;
213 ///////////////////////////////////////////////////////////////////////
215 PASN_Object::PASN_Object(unsigned theTag, TagClass theTagClass, BOOL extend)
217 extendable = extend;
219 tag = theTag;
221 if (theTagClass != DefaultTagClass)
222 tagClass = theTagClass;
223 else
224 tagClass = ContextSpecificTagClass;
228 void PASN_Object::SetTag(unsigned newTag, TagClass tagClass_)
230 tag = newTag;
231 if (tagClass_ != DefaultTagClass)
232 tagClass = tagClass_;
236 PINDEX PASN_Object::GetObjectLength() const
238 PINDEX len = 1;
240 if (tag >= 31)
241 len += (CountBits(tag)+6)/7;
243 PINDEX dataLen = GetDataLength();
244 if (dataLen < 128)
245 len++;
246 else
247 len += (CountBits(dataLen)+7)/8 + 1;
249 return len + dataLen;
253 void PASN_Object::SetConstraintBounds(ConstraintType, int, unsigned)
258 void PASN_Object::SetCharacterSet(ConstraintType, const char *)
263 void PASN_Object::SetCharacterSet(ConstraintType, unsigned, unsigned)
268 ///////////////////////////////////////////////////////////////////////
270 PASN_ConstrainedObject::PASN_ConstrainedObject(unsigned tag, TagClass tagClass)
271 : PASN_Object(tag, tagClass)
273 constraint = Unconstrained;
274 lowerLimit = 0;
275 upperLimit = UINT_MAX;
279 void PASN_ConstrainedObject::SetConstraintBounds(ConstraintType ctype,
280 int lower, unsigned upper)
282 constraint = ctype;
283 if (constraint == Unconstrained) {
284 lower = 0;
285 upper = UINT_MAX;
288 extendable = ctype == ExtendableConstraint;
289 PAssert((lower >= 0 || upper < 0x7fffffff) &&
290 (lower < 0 || (unsigned)lower <= upper), PInvalidParameter);
291 lowerLimit = lower;
292 upperLimit = upper;
296 int PASN_ConstrainedObject::ConstrainedLengthDecode(PPER_Stream & strm, unsigned & length)
298 // The execution order is important in the following. The SingleBitDecode() function
299 // must be called if extendable is TRUE, no matter what.
300 if ((extendable && strm.SingleBitDecode()) || constraint == Unconstrained)
301 return strm.LengthDecode(0, INT_MAX, length);
302 else
303 return strm.LengthDecode(lowerLimit, upperLimit, length);
307 void PASN_ConstrainedObject::ConstrainedLengthEncode(PPER_Stream & strm, unsigned length) const
309 if (ConstraintEncode(strm, length)) // 26.4
310 strm.LengthEncode(length, 0, INT_MAX);
311 else
312 strm.LengthEncode(length, lowerLimit, upperLimit);
316 BOOL PASN_ConstrainedObject::ConstraintEncode(PPER_Stream & strm, unsigned value) const
318 if (!extendable)
319 return constraint != FixedConstraint;
321 BOOL needsExtending = value > upperLimit;
323 if (!needsExtending) {
324 if (lowerLimit < 0) {
325 if ((int)value < lowerLimit)
326 needsExtending = TRUE;
328 else {
329 if (value < (unsigned)lowerLimit)
330 needsExtending = TRUE;
334 strm.SingleBitEncode(needsExtending);
336 return needsExtending || constraint != FixedConstraint;
340 ///////////////////////////////////////////////////////////////////////
342 PASN_Null::PASN_Null(unsigned tag, TagClass tagClass)
343 : PASN_Object(tag, tagClass)
348 PObject::Comparison PASN_Null::Compare(const PObject & obj) const
350 PAssert(obj.IsDescendant(PASN_Null::Class()), PInvalidCast);
351 return EqualTo;
355 PObject * PASN_Null::Clone() const
357 PAssert(IsClass(PASN_Null::Class()), PInvalidCast);
358 return new PASN_Null(*this);
362 void PASN_Null::PrintOn(ostream & strm) const
364 strm << "<<null>>";
368 PString PASN_Null::GetTypeAsString() const
370 return "Null";
374 PINDEX PASN_Null::GetDataLength() const
376 return 0;
380 BOOL PASN_Null::Decode(PASN_Stream & strm)
382 return strm.NullDecode(*this);
386 void PASN_Null::Encode(PASN_Stream & strm) const
388 strm.NullEncode(*this);
392 BOOL PBER_Stream::NullDecode(PASN_Null & value)
394 unsigned len;
395 if (!HeaderDecode(value, len))
396 return FALSE;
398 byteOffset += len;
399 return TRUE;
403 void PBER_Stream::NullEncode(const PASN_Null & value)
405 HeaderEncode(value);
409 BOOL PPER_Stream::NullDecode(PASN_Null &)
411 return TRUE;
415 void PPER_Stream::NullEncode(const PASN_Null &)
420 ///////////////////////////////////////////////////////////////////////
422 PASN_Boolean::PASN_Boolean(BOOL val)
423 : PASN_Object(UniversalBoolean, UniversalTagClass)
425 value = val;
429 PASN_Boolean::PASN_Boolean(unsigned tag, TagClass tagClass, BOOL val)
430 : PASN_Object(tag, tagClass)
432 value = val;
436 PObject::Comparison PASN_Boolean::Compare(const PObject & obj) const
438 PAssert(obj.IsDescendant(PASN_Boolean::Class()), PInvalidCast);
439 return value == ((const PASN_Boolean &)obj).value ? EqualTo : GreaterThan;
443 PObject * PASN_Boolean::Clone() const
445 PAssert(IsClass(PASN_Boolean::Class()), PInvalidCast);
446 return new PASN_Boolean(*this);
450 void PASN_Boolean::PrintOn(ostream & strm) const
452 if (value)
453 strm << "TRUE";
454 else
455 strm << "FALSE";
459 PString PASN_Boolean::GetTypeAsString() const
461 return "Boolean";
465 PINDEX PASN_Boolean::GetDataLength() const
467 return 1;
471 BOOL PASN_Boolean::Decode(PASN_Stream & strm)
473 return strm.BooleanDecode(*this);
477 void PASN_Boolean::Encode(PASN_Stream & strm) const
479 strm.BooleanEncode(*this);
483 BOOL PBER_Stream::BooleanDecode(PASN_Boolean & value)
485 unsigned len;
486 if (!HeaderDecode(value, len))
487 return FALSE;
489 while (len-- > 0) {
490 if (IsAtEnd())
491 return FALSE;
492 value = (BOOL)ByteDecode();
495 return TRUE;
499 void PBER_Stream::BooleanEncode(const PASN_Boolean & value)
501 HeaderEncode(value);
502 ByteEncode((BOOL)value);
506 BOOL PPER_Stream::BooleanDecode(PASN_Boolean & value)
508 if (IsAtEnd())
509 return FALSE;
511 // X.931 Section 11
512 value = (BOOL)SingleBitDecode();
513 return TRUE;
517 void PPER_Stream::BooleanEncode(const PASN_Boolean & value)
519 // X.931 Section 11
520 SingleBitEncode((BOOL)value);
524 ///////////////////////////////////////////////////////////////////////
526 PASN_Integer::PASN_Integer(unsigned val)
527 : PASN_ConstrainedObject(UniversalInteger, UniversalTagClass)
529 value = val;
533 PASN_Integer::PASN_Integer(unsigned tag, TagClass tagClass, unsigned val)
534 : PASN_ConstrainedObject(tag, tagClass)
536 value = val;
540 PASN_Integer & PASN_Integer::operator=(unsigned val)
542 if (constraint == Unconstrained)
543 value = val;
544 else if (lowerLimit >= 0) { // Is unsigned integer
545 if (val < (unsigned)lowerLimit)
546 value = lowerLimit;
547 else if (val > upperLimit)
548 value = upperLimit;
549 else
550 value = val;
552 else {
553 int ival = (int)val;
554 if (ival < lowerLimit)
555 value = lowerLimit;
556 else if (upperLimit < INT_MAX && ival > (int)upperLimit)
557 value = upperLimit;
558 else
559 value = val;
562 return *this;
566 PObject::Comparison PASN_Integer::Compare(const PObject & obj) const
568 PAssert(obj.IsDescendant(PASN_Integer::Class()), PInvalidCast);
569 const PASN_Integer & other = (const PASN_Integer &)obj;
571 if (value < other.value)
572 return LessThan;
574 if (value > other.value)
575 return GreaterThan;
577 return EqualTo;
581 PObject * PASN_Integer::Clone() const
583 PAssert(IsClass(PASN_Integer::Class()), PInvalidCast);
584 return new PASN_Integer(*this);
588 void PASN_Integer::PrintOn(ostream & strm) const
590 if (lowerLimit < 0)
591 strm << (int)value;
592 else
593 strm << value;
597 void PASN_Integer::SetConstraintBounds(ConstraintType type, int lower, unsigned upper)
599 PASN_ConstrainedObject::SetConstraintBounds(type, lower, upper);
600 if (constraint != Unconstrained) {
601 if ((int)value < lowerLimit)
602 value = lowerLimit;
603 else if (value > upperLimit)
604 value = upperLimit;
609 PString PASN_Integer::GetTypeAsString() const
611 return "Integer";
615 static PINDEX GetIntegerDataLength(int value)
617 // create a mask which is the top nine bits of a DWORD, or 0xFF800000
618 // on a big endian machine
619 int shift = (sizeof(value)-1)*8-1;
621 // remove all sequences of nine 0's or 1's at the start of the value
622 while (shift > 0 && ((value >> shift)&0x1ff) == (value < 0 ? 0x1ff : 0))
623 shift -= 8;
625 return (shift+9)/8;
629 PINDEX PASN_Integer::GetDataLength() const
631 return GetIntegerDataLength(value);
635 BOOL PASN_Integer::Decode(PASN_Stream & strm)
637 return strm.IntegerDecode(*this);
641 void PASN_Integer::Encode(PASN_Stream & strm) const
643 strm.IntegerEncode(*this);
647 BOOL PBER_Stream::IntegerDecode(PASN_Integer & value)
649 unsigned len;
650 if (!HeaderDecode(value, len) || len == 0 || IsAtEnd())
651 return FALSE;
653 int accumulator = (char)ByteDecode(); // sign extended first byte
654 while (--len > 0) {
655 if (IsAtEnd())
656 return FALSE;
657 accumulator = (accumulator << 8) | ByteDecode();
660 value = accumulator;
661 return TRUE;
665 void PBER_Stream::IntegerEncode(const PASN_Integer & value)
667 HeaderEncode(value);
668 // output the integer bits
669 for (int count = GetIntegerDataLength(value)-1; count >= 0; count--)
670 ByteEncode(value >> (count*8));
674 BOOL PPER_Stream::IntegerDecode(PASN_Integer & value)
676 return value.DecodePER(*this);
680 void PPER_Stream::IntegerEncode(const PASN_Integer & value)
682 value.EncodePER(*this);
686 BOOL PASN_Integer::DecodePER(PPER_Stream & strm)
688 // X.931 Sections 12
690 if ((extendable && strm.SingleBitDecode()) || constraint != FixedConstraint) { // 12.1
691 unsigned len;
692 if (strm.LengthDecode(0, INT_MAX, len) != 0)
693 return FALSE;
694 return strm.MultiBitDecode(len*8, value);
697 if ((unsigned)lowerLimit != upperLimit) // 12.2.1
698 return strm.UnsignedDecode(lowerLimit, upperLimit, value) == 0; // 12.2.2 which devolves to 10.5
700 value = lowerLimit;
701 return TRUE;
705 void PASN_Integer::EncodePER(PPER_Stream & strm) const
707 // X.931 Sections 12
709 if (ConstraintEncode(strm, (int)value)) { // 12.1
710 PINDEX nBytes;
711 unsigned adjusted_value = value - lowerLimit;
712 if (adjusted_value == 0)
713 nBytes = 1;
714 else {
715 PINDEX nBits = CountBits(adjusted_value+1);
716 nBytes = (nBits+7)/8;
718 strm.LengthEncode(nBytes, 0, INT_MAX);
719 strm.MultiBitEncode(adjusted_value, nBytes*8);
720 return;
723 if ((unsigned)lowerLimit == upperLimit) // 12.2.1
724 return;
726 // 12.2.2 which devolves to 10.5
727 strm.UnsignedEncode(value, lowerLimit, upperLimit);
731 ///////////////////////////////////////////////////////////////////////
733 PASN_Enumeration::PASN_Enumeration(unsigned val)
734 : PASN_Object(UniversalEnumeration, UniversalTagClass, FALSE)
736 value = val;
737 maxEnumValue = P_MAX_INDEX;
741 PASN_Enumeration::PASN_Enumeration(unsigned tag, TagClass tagClass,
742 unsigned maxEnum, BOOL extend,
743 unsigned val)
744 : PASN_Object(tag, tagClass, extend)
746 value = val;
747 maxEnumValue = maxEnum;
751 static POrdinalToString BuildNamesDict(const PString & nameSpec)
753 POrdinalToString names;
755 PStringArray nameList = nameSpec.Tokenise(' ', FALSE);
757 int num = 0;
758 for (PINDEX i = 0; i < nameList.GetSize(); i++) {
759 const PString & thisName = nameList[i];
760 if (!thisName) {
761 PINDEX equalPos = thisName.Find('=');
762 if (equalPos != P_MAX_INDEX)
763 num = (int)thisName.Mid(equalPos+1).AsInteger();
764 names.SetAt(POrdinalKey(num), thisName.Left(equalPos));
765 num++;
769 return names;
773 PASN_Enumeration::PASN_Enumeration(unsigned tag, TagClass tagClass,
774 unsigned maxEnum, BOOL extend,
775 const PString & nameSpec,
776 unsigned val)
777 : PASN_Object(tag, tagClass, extend),
778 names(BuildNamesDict(nameSpec))
780 PAssert(maxEnum > 0, PInvalidParameter);
781 maxEnumValue = maxEnum;
783 PAssert(val < maxEnum, PInvalidParameter);
784 value = val;
788 PObject::Comparison PASN_Enumeration::Compare(const PObject & obj) const
790 PAssert(obj.IsDescendant(PASN_Enumeration::Class()), PInvalidCast);
791 const PASN_Enumeration & other = (const PASN_Enumeration &)obj;
793 if (value < other.value)
794 return LessThan;
796 if (value > other.value)
797 return GreaterThan;
799 return EqualTo;
803 PObject * PASN_Enumeration::Clone() const
805 PAssert(IsClass(PASN_Enumeration::Class()), PInvalidCast);
806 return new PASN_Enumeration(*this);
810 void PASN_Enumeration::PrintOn(ostream & strm) const
812 if (names.Contains(value))
813 strm << names[value];
814 else
815 strm << '<' << value << '>';
819 PString PASN_Enumeration::GetTypeAsString() const
821 return "Enumeration";
825 PINDEX PASN_Enumeration::GetDataLength() const
827 return GetIntegerDataLength(value);
831 BOOL PASN_Enumeration::Decode(PASN_Stream & strm)
833 return strm.EnumerationDecode(*this);
837 void PASN_Enumeration::Encode(PASN_Stream & strm) const
839 strm.EnumerationEncode(*this);
843 BOOL PBER_Stream::EnumerationDecode(PASN_Enumeration & value)
845 unsigned len;
846 if (!HeaderDecode(value, len) || len == 0 || IsAtEnd())
847 return FALSE;
849 unsigned val = 0;
850 while (len-- > 0) {
851 if (IsAtEnd())
852 return FALSE;
853 val = (val << 8) | ByteDecode();
856 value = val;
857 return TRUE;
861 void PBER_Stream::EnumerationEncode(const PASN_Enumeration & value)
863 HeaderEncode(value);
864 // output the integer bits
865 for (int count = GetIntegerDataLength(value)-1; count >= 0; count--)
866 ByteEncode(value >> (count*8));
870 BOOL PPER_Stream::EnumerationDecode(PASN_Enumeration & value)
872 return value.DecodePER(*this);
876 void PPER_Stream::EnumerationEncode(const PASN_Enumeration & value)
878 value.EncodePER(*this);
882 BOOL PASN_Enumeration::DecodePER(PPER_Stream & strm)
884 // X.691 Section 13
886 if (extendable) { // 13.3
887 if (strm.SingleBitDecode()) {
888 unsigned len = 0;
889 return strm.SmallUnsignedDecode(len) &&
890 len > 0 &&
891 strm.UnsignedDecode(0, len-1, value) == 0;
895 return strm.UnsignedDecode(0, maxEnumValue, value) == 0; // 13.2
899 void PASN_Enumeration::EncodePER(PPER_Stream & strm) const
901 // X.691 Section 13
903 if (extendable) { // 13.3
904 BOOL extended = value > maxEnumValue;
905 strm.SingleBitEncode(extended);
906 if (extended) {
907 strm.SmallUnsignedEncode(1+value);
908 strm.UnsignedEncode(value, 0, value);
909 return;
913 strm.UnsignedEncode(value, 0, maxEnumValue); // 13.2
917 ///////////////////////////////////////////////////////////////////////
919 PASN_Real::PASN_Real(double val)
920 : PASN_Object(UniversalReal, UniversalTagClass)
922 value = val;
926 PASN_Real::PASN_Real(unsigned tag, TagClass tagClass, double val)
927 : PASN_Object(tag, tagClass)
929 value = val;
933 PObject::Comparison PASN_Real::Compare(const PObject & obj) const
935 PAssert(obj.IsDescendant(PASN_Real::Class()), PInvalidCast);
936 const PASN_Real & other = (const PASN_Real &)obj;
938 if (value < other.value)
939 return LessThan;
941 if (value > other.value)
942 return GreaterThan;
944 return EqualTo;
948 PObject * PASN_Real::Clone() const
950 PAssert(IsClass(PASN_Real::Class()), PInvalidCast);
951 return new PASN_Real(*this);
955 void PASN_Real::PrintOn(ostream & strm) const
957 strm << value;
961 PString PASN_Real::GetTypeAsString() const
963 return "Real";
967 PINDEX PASN_Real::GetDataLength() const
969 PAssertAlways(PUnimplementedFunction);
970 return 0;
974 BOOL PASN_Real::Decode(PASN_Stream & strm)
976 return strm.RealDecode(*this);
980 void PASN_Real::Encode(PASN_Stream & strm) const
982 strm.RealEncode(*this);
986 BOOL PBER_Stream::RealDecode(PASN_Real & value)
988 unsigned len;
989 if (!HeaderDecode(value, len) || len == 0 || IsAtEnd())
990 return FALSE;
992 PAssertAlways(PUnimplementedFunction);
993 byteOffset += len;
995 return TRUE;
999 void PBER_Stream::RealEncode(const PASN_Real &)
1001 PAssertAlways(PUnimplementedFunction);
1005 BOOL PPER_Stream::RealDecode(PASN_Real &)
1007 // X.691 Section 14
1009 if (IsAtEnd())
1010 return FALSE;
1012 unsigned len;
1013 if (!MultiBitDecode(8, len))
1014 return FALSE;
1016 PAssertAlways(PUnimplementedFunction);
1017 byteOffset += len+1;
1018 return TRUE;
1022 void PPER_Stream::RealEncode(const PASN_Real &)
1024 // X.691 Section 14
1026 MultiBitEncode(0, 8);
1027 PAssertAlways(PUnimplementedFunction);
1028 MultiBitEncode(0, 8);
1032 ///////////////////////////////////////////////////////////////////////
1034 PASN_ObjectId::PASN_ObjectId(const char * dotstr)
1035 : PASN_Object(UniversalObjectId, UniversalTagClass)
1037 if (dotstr != NULL)
1038 SetValue(dotstr);
1042 PASN_ObjectId::PASN_ObjectId(unsigned tag, TagClass tagClass)
1043 : PASN_Object(tag, tagClass)
1048 PASN_ObjectId::PASN_ObjectId(const PASN_ObjectId & other)
1049 : PASN_Object(other),
1050 value(other.value, other.GetSize())
1055 PASN_ObjectId & PASN_ObjectId::operator=(const PASN_ObjectId & other)
1057 PASN_Object::operator=(other);
1058 value = PUnsignedArray(other.value, other.GetSize());
1059 return *this;
1063 PASN_ObjectId & PASN_ObjectId::operator=(const char * dotstr)
1065 if (dotstr != NULL)
1066 SetValue(dotstr);
1067 else
1068 value.SetSize(0);
1069 return *this;
1073 PASN_ObjectId & PASN_ObjectId::operator=(const PString & dotstr)
1075 SetValue(dotstr);
1076 return *this;
1080 void PASN_ObjectId::SetValue(const PString & dotstr)
1082 PStringArray parts = dotstr.Tokenise('.');
1083 value.SetSize(parts.GetSize());
1084 for (PINDEX i = 0; i < parts.GetSize(); i++)
1085 value[i] = parts[i].AsUnsigned();
1089 BOOL PASN_ObjectId::operator==(const char * dotstr) const
1091 PASN_ObjectId id;
1092 id.SetValue(dotstr);
1093 return *this == id;
1097 PObject::Comparison PASN_ObjectId::Compare(const PObject & obj) const
1099 PAssert(obj.IsDescendant(PASN_ObjectId::Class()), PInvalidCast);
1100 const PASN_ObjectId & other = (const PASN_ObjectId &)obj;
1101 return value.Compare(other.value);
1105 PObject * PASN_ObjectId::Clone() const
1107 PAssert(IsClass(PASN_ObjectId::Class()), PInvalidCast);
1108 return new PASN_ObjectId(*this);
1112 void PASN_ObjectId::PrintOn(ostream & strm) const
1114 for (PINDEX i = 0; i < value.GetSize(); i++) {
1115 strm << (unsigned)value[i];
1116 if (i < value.GetSize()-1)
1117 strm << '.';
1122 PString PASN_ObjectId::GetTypeAsString() const
1124 return "Object ID";
1128 BOOL PASN_ObjectId::CommonDecode(PASN_Stream & strm, unsigned dataLen)
1130 value.SetSize(0);
1132 // handle zero length strings correctly
1133 if (dataLen == 0)
1134 return TRUE;
1136 unsigned subId;
1138 // start at the second identifier in the buffer, because we will later
1139 // expand the first number into the first two IDs
1140 PINDEX i = 1;
1141 while (dataLen > 0) {
1142 unsigned byte;
1143 subId = 0;
1144 do { /* shift and add in low order 7 bits */
1145 if (strm.IsAtEnd())
1146 return FALSE;
1147 byte = strm.ByteDecode();
1148 subId = (subId << 7) + (byte & 0x7f);
1149 dataLen--;
1150 } while ((byte & 0x80) != 0);
1151 value.SetAt(i++, subId);
1155 * The first two subidentifiers are encoded into the first component
1156 * with the value (X * 40) + Y, where:
1157 * X is the value of the first subidentifier.
1158 * Y is the value of the second subidentifier.
1160 subId = value[1];
1161 if (subId < 40) {
1162 value[0] = 0;
1163 value[1] = subId;
1165 else if (subId < 80) {
1166 value[0] = 1;
1167 value[1] = subId-40;
1169 else {
1170 value[0] = 2;
1171 value[1] = subId-80;
1174 return TRUE;
1178 void PASN_ObjectId::CommonEncode(PBYTEArray & encodecObjectId) const
1180 PINDEX length = value.GetSize();
1181 const unsigned * objId = value;
1183 if (length < 2) {
1184 // Thise case is really illegal, but we have to do SOMETHING
1185 encodecObjectId.SetSize(0);
1186 return;
1189 unsigned subId = (objId[0] * 40) + objId[1];
1190 objId += 2;
1192 PINDEX outputPosition = 0;
1194 while (--length > 0) {
1195 if (subId < 128)
1196 encodecObjectId[outputPosition++] = (BYTE)subId;
1197 else {
1198 unsigned mask = 0x7F; /* handle subid == 0 case */
1199 int bits = 0;
1201 /* testmask *MUST* !!!! be of an unsigned type */
1202 unsigned testmask = 0x7F;
1203 int testbits = 0;
1204 while (testmask != 0) {
1205 if (subId & testmask) { /* if any bits set */
1206 mask = testmask;
1207 bits = testbits;
1209 testmask <<= 7;
1210 testbits += 7;
1213 /* mask can't be zero here */
1214 while (mask != 0x7F) {
1215 /* fix a mask that got truncated above */
1216 if (mask == 0x1E00000)
1217 mask = 0xFE00000;
1219 encodecObjectId[outputPosition++] = (BYTE)(((subId & mask) >> bits) | 0x80);
1221 mask >>= 7;
1222 bits -= 7;
1225 encodecObjectId[outputPosition++] = (BYTE)(subId & mask);
1228 if (length > 1)
1229 subId = *objId++;
1234 PINDEX PASN_ObjectId::GetDataLength() const
1236 PBYTEArray dummy;
1237 CommonEncode(dummy);
1238 return dummy.GetSize();
1242 BOOL PASN_ObjectId::Decode(PASN_Stream & strm)
1244 return strm.ObjectIdDecode(*this);
1248 void PASN_ObjectId::Encode(PASN_Stream & strm) const
1250 strm.ObjectIdEncode(*this);
1254 BOOL PBER_Stream::ObjectIdDecode(PASN_ObjectId & value)
1256 unsigned len;
1257 if (!HeaderDecode(value, len))
1258 return FALSE;
1260 return value.CommonDecode(*this, len);
1264 void PBER_Stream::ObjectIdEncode(const PASN_ObjectId & value)
1266 HeaderEncode(value);
1267 PBYTEArray data;
1268 value.CommonEncode(data);
1269 BlockEncode(data, data.GetSize());
1273 BOOL PPER_Stream::ObjectIdDecode(PASN_ObjectId & value)
1275 // X.691 Section 23
1277 unsigned dataLen;
1278 if (LengthDecode(0, 255, dataLen) < 0)
1279 return FALSE;
1281 ByteAlign();
1282 return value.CommonDecode(*this, dataLen);
1286 void PPER_Stream::ObjectIdEncode(const PASN_ObjectId & value)
1288 // X.691 Section 23
1290 PBYTEArray eObjId;
1291 value.CommonEncode(eObjId);
1292 LengthEncode(eObjId.GetSize(), 0, 255);
1293 BlockEncode(eObjId, eObjId.GetSize());
1297 ///////////////////////////////////////////////////////////////////////
1299 PASN_BitString::PASN_BitString(unsigned nBits, const BYTE * buf)
1300 : PASN_ConstrainedObject(UniversalBitString, UniversalTagClass),
1301 totalBits(nBits),
1302 bitData((totalBits+7)/8)
1304 if (buf != NULL)
1305 memcpy(bitData.GetPointer(), buf, bitData.GetSize());
1309 PASN_BitString::PASN_BitString(unsigned tag, TagClass tagClass, unsigned nBits)
1310 : PASN_ConstrainedObject(tag, tagClass),
1311 totalBits(nBits),
1312 bitData((totalBits+7)/8)
1317 PASN_BitString::PASN_BitString(const PASN_BitString & other)
1318 : PASN_ConstrainedObject(other),
1319 bitData(other.bitData, other.bitData.GetSize())
1321 totalBits = other.totalBits;
1325 PASN_BitString & PASN_BitString::operator=(const PASN_BitString & other)
1327 PASN_ConstrainedObject::operator=(other);
1328 totalBits = other.totalBits;
1329 bitData = PBYTEArray(other.bitData, other.bitData.GetSize());
1330 return *this;
1334 void PASN_BitString::SetData(unsigned nBits, const PBYTEArray & bytes)
1336 bitData = bytes;
1337 SetSize(nBits);
1341 void PASN_BitString::SetData(unsigned nBits, const BYTE * buf, PINDEX size)
1343 if (size == 0)
1344 size = (nBits+7)/8;
1345 memcpy(bitData.GetPointer(size), buf, size);
1346 SetSize(nBits);
1350 BOOL PASN_BitString::SetSize(unsigned nBits)
1352 if (constraint == Unconstrained)
1353 totalBits = nBits;
1354 else if (totalBits < (unsigned)lowerLimit)
1355 totalBits = lowerLimit;
1356 else if ((unsigned)totalBits > upperLimit)
1357 totalBits = upperLimit;
1358 else
1359 totalBits = nBits;
1360 return bitData.SetSize((nBits+7)/8);
1364 BOOL PASN_BitString::operator[](PINDEX bit) const
1366 if ((unsigned)bit < totalBits)
1367 return (bitData[bit>>3] & (1 << (7 - (bit&7)))) != 0;
1368 return FALSE;
1372 void PASN_BitString::Set(unsigned bit)
1374 if (bit < totalBits)
1375 bitData[(PINDEX)(bit>>3)] |= 1 << (7 - (bit&7));
1379 void PASN_BitString::Clear(unsigned bit)
1381 if (bit < totalBits)
1382 bitData[(PINDEX)(bit>>3)] &= ~(1 << (7 - (bit&7)));
1386 void PASN_BitString::Invert(unsigned bit)
1388 if (bit < totalBits)
1389 bitData[(PINDEX)(bit>>3)] ^= 1 << (7 - (bit&7));
1393 PObject::Comparison PASN_BitString::Compare(const PObject & obj) const
1395 PAssert(obj.IsDescendant(PASN_BitString::Class()), PInvalidCast);
1396 const PASN_BitString & other = (const PASN_BitString &)obj;
1397 if (totalBits < other.totalBits)
1398 return LessThan;
1399 if (totalBits > other.totalBits)
1400 return GreaterThan;
1401 return bitData.Compare(other.bitData);
1405 PObject * PASN_BitString::Clone() const
1407 PAssert(IsClass(PASN_BitString::Class()), PInvalidCast);
1408 return new PASN_BitString(*this);
1412 void PASN_BitString::PrintOn(ostream & strm) const
1414 BYTE mask = 0x80;
1415 PINDEX offset = 0;
1416 for (unsigned i = 0; i < totalBits; i++) {
1417 strm << ((bitData[offset]&mask) != 0 ? '1' : '0');
1418 mask >>= 1;
1419 if (mask == 0) {
1420 mask = 0x80;
1421 offset++;
1427 void PASN_BitString::SetConstraintBounds(ConstraintType type, int lower, unsigned upper)
1429 PAssert(lower >= 0, PInvalidParameter);
1430 PASN_ConstrainedObject::SetConstraintBounds(type, lower, upper);
1431 SetSize(GetSize());
1435 PString PASN_BitString::GetTypeAsString() const
1437 return "Bit String";
1441 PINDEX PASN_BitString::GetDataLength() const
1443 return (totalBits+7)/8 + 1;
1447 BOOL PASN_BitString::Decode(PASN_Stream & strm)
1449 return strm.BitStringDecode(*this);
1453 void PASN_BitString::Encode(PASN_Stream & strm) const
1455 strm.BitStringEncode(*this);
1459 BOOL PASN_BitString::DecodeBER(PBER_Stream & strm, unsigned len)
1461 totalBits = len*8 - strm.ByteDecode();
1462 unsigned nBytes = (totalBits+7)/8;
1463 return strm.BlockDecode(bitData.GetPointer(nBytes), nBytes) == nBytes;
1467 void PASN_BitString::EncodeBER(PBER_Stream & strm) const
1469 if (totalBits == 0)
1470 strm.ByteEncode(0);
1471 else {
1472 strm.ByteEncode(8-totalBits%8);
1473 strm.BlockEncode(bitData, (totalBits+7)/8);
1478 BOOL PASN_BitString::DecodePER(PPER_Stream & strm)
1480 // X.691 Section 15
1482 if (ConstrainedLengthDecode(strm, totalBits) < 0)
1483 return FALSE;
1485 SetSize(totalBits);
1487 if (totalBits == 0)
1488 return TRUE; // 15.7
1490 if (totalBits > strm.GetBitsLeft())
1491 return FALSE;
1493 if (totalBits > 16) {
1494 unsigned nBytes = (totalBits+7)/8;
1495 return strm.BlockDecode(bitData.GetPointer(), nBytes) == nBytes; // 15.9
1498 unsigned theBits;
1499 if (totalBits <= 8) {
1500 if (!strm.MultiBitDecode(totalBits, theBits))
1501 return FALSE;
1503 bitData[0] = (BYTE)(theBits << (8-totalBits));
1505 else { // 15.8
1506 if (!strm.MultiBitDecode(8, theBits))
1507 return FALSE;
1509 bitData[0] = (BYTE)theBits;
1511 if (!strm.MultiBitDecode(totalBits-8, theBits))
1512 return FALSE;
1514 bitData[1] = (BYTE)(theBits << (16-totalBits));
1517 return TRUE;
1521 void PASN_BitString::EncodePER(PPER_Stream & strm) const
1523 // X.691 Section 15
1525 ConstrainedLengthEncode(strm, totalBits);
1527 if (totalBits == 0)
1528 return;
1530 if (totalBits > 16)
1531 strm.BlockEncode(bitData, (totalBits+7)/8); // 15.9
1532 else if (totalBits <= 8) // 15.8
1533 strm.MultiBitEncode(bitData[0] >> (8 - totalBits), totalBits);
1534 else {
1535 strm.MultiBitEncode(bitData[0], 8);
1536 strm.MultiBitEncode(bitData[1] >> (16 - totalBits), totalBits-8);
1541 BOOL PASN_BitString::DecodeSequenceExtensionBitmap(PPER_Stream & strm)
1543 if (!strm.SmallUnsignedDecode(totalBits))
1544 return FALSE;
1546 totalBits++;
1548 SetSize(totalBits);
1550 if (totalBits > strm.GetBitsLeft())
1551 return FALSE;
1553 unsigned theBits;
1555 PINDEX idx = 0;
1556 unsigned bitsLeft = totalBits;
1557 while (bitsLeft >= 8) {
1558 if (!strm.MultiBitDecode(8, theBits))
1559 return FALSE;
1560 bitData[idx++] = (BYTE)theBits;
1561 bitsLeft -= 8;
1564 if (bitsLeft > 0) {
1565 if (!strm.MultiBitDecode(bitsLeft, theBits))
1566 return FALSE;
1567 bitData[idx] = (BYTE)(theBits << (8-bitsLeft));
1570 return TRUE;
1574 void PASN_BitString::EncodeSequenceExtensionBitmap(PPER_Stream & strm) const
1576 PAssert(totalBits > 0, PLogicError);
1578 strm.SmallUnsignedEncode(totalBits-1);
1580 PINDEX idx = 0;
1581 unsigned bitsLeft = totalBits;
1582 while (bitsLeft >= 8) {
1583 strm.MultiBitEncode(bitData[idx++], 8);
1584 bitsLeft -= 8;
1587 if (bitsLeft > 0)
1588 strm.MultiBitEncode(bitData[idx] >> (8 - bitsLeft), bitsLeft);
1592 BOOL PBER_Stream::BitStringDecode(PASN_BitString & value)
1594 unsigned len;
1595 if (!HeaderDecode(value, len) || len == 0 || IsAtEnd())
1596 return FALSE;
1598 return value.DecodeBER(*this, len);
1602 void PBER_Stream::BitStringEncode(const PASN_BitString & value)
1604 HeaderEncode(value);
1605 value.EncodeBER(*this);
1609 BOOL PPER_Stream::BitStringDecode(PASN_BitString & value)
1611 return value.DecodePER(*this);
1615 void PPER_Stream::BitStringEncode(const PASN_BitString & value)
1617 value.EncodePER(*this);
1621 ///////////////////////////////////////////////////////////////////////
1623 PASN_OctetString::PASN_OctetString(const char * str, PINDEX size)
1624 : PASN_ConstrainedObject(UniversalOctetString, UniversalTagClass)
1626 if (str != NULL) {
1627 if (size == 0)
1628 size = ::strlen(str);
1629 SetValue((const BYTE *)str, size);
1634 PASN_OctetString::PASN_OctetString(unsigned tag, TagClass tagClass)
1635 : PASN_ConstrainedObject(tag, tagClass)
1640 PASN_OctetString::PASN_OctetString(const PASN_OctetString & other)
1641 : PASN_ConstrainedObject(other),
1642 value(other.value, other.GetSize())
1647 PASN_OctetString & PASN_OctetString::operator=(const PASN_OctetString & other)
1649 PASN_ConstrainedObject::operator=(other);
1650 value = PBYTEArray(other.value, other.GetSize());
1651 return *this;
1655 PASN_OctetString & PASN_OctetString::operator=(const char * str)
1657 if (str == NULL)
1658 value.SetSize(lowerLimit);
1659 else
1660 SetValue((const BYTE *)str, strlen(str));
1661 return *this;
1665 PASN_OctetString & PASN_OctetString::operator=(const PString & str)
1667 SetValue((const BYTE *)(const char *)str, str.GetSize()-1);
1668 return *this;
1672 PASN_OctetString & PASN_OctetString::operator=(const PBYTEArray & arr)
1674 PINDEX len = arr.GetSize();
1675 if ((unsigned)len > upperLimit || (int)len < lowerLimit)
1676 SetValue(arr, len);
1677 else
1678 value = arr;
1679 return *this;
1683 void PASN_OctetString::SetValue(const BYTE * data, PINDEX len)
1685 if ((unsigned)len > upperLimit)
1686 len = upperLimit;
1687 value.SetSize((int)len < lowerLimit ? lowerLimit : len);
1688 memcpy(value.GetPointer(), data, len);
1692 PString PASN_OctetString::AsString() const
1694 if (value.IsEmpty())
1695 return PString();
1696 return PString((const char *)(const BYTE *)value, value.GetSize());
1700 PObject::Comparison PASN_OctetString::Compare(const PObject & obj) const
1702 PAssert(obj.IsDescendant(PASN_OctetString::Class()), PInvalidCast);
1703 const PASN_OctetString & other = (const PASN_OctetString &)obj;
1704 return value.Compare(other.value);
1708 PObject * PASN_OctetString::Clone() const
1710 PAssert(IsClass(PASN_OctetString::Class()), PInvalidCast);
1711 return new PASN_OctetString(*this);
1715 void PASN_OctetString::PrintOn(ostream & strm) const
1717 int indent = strm.precision() + 2;
1718 strm << ' ' << value.GetSize() << " octets {\n";
1719 PINDEX i = 0;
1720 while (i < value.GetSize()) {
1721 strm << setw(indent) << " " << hex << setfill('0');
1722 PINDEX j;
1723 for (j = 0; j < 16; j++) {
1724 if (i+j < value.GetSize())
1725 strm << setw(2) << (unsigned)value[i+j] << ' ';
1726 else
1727 strm << " ";
1729 strm << " ";
1730 for (j = 0; j < 16; j++) {
1731 if (i+j < value.GetSize()) {
1732 if (isprint(value[i+j]))
1733 strm << value[i+j];
1734 else
1735 strm << ' ';
1738 strm << dec << setfill(' ') << '\n';
1739 i += 16;
1741 strm << setw(indent-1) << "}";
1745 void PASN_OctetString::SetConstraintBounds(ConstraintType type, int lower, unsigned upper)
1747 PAssert(lower >= 0, PInvalidParameter);
1748 PASN_ConstrainedObject::SetConstraintBounds(type, lower, upper);
1749 if (constraint != Unconstrained) {
1750 if (value.GetSize() < (PINDEX)lowerLimit)
1751 value.SetSize(lowerLimit);
1752 else if ((unsigned)value.GetSize() > upperLimit)
1753 value.SetSize(upperLimit);
1758 PString PASN_OctetString::GetTypeAsString() const
1760 return "Octet String";
1764 PINDEX PASN_OctetString::GetDataLength() const
1766 return value.GetSize();
1770 BOOL PASN_OctetString::Decode(PASN_Stream & strm)
1772 return strm.OctetStringDecode(*this);
1776 void PASN_OctetString::Encode(PASN_Stream & strm) const
1778 strm.OctetStringEncode(*this);
1782 BOOL PASN_OctetString::DecodePER(PPER_Stream & strm)
1784 // X.691 Section 16
1786 unsigned nBytes;
1787 if (ConstrainedLengthDecode(strm, nBytes) < 0)
1788 return FALSE;
1790 value.SetSize(nBytes); // 16.5
1792 unsigned theBits;
1793 switch (nBytes) {
1794 case 0 :
1795 break;
1797 case 1 : // 16.6
1798 if (!strm.MultiBitDecode(8, theBits))
1799 return FALSE;
1800 value[0] = (BYTE)theBits;
1801 break;
1803 case 2 : // 16.6
1804 if (!strm.MultiBitDecode(8, theBits))
1805 return FALSE;
1806 value[0] = (BYTE)theBits;
1807 if (!strm.MultiBitDecode(8, theBits))
1808 return FALSE;
1809 value[1] = (BYTE)theBits;
1810 break;
1812 default: // 16.7
1813 return strm.BlockDecode(value.GetPointer(), nBytes) == nBytes;
1816 return TRUE;
1820 void PASN_OctetString::EncodePER(PPER_Stream & strm) const
1822 // X.691 Section 16
1824 PINDEX nBytes = value.GetSize();
1825 ConstrainedLengthEncode(strm, nBytes);
1827 switch (nBytes) {
1828 case 0 : // 16.5
1829 break;
1831 case 1 : // 16.6
1832 strm.MultiBitEncode(value[0], 8);
1833 break;
1835 case 2 : // 16.6
1836 strm.MultiBitEncode(value[0], 8);
1837 strm.MultiBitEncode(value[1], 8);
1838 break;
1840 default: // 16.7
1841 strm.BlockEncode(value, nBytes);
1846 BOOL PBER_Stream::OctetStringDecode(PASN_OctetString & value)
1848 unsigned len;
1849 if (!HeaderDecode(value, len))
1850 return FALSE;
1852 return BlockDecode(value.GetPointer(len), len) == len;
1856 void PBER_Stream::OctetStringEncode(const PASN_OctetString & value)
1858 HeaderEncode(value);
1859 BlockEncode(value, value.GetSize());
1863 BOOL PPER_Stream::OctetStringDecode(PASN_OctetString & value)
1865 return value.DecodePER(*this);
1869 void PPER_Stream::OctetStringEncode(const PASN_OctetString & value)
1871 value.EncodePER(*this);
1875 BOOL PASN_OctetString::DecodeSubType(PASN_Object & obj)
1877 PPER_Stream stream = GetValue();
1878 return obj.Decode(stream);
1882 void PASN_OctetString::EncodeSubType(const PASN_Object & obj)
1884 PPER_Stream stream;
1885 obj.Encode(stream);
1886 stream.CompleteEncoding();
1887 SetValue(stream);
1891 ///////////////////////////////////////////////////////////////////////
1893 PASN_ConstrainedString::PASN_ConstrainedString(const char * canonical, PINDEX size,
1894 unsigned tag, TagClass tagClass)
1895 : PASN_ConstrainedObject(tag, tagClass)
1897 canonicalSet = canonical;
1898 canonicalSetSize = size;
1899 canonicalSetBits = CountBits(size);
1900 SetCharacterSet(canonicalSet, canonicalSetSize, Unconstrained);
1904 PASN_ConstrainedString & PASN_ConstrainedString::operator=(const char * str)
1906 if (str == NULL)
1907 str = "";
1909 PStringStream newValue;
1911 PINDEX len = strlen(str);
1913 // Can't copy any more characters than the upper constraint
1914 if ((unsigned)len > upperLimit)
1915 len = upperLimit;
1917 // Now copy individual characters, if they are in character set constraint
1918 for (PINDEX i = 0; i < len; i++) {
1919 PINDEX sz = characterSet.GetSize();
1920 if (sz == 0 || memchr(characterSet, str[i], sz) != NULL)
1921 newValue << str[i];
1924 // Make sure string meets minimum length constraint
1925 while ((int)len < lowerLimit) {
1926 newValue << characterSet[0];
1927 len++;
1930 value = newValue;
1931 value.MakeMinimumSize();
1932 return *this;
1936 void PASN_ConstrainedString::SetCharacterSet(ConstraintType ctype, const char * set)
1938 SetCharacterSet(set, strlen(set), ctype);
1942 void PASN_ConstrainedString::SetCharacterSet(ConstraintType ctype, unsigned firstChar, unsigned lastChar)
1944 char buffer[256];
1945 for (unsigned i = firstChar; i < lastChar; i++)
1946 buffer[i] = (char)i;
1947 SetCharacterSet(buffer, lastChar - firstChar + 1, ctype);
1951 void PASN_ConstrainedString::SetCharacterSet(const char * set, PINDEX setSize, ConstraintType ctype)
1953 if (ctype == Unconstrained) {
1954 characterSet.SetSize(canonicalSetSize);
1955 memcpy(characterSet.GetPointer(), canonicalSet, canonicalSetSize);
1957 else {
1958 characterSet.SetSize(setSize);
1959 PINDEX count = 0;
1960 for (PINDEX i = 0; i < canonicalSetSize; i++) {
1961 if (memchr(set, canonicalSet[i], setSize) != NULL)
1962 characterSet[count++] = canonicalSet[i];
1964 PAssert(count > 0, PInvalidParameter);
1965 characterSet.SetSize(count);
1968 charSetUnalignedBits = CountBits(characterSet.GetSize());
1970 charSetAlignedBits = 1;
1971 while (charSetUnalignedBits > charSetAlignedBits)
1972 charSetAlignedBits <<= 1;
1974 operator=((const char *)value);
1978 PObject::Comparison PASN_ConstrainedString::Compare(const PObject & obj) const
1980 PAssert(obj.IsDescendant(PASN_ConstrainedString::Class()), PInvalidCast);
1981 const PASN_ConstrainedString & other = (const PASN_ConstrainedString &)obj;
1982 return value.Compare(other.value);
1986 void PASN_ConstrainedString::PrintOn(ostream & strm) const
1988 strm << value.ToLiteral();
1992 void PASN_ConstrainedString::SetConstraintBounds(ConstraintType type,
1993 int lower, unsigned upper)
1995 PAssert(lower >= 0, PInvalidParameter);
1996 PASN_ConstrainedObject::SetConstraintBounds(type, lower, upper);
1997 if (constraint != Unconstrained) {
1998 if (value.GetSize() < (PINDEX)lowerLimit)
1999 value.SetSize(lowerLimit);
2000 else if ((unsigned)value.GetSize() > upperLimit)
2001 value.SetSize(upperLimit);
2006 PINDEX PASN_ConstrainedString::GetDataLength() const
2008 return value.GetSize()-1;
2012 BOOL PASN_ConstrainedString::Decode(PASN_Stream & strm)
2014 return strm.ConstrainedStringDecode(*this);
2018 void PASN_ConstrainedString::Encode(PASN_Stream & strm) const
2020 strm.ConstrainedStringEncode(*this);
2024 BOOL PASN_ConstrainedString::DecodeBER(PBER_Stream & strm, unsigned len)
2026 return strm.BlockDecode((BYTE *)value.GetPointer(len+1), len) == len;
2030 void PASN_ConstrainedString::EncodeBER(PBER_Stream & strm) const
2032 strm.BlockEncode(value, value.GetSize()-1);
2036 BOOL PASN_ConstrainedString::DecodePER(PPER_Stream & strm)
2038 // X.691 Section 26
2040 unsigned len;
2041 if (ConstrainedLengthDecode(strm, len) < 0)
2042 return FALSE;
2044 unsigned nBits = strm.IsAligned() ? charSetAlignedBits : charSetUnalignedBits;
2045 unsigned totalBits = upperLimit*nBits;
2047 if (constraint == Unconstrained ||
2048 (lowerLimit == (int)upperLimit ? (totalBits > 16) : (totalBits >= 16))) {
2049 if (nBits == 8)
2050 return strm.BlockDecode((BYTE *)value.GetPointer(len+1), len) == len;
2051 if (strm.IsAligned())
2052 strm.ByteAlign();
2055 value.SetSize(len+1);
2057 PINDEX i;
2058 for (i = 0; i < (PINDEX)len; i++) {
2059 unsigned theBits;
2060 if (!strm.MultiBitDecode(nBits, theBits))
2061 return FALSE;
2062 if (nBits >= canonicalSetBits && canonicalSetBits > 4)
2063 value[i] = (char)theBits;
2064 else
2065 value[i] = characterSet[(PINDEX)theBits];
2067 value[i] = '\0';
2069 return TRUE;
2073 void PASN_ConstrainedString::EncodePER(PPER_Stream & strm) const
2075 // X.691 Section 26
2077 PINDEX len = value.GetSize()-1;
2078 ConstrainedLengthEncode(strm, len);
2080 unsigned nBits = strm.IsAligned() ? charSetAlignedBits : charSetUnalignedBits;
2081 unsigned totalBits = upperLimit*nBits;
2083 if (constraint == Unconstrained ||
2084 (lowerLimit == (int)upperLimit ? (totalBits > 16) : (totalBits >= 16))) {
2085 if (nBits == 8) {
2086 strm.BlockEncode((const BYTE *)(const char *)value, len);
2087 return;
2089 if (strm.IsAligned())
2090 strm.ByteAlign();
2093 for (PINDEX i = 0; i < len; i++) {
2094 if (nBits >= canonicalSetBits && canonicalSetBits > 4)
2095 strm.MultiBitEncode(value[i], nBits);
2096 else {
2097 const void * ptr = memchr(characterSet, value[i], characterSet.GetSize());
2098 PINDEX pos = 0;
2099 if (ptr != NULL)
2100 pos = ((const char *)ptr - (const char *)characterSet);
2101 strm.MultiBitEncode(pos, nBits);
2107 BOOL PBER_Stream::ConstrainedStringDecode(PASN_ConstrainedString & value)
2109 unsigned len;
2110 if (!HeaderDecode(value, len))
2111 return FALSE;
2113 return value.DecodeBER(*this, len);
2117 void PBER_Stream::ConstrainedStringEncode(const PASN_ConstrainedString & value)
2119 HeaderEncode(value);
2120 value.Encode(*this);
2124 BOOL PPER_Stream::ConstrainedStringDecode(PASN_ConstrainedString & value)
2126 return value.DecodePER(*this);
2130 void PPER_Stream::ConstrainedStringEncode(const PASN_ConstrainedString & value)
2132 value.EncodePER(*this);
2136 #define DEFINE_STRING_CLASS(name, set) \
2137 static const char name##StringSet[] = set; \
2138 PASN_##name##String::PASN_##name##String(const char * str) \
2139 : PASN_ConstrainedString(name##StringSet, sizeof(name##StringSet)-1, \
2140 Universal##name##String, UniversalTagClass) \
2141 { PASN_ConstrainedString::SetValue(str); } \
2142 PASN_##name##String::PASN_##name##String(unsigned tag, TagClass tagClass) \
2143 : PASN_ConstrainedString(name##StringSet, sizeof(name##StringSet)-1, tag, tagClass) \
2144 { } \
2145 PASN_##name##String & PASN_##name##String::operator=(const char * str) \
2146 { PASN_ConstrainedString::SetValue(str); return *this; } \
2147 PASN_##name##String & PASN_##name##String::operator=(const PString & str) \
2148 { PASN_ConstrainedString::SetValue(str); return *this; } \
2149 PObject * PASN_##name##String::Clone() const \
2150 { PAssert(IsClass(PASN_##name##String::Class()), PInvalidCast); \
2151 return new PASN_##name##String(*this); } \
2152 PString PASN_##name##String::GetTypeAsString() const \
2153 { return #name " String"; }
2155 DEFINE_STRING_CLASS(Numeric, " 0123456789")
2156 DEFINE_STRING_CLASS(Printable, " '()+,-./0123456789:=?"
2157 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2158 "abcdefghijklmnopqrstuvwxyz")
2159 DEFINE_STRING_CLASS(Visible, " !\"#$%&'()*+,-./0123456789:;<=>?"
2160 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
2161 "`abcdefghijklmnopqrstuvwxyz{|}~")
2162 DEFINE_STRING_CLASS(IA5, "\000\001\002\003\004\005\006\007"
2163 "\010\011\012\013\014\015\016\017"
2164 "\020\021\022\023\024\025\026\027"
2165 "\030\031\032\033\034\035\036\037"
2166 " !\"#$%&'()*+,-./0123456789:;<=>?"
2167 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
2168 "`abcdefghijklmnopqrstuvwxyz{|}~\177")
2169 DEFINE_STRING_CLASS(General, "\000\001\002\003\004\005\006\007"
2170 "\010\011\012\013\014\015\016\017"
2171 "\020\021\022\023\024\025\026\027"
2172 "\030\031\032\033\034\035\036\037"
2173 " !\"#$%&'()*+,-./0123456789:;<=>?"
2174 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
2175 "`abcdefghijklmnopqrstuvwxyz{|}~\177"
2176 "\200\201\202\203\204\205\206\207"
2177 "\210\211\212\213\214\215\216\217"
2178 "\220\221\222\223\224\225\226\227"
2179 "\230\231\232\233\234\235\236\237"
2180 "\240\241\242\243\244\245\246\247"
2181 "\250\251\252\253\254\255\256\257"
2182 "\260\261\262\263\264\265\266\267"
2183 "\270\271\272\273\274\275\276\277"
2184 "\300\301\302\303\304\305\306\307"
2185 "\310\311\312\313\314\315\316\317"
2186 "\320\321\322\323\324\325\326\327"
2187 "\330\331\332\333\334\335\336\337"
2188 "\340\341\342\343\344\345\346\347"
2189 "\350\351\352\353\354\355\356\357"
2190 "\360\361\362\363\364\365\366\367"
2191 "\370\371\372\373\374\375\376\377")
2194 ///////////////////////////////////////////////////////////////////////
2196 PASN_BMPString::PASN_BMPString(const char * str)
2197 : PASN_ConstrainedObject(UniversalBMPString, UniversalTagClass)
2199 Construct();
2200 if (str != NULL)
2201 SetValue(str);
2205 PASN_BMPString::PASN_BMPString(const PWORDArray & wstr)
2206 : PASN_ConstrainedObject(UniversalBMPString, UniversalTagClass)
2208 Construct();
2209 SetValue(wstr);
2213 PASN_BMPString::PASN_BMPString(unsigned tag, TagClass tagClass)
2214 : PASN_ConstrainedObject(tag, tagClass)
2216 Construct();
2220 void PASN_BMPString::Construct()
2222 firstChar = 0;
2223 lastChar = 0xffff;
2224 charSetAlignedBits = 16;
2225 charSetUnalignedBits = 16;
2229 PASN_BMPString::PASN_BMPString(const PASN_BMPString & other)
2230 : PASN_ConstrainedObject(other),
2231 value(other.value, other.value.GetSize()),
2232 characterSet(other.characterSet)
2234 firstChar = other.firstChar;
2235 lastChar = other.lastChar;
2236 charSetAlignedBits = other.charSetAlignedBits;
2237 charSetUnalignedBits = other.charSetUnalignedBits;
2241 PASN_BMPString & PASN_BMPString::operator=(const PASN_BMPString & other)
2243 PASN_ConstrainedObject::operator=(other);
2245 value = PWORDArray(other.value, other.value.GetSize());
2246 characterSet = other.characterSet;
2247 firstChar = other.firstChar;
2248 lastChar = other.lastChar;
2249 charSetAlignedBits = other.charSetAlignedBits;
2250 charSetUnalignedBits = other.charSetUnalignedBits;
2252 return *this;
2256 BOOL PASN_BMPString::IsLegalCharacter(WORD ch)
2258 if (ch < firstChar)
2259 return FALSE;
2261 if (ch > lastChar)
2262 return FALSE;
2264 if (characterSet.IsEmpty())
2265 return TRUE;
2267 const WORD * wptr = characterSet;
2268 PINDEX count = characterSet.GetSize();
2269 while (count-- > 0) {
2270 if (*wptr == ch)
2271 return TRUE;
2272 wptr++;
2275 return FALSE;
2279 PASN_BMPString & PASN_BMPString::operator=(const char * str)
2281 // Must be at least this big for string conversion
2282 value.SetSize(::strlen(str));
2284 // Convert string looking for "&#1234;" style characters for 16 bit stuff
2285 PINDEX count = 0;
2286 while (*str != '\0') {
2287 WORD c = (BYTE)*str++;
2289 if (c == '&' && *str == '#') {
2290 unsigned bigChar = 0;
2291 const char * p = str+1;
2292 while (isdigit(*p))
2293 bigChar = bigChar*10 + *p++ - '0';
2294 if (*p == ';' && bigChar < 65536) {
2295 c = (WORD)bigChar;
2296 str = p + 1;
2300 if (IsLegalCharacter(c))
2301 value[count++] = c;
2304 // Can't have any more than the upper constraint
2305 if ((unsigned)count > upperLimit)
2306 count = upperLimit;
2308 // Number of bytes must be at least lhe lower constraint
2309 PINDEX newSize = (int)count < lowerLimit ? lowerLimit : count;
2310 value.SetSize(newSize);
2312 // Pad out with the first character till required size
2313 while (count < newSize)
2314 value[count++] = firstChar;
2316 return *this;
2320 PASN_BMPString & PASN_BMPString::operator=(const PWORDArray & array)
2322 PINDEX paramSize = array.GetSize();
2324 // Can't copy any more than the upper constraint
2325 if ((unsigned)paramSize > upperLimit)
2326 paramSize = upperLimit;
2328 // Number of bytes must be at least lhe lower constraint
2329 PINDEX newSize = (int)paramSize < lowerLimit ? lowerLimit : paramSize;
2330 value.SetSize(newSize);
2332 PINDEX count = 0;
2333 for (PINDEX i = 0; i < paramSize; i++) {
2334 WORD c = array[i];
2335 if (IsLegalCharacter(c))
2336 value[count++] = c;
2339 // Pad out with the first character till required size
2340 while (count < newSize)
2341 value[count++] = firstChar;
2343 return *this;
2347 PString PASN_BMPString::GetValue() const
2349 PString str;
2350 for (PINDEX i = 0; i < value.GetSize(); i++) {
2351 if (value[i] < 256)
2352 str += (char)value[i];
2353 else
2354 str.sprintf("&#%u;", value[i]);
2356 return str;
2360 void PASN_BMPString::SetCharacterSet(ConstraintType ctype, const char * charSet)
2362 PWORDArray array(strlen(charSet));
2364 PINDEX count = 0;
2365 while (*charSet != '\0')
2366 array[count++] = (BYTE)*charSet++;
2368 SetCharacterSet(ctype, array);
2372 void PASN_BMPString::SetCharacterSet(ConstraintType ctype, const PWORDArray & charSet)
2374 if (ctype == Unconstrained) {
2375 firstChar = 0;
2376 lastChar = 0xffff;
2377 characterSet.SetSize(0);
2379 else {
2380 characterSet = charSet;
2382 charSetUnalignedBits = CountBits(lastChar - firstChar + 1);
2383 if (!charSet.IsEmpty()) {
2384 unsigned count = 0;
2385 for (PINDEX i = 0; i < charSet.GetSize(); i++) {
2386 if (characterSet[i] >= firstChar && characterSet[i] <= lastChar)
2387 count++;
2389 count = CountBits(count);
2390 if (charSetUnalignedBits > count)
2391 charSetUnalignedBits = count;
2394 charSetAlignedBits = 1;
2395 while (charSetUnalignedBits > charSetAlignedBits)
2396 charSetAlignedBits <<= 1;
2398 SetValue(value);
2403 void PASN_BMPString::SetCharacterSet(ConstraintType ctype, unsigned first, unsigned last)
2405 if (ctype != Unconstrained) {
2406 PAssert(first < 0x10000 && last < 0x10000 && last > first, PInvalidParameter);
2407 firstChar = (WORD)first;
2408 lastChar = (WORD)last;
2410 SetCharacterSet(ctype, characterSet);
2414 PObject * PASN_BMPString::Clone() const
2416 PAssert(IsClass(PASN_BMPString::Class()), PInvalidCast);
2417 return new PASN_BMPString(*this);
2421 PObject::Comparison PASN_BMPString::Compare(const PObject & obj) const
2423 PAssert(obj.IsDescendant(PASN_BMPString::Class()), PInvalidCast);
2424 const PASN_BMPString & other = (const PASN_BMPString &)obj;
2425 return value.Compare(other.value);
2429 void PASN_BMPString::PrintOn(ostream & strm) const
2431 int indent = strm.precision() + 2;
2432 PINDEX sz = value.GetSize();
2433 strm << ' ' << sz << " characters {\n";
2434 PINDEX i = 0;
2435 while (i < sz) {
2436 strm << setw(indent) << " " << hex << setfill('0');
2437 PINDEX j;
2438 for (j = 0; j < 8; j++)
2439 if (i+j < sz)
2440 strm << setw(4) << value[i+j] << ' ';
2441 else
2442 strm << " ";
2443 strm << " ";
2444 for (j = 0; j < 8; j++) {
2445 if (i+j < sz) {
2446 WORD c = value[i+j];
2447 if (c < 128 && isprint(c))
2448 strm << (char)c;
2449 else
2450 strm << ' ';
2453 strm << dec << setfill(' ') << '\n';
2454 i += 8;
2456 strm << setw(indent-1) << "}";
2460 PString PASN_BMPString::GetTypeAsString() const
2462 return "BMP String";
2466 PINDEX PASN_BMPString::GetDataLength() const
2468 return value.GetSize()*2;
2472 BOOL PASN_BMPString::Decode(PASN_Stream & strm)
2474 return strm.BMPStringDecode(*this);
2478 void PASN_BMPString::Encode(PASN_Stream & strm) const
2480 strm.BMPStringEncode(*this);
2484 BOOL PASN_BMPString::DecodeBER(PBER_Stream & strm, unsigned len)
2486 value.SetSize(len/2);
2487 return strm.BlockDecode((BYTE *)value.GetPointer(len), len) == len;
2491 void PASN_BMPString::EncodeBER(PBER_Stream & strm) const
2493 strm.BlockEncode((const BYTE *)(const WORD *)value, value.GetSize()*2);
2497 BOOL PASN_BMPString::DecodePER(PPER_Stream & strm)
2499 // X.691 Section 26
2501 unsigned len;
2502 if (ConstrainedLengthDecode(strm, len) < 0)
2503 return FALSE;
2505 value.SetSize(len);
2507 PINDEX nBits = strm.IsAligned() ? charSetAlignedBits : charSetUnalignedBits;
2509 if ((constraint == Unconstrained || upperLimit*nBits > 16) && strm.IsAligned())
2510 strm.ByteAlign();
2512 for (PINDEX i = 0; i < (PINDEX)len; i++) {
2513 unsigned theBits;
2514 if (!strm.MultiBitDecode(nBits, theBits))
2515 return FALSE;
2516 if (characterSet.IsEmpty())
2517 value[i] = (WORD)(theBits + firstChar);
2518 else
2519 value[i] = characterSet[(PINDEX)theBits];
2522 return TRUE;
2526 void PASN_BMPString::EncodePER(PPER_Stream & strm) const
2528 // X.691 Section 26
2530 PINDEX len = value.GetSize();
2531 ConstrainedLengthEncode(strm, len);
2533 PINDEX nBits = strm.IsAligned() ? charSetAlignedBits : charSetUnalignedBits;
2535 if ((constraint == Unconstrained || upperLimit*nBits > 16) && strm.IsAligned())
2536 strm.ByteAlign();
2538 for (PINDEX i = 0; i < len; i++) {
2539 if (characterSet.IsEmpty())
2540 strm.MultiBitEncode(value[i] - firstChar, nBits);
2541 else {
2542 for (PINDEX pos = 0; pos < characterSet.GetSize(); pos++) {
2543 if (characterSet[pos] == value[i]) {
2544 strm.MultiBitEncode(pos, nBits);
2545 break;
2553 BOOL PBER_Stream::BMPStringDecode(PASN_BMPString & value)
2555 unsigned len;
2556 if (!HeaderDecode(value, len))
2557 return FALSE;
2559 return value.DecodeBER(*this, len);
2563 void PBER_Stream::BMPStringEncode(const PASN_BMPString & value)
2565 HeaderEncode(value);
2566 value.EncodeBER(*this);
2570 BOOL PPER_Stream::BMPStringDecode(PASN_BMPString & value)
2572 return value.DecodePER(*this);
2576 void PPER_Stream::BMPStringEncode(const PASN_BMPString & value)
2578 value.EncodePER(*this);
2582 ///////////////////////////////////////////////////////////////////////
2584 PASN_GeneralisedTime & PASN_GeneralisedTime::operator=(const PTime & time)
2586 value = time.AsString("yyyyMMddhhmmss.uz");
2587 value.Replace("GMT", "Z");
2588 return *this;
2592 PTime PASN_GeneralisedTime::GetValue() const
2594 int year = value(0,3).AsInteger();
2595 int month = value(4,5).AsInteger();
2596 int day = value(6,7).AsInteger();
2597 int hour = value(8,9).AsInteger();
2598 int minute = value(10,11).AsInteger();
2599 int seconds = 0;
2600 int zonePos = 12;
2602 if (isdigit(value[12])) {
2603 seconds = value(12,13).AsInteger();
2604 if (value[14] != '.')
2605 zonePos = 14;
2606 else {
2607 zonePos = 15;
2608 while (isdigit(value[zonePos]))
2609 zonePos++;
2613 int zone = PTime::Local;
2614 switch (value[zonePos]) {
2615 case 'Z' :
2616 zone = PTime::UTC;
2617 break;
2618 case '+' :
2619 case '-' :
2620 zone = value(zonePos+1,zonePos+2).AsInteger()*60 +
2621 value(zonePos+3,zonePos+4).AsInteger();
2624 return PTime(seconds, minute, hour, day, month, year, zone);
2628 ///////////////////////////////////////////////////////////////////////
2630 PASN_UniversalTime & PASN_UniversalTime::operator=(const PTime & time)
2632 value = time.AsString("yyMMddhhmmssz");
2633 value.Replace("GMT", "Z");
2634 return *this;
2638 PTime PASN_UniversalTime::GetValue() const
2640 int year = value(0,1).AsInteger();
2641 if (year < 36)
2642 year += 2000;
2643 else
2644 year += 1900;
2646 int month = value(2,3).AsInteger();
2647 int day = value(4,5).AsInteger();
2648 int hour = value(6,7).AsInteger();
2649 int minute = value(8,9).AsInteger();
2650 int seconds = 0;
2651 int zonePos = 10;
2653 if (isdigit(value[10])) {
2654 seconds = value(10,11).AsInteger();
2655 zonePos = 12;
2658 int zone = PTime::UTC;
2659 if (value[zonePos] != 'Z')
2660 zone = value(zonePos+1,zonePos+2).AsInteger()*60 +
2661 value(zonePos+3,zonePos+4).AsInteger();
2663 return PTime(seconds, minute, hour, day, month, year, zone);
2667 ///////////////////////////////////////////////////////////////////////
2669 PASN_Choice::PASN_Choice(unsigned nChoices, BOOL extend)
2670 : PASN_Object(0, ApplicationTagClass, extend)
2672 numChoices = nChoices;
2673 choice = NULL;
2677 PASN_Choice::PASN_Choice(unsigned tag, TagClass tagClass,
2678 unsigned upper, BOOL extend)
2679 : PASN_Object(tag, tagClass, extend)
2681 numChoices = upper;
2682 choice = NULL;
2686 PASN_Choice::PASN_Choice(unsigned tag, TagClass tagClass,
2687 unsigned upper, BOOL extend, const PString & nameSpec)
2688 : PASN_Object(tag, tagClass, extend),
2689 names(BuildNamesDict(nameSpec))
2691 numChoices = upper;
2692 choice = NULL;
2696 PASN_Choice::PASN_Choice(const PASN_Choice & other)
2697 : PASN_Object(other),
2698 names(other.names)
2700 numChoices = other.numChoices;
2702 if (other.choice != NULL)
2703 choice = (PASN_Object *)other.choice->Clone();
2704 else
2705 choice = NULL;
2709 PASN_Choice & PASN_Choice::operator=(const PASN_Choice & other)
2711 delete choice;
2713 PASN_Object::operator=(other);
2715 numChoices = other.numChoices;
2716 names = other.names;
2718 if (other.choice != NULL)
2719 choice = (PASN_Object *)other.choice->Clone();
2720 else
2721 choice = NULL;
2723 return *this;
2727 PASN_Choice::~PASN_Choice()
2729 delete choice;
2733 void PASN_Choice::SetTag(unsigned newTag, TagClass tagClass)
2735 PASN_Object::SetTag(newTag, tagClass);
2737 delete choice;
2739 if (CreateObject())
2740 choice->SetTag(newTag, tagClass);
2744 PString PASN_Choice::GetTagName() const
2746 if (tag == UINT_MAX)
2747 return "<uninitialised>";
2749 if (names.Contains(tag))
2750 return names[tag];
2752 if (choice != NULL && choice->IsDescendant(PASN_Choice::Class()) &&
2753 choice->GetTag() == tag && choice->GetTagClass() == tagClass)
2754 return PString(choice->GetClass()) + "->" + ((PASN_Choice *)choice)->GetTagName();
2756 return psprintf("<%u>", tag);
2760 PASN_Object & PASN_Choice::GetObject() const
2762 PAssert(choice != NULL, "NULL Choice");
2763 return *choice;
2767 #if defined(__GNUC__) && __GNUC__ <= 2 && __GNUC_MINOR__ < 9
2769 PASN_Choice::operator PASN_Null &() const
2771 PAssert(PAssertNULL(choice)->IsDescendant(PASN_Null::Class()), PInvalidCast);
2772 return *(PASN_Null *)choice;
2776 PASN_Choice::operator PASN_Boolean &() const
2778 PAssert(PAssertNULL(choice)->IsDescendant(PASN_Boolean::Class()), PInvalidCast);
2779 return *(PASN_Boolean *)choice;
2783 PASN_Choice::operator PASN_Integer &() const
2785 PAssert(PAssertNULL(choice)->IsDescendant(PASN_Integer::Class()), PInvalidCast);
2786 return *(PASN_Integer *)choice;
2790 PASN_Choice::operator PASN_Enumeration &() const
2792 PAssert(PAssertNULL(choice)->IsDescendant(PASN_Enumeration::Class()), PInvalidCast);
2793 return *(PASN_Enumeration *)choice;
2797 PASN_Choice::operator PASN_Real &() const
2799 PAssert(PAssertNULL(choice)->IsDescendant(PASN_Real::Class()), PInvalidCast);
2800 return *(PASN_Real *)choice;
2804 PASN_Choice::operator PASN_ObjectId &() const
2806 PAssert(PAssertNULL(choice)->IsDescendant(PASN_ObjectId::Class()), PInvalidCast);
2807 return *(PASN_ObjectId *)choice;
2811 PASN_Choice::operator PASN_BitString &() const
2813 PAssert(PAssertNULL(choice)->IsDescendant(PASN_BitString::Class()), PInvalidCast);
2814 return *(PASN_BitString *)choice;
2818 PASN_Choice::operator PASN_OctetString &() const
2820 PAssert(PAssertNULL(choice)->IsDescendant(PASN_OctetString::Class()), PInvalidCast);
2821 return *(PASN_OctetString *)choice;
2825 PASN_Choice::operator PASN_NumericString &() const
2827 PAssert(PAssertNULL(choice)->IsDescendant(PASN_NumericString::Class()), PInvalidCast);
2828 return *(PASN_NumericString *)choice;
2832 PASN_Choice::operator PASN_PrintableString &() const
2834 PAssert(PAssertNULL(choice)->IsDescendant(PASN_PrintableString::Class()), PInvalidCast);
2835 return *(PASN_PrintableString *)choice;
2839 PASN_Choice::operator PASN_VisibleString &() const
2841 PAssert(PAssertNULL(choice)->IsDescendant(PASN_VisibleString::Class()), PInvalidCast);
2842 return *(PASN_VisibleString *)choice;
2846 PASN_Choice::operator PASN_IA5String &() const
2848 PAssert(PAssertNULL(choice)->IsDescendant(PASN_IA5String::Class()), PInvalidCast);
2849 return *(PASN_IA5String *)choice;
2853 PASN_Choice::operator PASN_GeneralString &() const
2855 PAssert(PAssertNULL(choice)->IsDescendant(PASN_GeneralString::Class()), PInvalidCast);
2856 return *(PASN_GeneralString *)choice;
2860 PASN_Choice::operator PASN_BMPString &() const
2862 PAssert(PAssertNULL(choice)->IsDescendant(PASN_BMPString::Class()), PInvalidCast);
2863 return *(PASN_BMPString *)choice;
2867 PASN_Choice::operator PASN_Sequence &() const
2869 PAssert(PAssertNULL(choice)->IsDescendant(PASN_Sequence::Class()), PInvalidCast);
2870 return *(PASN_Sequence *)choice;
2874 #else
2877 PASN_Choice::operator PASN_Null &()
2879 PAssert(PAssertNULL(choice)->IsDescendant(PASN_Null::Class()), PInvalidCast);
2880 return *(PASN_Null *)choice;
2884 PASN_Choice::operator PASN_Boolean &()
2886 PAssert(PAssertNULL(choice)->IsDescendant(PASN_Boolean::Class()), PInvalidCast);
2887 return *(PASN_Boolean *)choice;
2891 PASN_Choice::operator PASN_Integer &()
2893 PAssert(PAssertNULL(choice)->IsDescendant(PASN_Integer::Class()), PInvalidCast);
2894 return *(PASN_Integer *)choice;
2898 PASN_Choice::operator PASN_Enumeration &()
2900 PAssert(PAssertNULL(choice)->IsDescendant(PASN_Enumeration::Class()), PInvalidCast);
2901 return *(PASN_Enumeration *)choice;
2905 PASN_Choice::operator PASN_Real &()
2907 PAssert(PAssertNULL(choice)->IsDescendant(PASN_Real::Class()), PInvalidCast);
2908 return *(PASN_Real *)choice;
2912 PASN_Choice::operator PASN_ObjectId &()
2914 PAssert(PAssertNULL(choice)->IsDescendant(PASN_ObjectId::Class()), PInvalidCast);
2915 return *(PASN_ObjectId *)choice;
2919 PASN_Choice::operator PASN_BitString &()
2921 PAssert(PAssertNULL(choice)->IsDescendant(PASN_BitString::Class()), PInvalidCast);
2922 return *(PASN_BitString *)choice;
2926 PASN_Choice::operator PASN_OctetString &()
2928 PAssert(PAssertNULL(choice)->IsDescendant(PASN_OctetString::Class()), PInvalidCast);
2929 return *(PASN_OctetString *)choice;
2933 PASN_Choice::operator PASN_NumericString &()
2935 PAssert(PAssertNULL(choice)->IsDescendant(PASN_NumericString::Class()), PInvalidCast);
2936 return *(PASN_NumericString *)choice;
2940 PASN_Choice::operator PASN_PrintableString &()
2942 PAssert(PAssertNULL(choice)->IsDescendant(PASN_PrintableString::Class()), PInvalidCast);
2943 return *(PASN_PrintableString *)choice;
2947 PASN_Choice::operator PASN_VisibleString &()
2949 PAssert(PAssertNULL(choice)->IsDescendant(PASN_VisibleString::Class()), PInvalidCast);
2950 return *(PASN_VisibleString *)choice;
2954 PASN_Choice::operator PASN_IA5String &()
2956 PAssert(PAssertNULL(choice)->IsDescendant(PASN_IA5String::Class()), PInvalidCast);
2957 return *(PASN_IA5String *)choice;
2961 PASN_Choice::operator PASN_GeneralString &()
2963 PAssert(PAssertNULL(choice)->IsDescendant(PASN_GeneralString::Class()), PInvalidCast);
2964 return *(PASN_GeneralString *)choice;
2968 PASN_Choice::operator PASN_BMPString &()
2970 PAssert(PAssertNULL(choice)->IsDescendant(PASN_BMPString::Class()), PInvalidCast);
2971 return *(PASN_BMPString *)choice;
2975 PASN_Choice::operator PASN_Sequence &()
2977 PAssert(PAssertNULL(choice)->IsDescendant(PASN_Sequence::Class()), PInvalidCast);
2978 return *(PASN_Sequence *)choice;
2982 PASN_Choice::operator const PASN_Null &() const
2984 PAssert(PAssertNULL(choice)->IsDescendant(PASN_Null::Class()), PInvalidCast);
2985 return *(const PASN_Null *)choice;
2989 PASN_Choice::operator const PASN_Boolean &() const
2991 PAssert(PAssertNULL(choice)->IsDescendant(PASN_Boolean::Class()), PInvalidCast);
2992 return *(const PASN_Boolean *)choice;
2996 PASN_Choice::operator const PASN_Integer &() const
2998 PAssert(PAssertNULL(choice)->IsDescendant(PASN_Integer::Class()), PInvalidCast);
2999 return *(const PASN_Integer *)choice;
3003 PASN_Choice::operator const PASN_Enumeration &() const
3005 PAssert(PAssertNULL(choice)->IsDescendant(PASN_Enumeration::Class()), PInvalidCast);
3006 return *(const PASN_Enumeration *)choice;
3010 PASN_Choice::operator const PASN_Real &() const
3012 PAssert(PAssertNULL(choice)->IsDescendant(PASN_Real::Class()), PInvalidCast);
3013 return *(const PASN_Real *)choice;
3017 PASN_Choice::operator const PASN_ObjectId &() const
3019 PAssert(PAssertNULL(choice)->IsDescendant(PASN_ObjectId::Class()), PInvalidCast);
3020 return *(const PASN_ObjectId *)choice;
3024 PASN_Choice::operator const PASN_BitString &() const
3026 PAssert(PAssertNULL(choice)->IsDescendant(PASN_BitString::Class()), PInvalidCast);
3027 return *(const PASN_BitString *)choice;
3031 PASN_Choice::operator const PASN_OctetString &() const
3033 PAssert(PAssertNULL(choice)->IsDescendant(PASN_OctetString::Class()), PInvalidCast);
3034 return *(const PASN_OctetString *)choice;
3038 PASN_Choice::operator const PASN_NumericString &() const
3040 PAssert(PAssertNULL(choice)->IsDescendant(PASN_NumericString::Class()), PInvalidCast);
3041 return *(const PASN_NumericString *)choice;
3045 PASN_Choice::operator const PASN_PrintableString &() const
3047 PAssert(PAssertNULL(choice)->IsDescendant(PASN_PrintableString::Class()), PInvalidCast);
3048 return *(const PASN_PrintableString *)choice;
3052 PASN_Choice::operator const PASN_VisibleString &() const
3054 PAssert(PAssertNULL(choice)->IsDescendant(PASN_VisibleString::Class()), PInvalidCast);
3055 return *(const PASN_VisibleString *)choice;
3059 PASN_Choice::operator const PASN_IA5String &() const
3061 PAssert(PAssertNULL(choice)->IsDescendant(PASN_IA5String::Class()), PInvalidCast);
3062 return *(const PASN_IA5String *)choice;
3066 PASN_Choice::operator const PASN_GeneralString &() const
3068 PAssert(PAssertNULL(choice)->IsDescendant(PASN_GeneralString::Class()), PInvalidCast);
3069 return *(const PASN_GeneralString *)choice;
3073 PASN_Choice::operator const PASN_BMPString &() const
3075 PAssert(PAssertNULL(choice)->IsDescendant(PASN_BMPString::Class()), PInvalidCast);
3076 return *(const PASN_BMPString *)choice;
3080 PASN_Choice::operator const PASN_Sequence &() const
3082 PAssert(PAssertNULL(choice)->IsDescendant(PASN_Sequence::Class()), PInvalidCast);
3083 return *(const PASN_Sequence *)choice;
3087 #endif
3090 PObject::Comparison PASN_Choice::Compare(const PObject & obj) const
3092 PAssert(obj.IsDescendant(PASN_Choice::Class()), PInvalidCast);
3093 const PASN_Choice & other = (const PASN_Choice &)obj;
3095 if (choice == other.choice)
3096 return EqualTo;
3098 if (choice == NULL)
3099 return LessThan;
3101 if (other.choice == NULL)
3102 return GreaterThan;
3104 if (tag < other.tag)
3105 return LessThan;
3107 if (tag > other.tag)
3108 return GreaterThan;
3110 return choice->Compare(*other.choice);
3114 void PASN_Choice::PrintOn(ostream & strm) const
3116 strm << GetTagName();
3118 if (choice != NULL)
3119 strm << ' ' << *choice;
3120 else
3121 strm << " (NULL)";
3125 PString PASN_Choice::GetTypeAsString() const
3127 return "Choice";
3131 PINDEX PASN_Choice::GetDataLength() const
3133 if (choice != NULL)
3134 return choice->GetDataLength();
3135 return 0;
3139 BOOL PASN_Choice::IsPrimitive() const
3141 if (choice != NULL)
3142 return choice->IsPrimitive();
3143 return FALSE;
3147 BOOL PASN_Choice::Decode(PASN_Stream & strm)
3149 return strm.ChoiceDecode(*this);
3153 void PASN_Choice::Encode(PASN_Stream & strm) const
3155 strm.ChoiceEncode(*this);
3159 BOOL PASN_Choice::DecodePER(PPER_Stream & strm)
3161 // X.691 Section 22
3162 delete choice;
3164 if (strm.IsAtEnd()) {
3165 choice = NULL;
3166 return FALSE;
3169 BOOL ok = TRUE;
3171 if (extendable) {
3172 if (strm.SingleBitDecode()) {
3173 if (!strm.SmallUnsignedDecode(tag))
3174 return FALSE;
3175 tag += numChoices;
3176 unsigned len;
3177 if (strm.LengthDecode(0, INT_MAX, len) != 0)
3178 return FALSE;
3179 if (CreateObject()) {
3180 PINDEX nextPos = strm.GetPosition() + len;
3181 ok = choice->Decode(strm);
3182 strm.SetPosition(nextPos);
3184 else {
3185 PASN_OctetString * open_type = new PASN_OctetString;
3186 open_type->SetConstraints(PASN_ConstrainedObject::FixedConstraint, len);
3187 open_type->Decode(strm);
3188 if (open_type->GetSize() > 0)
3189 choice = open_type;
3190 else {
3191 delete open_type;
3192 ok = FALSE;
3195 return ok;
3199 if (numChoices < 2)
3200 tag = 0;
3201 else {
3202 if (strm.UnsignedDecode(0, numChoices-1, tag) < 0)
3203 return FALSE;
3206 if (CreateObject())
3207 ok = choice->Decode(strm);
3209 return ok;
3213 void PASN_Choice::EncodePER(PPER_Stream & strm) const
3215 PAssert(tag != UINT_MAX, PLogicError);
3217 if (extendable) {
3218 BOOL extended = tag >= numChoices;
3219 strm.SingleBitEncode(extended);
3220 if (extended) {
3221 strm.SmallUnsignedEncode(tag - numChoices);
3222 strm.AnyTypeEncode(choice);
3223 return;
3227 if (numChoices > 1)
3228 strm.UnsignedEncode(tag, 0, numChoices-1);
3230 if (choice != NULL)
3231 choice->Encode(strm);
3235 BOOL PBER_Stream::ChoiceDecode(PASN_Choice & value)
3237 PINDEX savedPosition = GetPosition();
3239 unsigned tag;
3240 PASN_Object::TagClass tagClass;
3241 BOOL primitive;
3242 unsigned entryLen;
3243 if (!HeaderDecode(tag, tagClass, primitive, entryLen))
3244 return FALSE;
3246 SetPosition(savedPosition);
3248 value.SetTag(tag, tagClass);
3249 if (value.IsValid())
3250 return value.GetObject().Decode(*this);
3252 return TRUE;
3256 void PBER_Stream::ChoiceEncode(const PASN_Choice & value)
3258 if (value.IsValid())
3259 value.GetObject().Encode(*this);
3263 BOOL PPER_Stream::ChoiceDecode(PASN_Choice & value)
3265 return value.DecodePER(*this);
3269 void PPER_Stream::ChoiceEncode(const PASN_Choice & value)
3271 value.EncodePER(*this);
3275 ///////////////////////////////////////////////////////////////////////
3277 PASN_Sequence::PASN_Sequence(unsigned tag, TagClass tagClass,
3278 unsigned nOpts, BOOL extend, unsigned nExtend)
3279 : PASN_Object(tag, tagClass, extend)
3281 optionMap.SetConstraints(PASN_ConstrainedObject::FixedConstraint, nOpts);
3282 knownExtensions = nExtend;
3283 totalExtensions = 0;
3284 endBasicEncoding = 0;
3288 PASN_Sequence::PASN_Sequence(const PASN_Sequence & other)
3289 : PASN_Object(other),
3290 fields(other.fields.GetSize()),
3291 optionMap(other.optionMap),
3292 extensionMap(other.extensionMap)
3294 for (PINDEX i = 0; i < other.fields.GetSize(); i++)
3295 fields.SetAt(i, other.fields[i].Clone());
3297 knownExtensions = other.knownExtensions;
3298 totalExtensions = other.totalExtensions;
3299 endBasicEncoding = 0;
3303 PASN_Sequence & PASN_Sequence::operator=(const PASN_Sequence & other)
3305 PASN_Object::operator=(other);
3307 fields.SetSize(other.fields.GetSize());
3308 for (PINDEX i = 0; i < other.fields.GetSize(); i++)
3309 fields.SetAt(i, other.fields[i].Clone());
3311 optionMap = other.optionMap;
3312 knownExtensions = other.knownExtensions;
3313 totalExtensions = other.totalExtensions;
3314 extensionMap = other.extensionMap;
3316 return *this;
3320 BOOL PASN_Sequence::HasOptionalField(PINDEX opt) const
3322 if (opt < (PINDEX)optionMap.GetSize())
3323 return optionMap[opt];
3324 else
3325 return extensionMap[opt - optionMap.GetSize()];
3329 void PASN_Sequence::IncludeOptionalField(PINDEX opt)
3331 if (opt < (PINDEX)optionMap.GetSize())
3332 optionMap.Set(opt);
3333 else {
3334 PAssert(extendable, "Must be extendable type");
3335 opt -= optionMap.GetSize();
3336 if (opt >= (PINDEX)extensionMap.GetSize())
3337 extensionMap.SetSize(opt+1);
3338 extensionMap.Set(opt);
3343 void PASN_Sequence::RemoveOptionalField(PINDEX opt)
3345 if (opt < (PINDEX)optionMap.GetSize())
3346 optionMap.Clear(opt);
3347 else {
3348 PAssert(extendable, "Must be extendable type");
3349 opt -= optionMap.GetSize();
3350 extensionMap.Clear(opt);
3355 PObject::Comparison PASN_Sequence::Compare(const PObject & obj) const
3357 PAssert(obj.IsDescendant(PASN_Sequence::Class()), PInvalidCast);
3358 const PASN_Sequence & other = (const PASN_Sequence &)obj;
3359 return fields.Compare(other.fields);
3363 PObject * PASN_Sequence::Clone() const
3365 PAssert(IsClass(PASN_Sequence::Class()), PInvalidCast);
3366 return new PASN_Sequence(*this);
3370 void PASN_Sequence::PrintOn(ostream & strm) const
3372 int indent = strm.precision() + 2;
3373 strm << "{\n";
3374 for (PINDEX i = 0; i < fields.GetSize(); i++) {
3375 strm << setw(indent+6) << "field[" << i << "] <";
3376 switch (fields[i].GetTagClass()) {
3377 case UniversalTagClass :
3378 strm << "Universal";
3379 break;
3380 case ApplicationTagClass :
3381 strm << "Application";
3382 break;
3383 case ContextSpecificTagClass :
3384 strm << "ContextSpecific";
3385 break;
3386 case PrivateTagClass :
3387 strm << "Private";
3388 default :
3389 break;
3391 strm << '-' << fields[i].GetTag() << '-'
3392 << fields[i].GetTypeAsString() << "> = "
3393 << fields[i] << '\n';
3395 strm << setw(indent-1) << "}";
3399 PString PASN_Sequence::GetTypeAsString() const
3401 return "Sequence";
3405 PINDEX PASN_Sequence::GetDataLength() const
3407 PINDEX len = 0;
3408 for (PINDEX i = 0; i < fields.GetSize(); i++)
3409 len += fields[i].GetObjectLength();
3410 return len;
3414 BOOL PASN_Sequence::IsPrimitive() const
3416 return FALSE;
3420 BOOL PASN_Sequence::Decode(PASN_Stream & strm)
3422 return PreambleDecode(strm) && UnknownExtensionsDecode(strm);
3426 void PASN_Sequence::Encode(PASN_Stream & strm) const
3428 PreambleEncode(strm);
3429 UnknownExtensionsEncode(strm);
3433 BOOL PASN_Sequence::PreambleDecode(PASN_Stream & strm)
3435 return strm.SequencePreambleDecode(*this);
3439 void PASN_Sequence::PreambleEncode(PASN_Stream & strm) const
3441 strm.SequencePreambleEncode(*this);
3445 BOOL PASN_Sequence::KnownExtensionDecode(PASN_Stream & strm, PINDEX fld, PASN_Object & field)
3447 return strm.SequenceKnownDecode(*this, fld, field);
3451 void PASN_Sequence::KnownExtensionEncode(PASN_Stream & strm, PINDEX fld, const PASN_Object & field) const
3453 strm.SequenceKnownEncode(*this, fld, field);
3457 BOOL PASN_Sequence::UnknownExtensionsDecode(PASN_Stream & strm)
3459 return strm.SequenceUnknownDecode(*this);
3463 void PASN_Sequence::UnknownExtensionsEncode(PASN_Stream & strm) const
3465 strm.SequenceUnknownEncode(*this);
3469 BOOL PASN_Sequence::PreambleDecodeBER(PBER_Stream & strm)
3471 fields.RemoveAll();
3473 unsigned len;
3474 if (!strm.HeaderDecode(*this, len))
3475 return FALSE;
3477 endBasicEncoding = strm.GetPosition() + len;
3478 return !strm.IsAtEnd();
3482 void PASN_Sequence::PreambleEncodeBER(PBER_Stream & strm) const
3484 strm.HeaderEncode(*this);
3488 BOOL PASN_Sequence::KnownExtensionDecodeBER(PBER_Stream & strm, PINDEX, PASN_Object & field)
3490 if (strm.GetPosition() >= endBasicEncoding)
3491 return FALSE;
3493 return field.Decode(strm);
3497 void PASN_Sequence::KnownExtensionEncodeBER(PBER_Stream & strm, PINDEX, const PASN_Object & field) const
3499 field.Encode(strm);
3503 BOOL PASN_Sequence::UnknownExtensionsDecodeBER(PBER_Stream & strm)
3505 while (strm.GetPosition() < endBasicEncoding) {
3506 PINDEX savedPosition = strm.GetPosition();
3508 unsigned tag;
3509 PASN_Object::TagClass tagClass;
3510 BOOL primitive;
3511 unsigned entryLen;
3512 if (!strm.HeaderDecode(tag, tagClass, primitive, entryLen))
3513 return FALSE;
3515 PINDEX nextEntryPosition = strm.GetPosition() + entryLen;
3516 strm.SetPosition(savedPosition);
3518 PASN_Object * obj = strm.CreateObject(tag, tagClass, primitive);
3519 if (obj == NULL)
3520 strm.SetPosition(nextEntryPosition);
3521 else {
3522 if (!obj->Decode(strm))
3523 return FALSE;
3525 fields.Append(obj);
3529 return TRUE;
3533 void PASN_Sequence::UnknownExtensionsEncodeBER(PBER_Stream & strm) const
3535 for (PINDEX i = 0; i < fields.GetSize(); i++)
3536 fields[i].Encode(strm);
3540 BOOL PASN_Sequence::PreambleDecodePER(PPER_Stream & strm)
3542 // X.691 Section 18
3544 if (extendable) {
3545 if (strm.IsAtEnd())
3546 return FALSE;
3547 totalExtensions = strm.SingleBitDecode() ? -1 : 0; // 18.1
3549 else
3550 totalExtensions = 0;
3551 return optionMap.Decode(strm); // 18.2
3555 void PASN_Sequence::PreambleEncodePER(PPER_Stream & strm) const
3557 // X.691 Section 18
3559 if (extendable) {
3560 BOOL hasExtensions = FALSE;
3561 for (unsigned i = 0; i < extensionMap.GetSize(); i++) {
3562 if (extensionMap[i]) {
3563 hasExtensions = TRUE;
3564 break;
3567 strm.SingleBitEncode(hasExtensions); // 18.1
3568 ((PASN_Sequence*)this)->totalExtensions = hasExtensions ? -1 : 0;
3570 optionMap.Encode(strm); // 18.2
3574 BOOL PASN_Sequence::NoExtensionsToDecode(PPER_Stream & strm)
3576 if (totalExtensions == 0)
3577 return TRUE;
3579 if (totalExtensions < 0) {
3580 if (!extensionMap.DecodeSequenceExtensionBitmap(strm))
3581 return FALSE;
3582 totalExtensions = extensionMap.GetSize();
3585 return FALSE;
3589 BOOL PASN_Sequence::NoExtensionsToEncode(PPER_Stream & strm)
3591 if (totalExtensions == 0)
3592 return TRUE;
3594 if (totalExtensions < 0) {
3595 totalExtensions = extensionMap.GetSize();
3596 extensionMap.EncodeSequenceExtensionBitmap(strm);
3599 return FALSE;
3603 BOOL PASN_Sequence::KnownExtensionDecodePER(PPER_Stream & strm, PINDEX fld, PASN_Object & field)
3605 if (NoExtensionsToDecode(strm))
3606 return TRUE;
3608 if (!extensionMap[fld-optionMap.GetSize()])
3609 return TRUE;
3611 unsigned len;
3612 if (strm.LengthDecode(0, INT_MAX, len) != 0)
3613 return FALSE;
3615 PINDEX nextExtensionPosition = strm.GetPosition() + len;
3616 BOOL ok = field.Decode(strm);
3617 strm.SetPosition(nextExtensionPosition);
3618 return ok;
3622 void PASN_Sequence::KnownExtensionEncodePER(PPER_Stream & strm, PINDEX fld, const PASN_Object & field) const
3624 if (((PASN_Sequence*)this)->NoExtensionsToEncode(strm))
3625 return;
3627 if (!extensionMap[fld-optionMap.GetSize()])
3628 return;
3630 strm.AnyTypeEncode(&field);
3634 BOOL PASN_Sequence::UnknownExtensionsDecodePER(PPER_Stream & strm)
3636 if (NoExtensionsToDecode(strm))
3637 return TRUE;
3639 if (totalExtensions <= knownExtensions)
3640 return TRUE; // Already read them
3642 PINDEX unknownCount = totalExtensions - knownExtensions;
3643 if (fields.GetSize() >= unknownCount)
3644 return TRUE; // Already read them
3646 fields.SetSize(unknownCount);
3648 PINDEX i;
3649 for (i = 0; i < fields.GetSize(); i++)
3650 fields.SetAt(i, new PASN_OctetString);
3652 for (i = knownExtensions; i < (PINDEX)extensionMap.GetSize(); i++) {
3653 if (extensionMap[i])
3654 if (!fields[i-knownExtensions].Decode(strm))
3655 return FALSE;
3658 return TRUE;
3662 void PASN_Sequence::UnknownExtensionsEncodePER(PPER_Stream & strm) const
3664 if (((PASN_Sequence*)this)->NoExtensionsToEncode(strm))
3665 return;
3667 int i;
3668 for (i = knownExtensions; i < totalExtensions; i++) {
3669 if (extensionMap[i])
3670 fields[i-knownExtensions].Encode(strm);
3675 BOOL PBER_Stream::SequencePreambleDecode(PASN_Sequence & seq)
3677 return seq.PreambleDecodeBER(*this);
3681 void PBER_Stream::SequencePreambleEncode(const PASN_Sequence & seq)
3683 seq.PreambleEncodeBER(*this);
3687 BOOL PBER_Stream::SequenceKnownDecode(PASN_Sequence & seq, PINDEX fld, PASN_Object & field)
3689 return seq.KnownExtensionDecodeBER(*this, fld, field);
3693 void PBER_Stream::SequenceKnownEncode(const PASN_Sequence & seq, PINDEX fld, const PASN_Object & field)
3695 seq.KnownExtensionEncodeBER(*this, fld, field);
3699 BOOL PBER_Stream::SequenceUnknownDecode(PASN_Sequence & seq)
3701 return seq.UnknownExtensionsDecodeBER(*this);
3705 void PBER_Stream::SequenceUnknownEncode(const PASN_Sequence & seq)
3707 seq.UnknownExtensionsEncodeBER(*this);
3711 BOOL PPER_Stream::SequencePreambleDecode(PASN_Sequence & seq)
3713 return seq.PreambleDecodePER(*this);
3717 void PPER_Stream::SequencePreambleEncode(const PASN_Sequence & seq)
3719 seq.PreambleEncodePER(*this);
3723 BOOL PPER_Stream::SequenceKnownDecode(PASN_Sequence & seq, PINDEX fld, PASN_Object & field)
3725 return seq.KnownExtensionDecodePER(*this, fld, field);
3729 void PPER_Stream::SequenceKnownEncode(const PASN_Sequence & seq, PINDEX fld, const PASN_Object & field)
3731 seq.KnownExtensionEncodePER(*this, fld, field);
3735 BOOL PPER_Stream::SequenceUnknownDecode(PASN_Sequence & seq)
3737 return seq.UnknownExtensionsDecodePER(*this);
3741 void PPER_Stream::SequenceUnknownEncode(const PASN_Sequence & seq)
3743 seq.UnknownExtensionsEncodePER(*this);
3747 ///////////////////////////////////////////////////////////////////////
3749 PASN_Set::PASN_Set(unsigned tag, TagClass tagClass,
3750 unsigned nOpts, BOOL extend, unsigned nExtend)
3751 : PASN_Sequence(tag, tagClass, nOpts, extend, nExtend)
3756 PObject * PASN_Set::Clone() const
3758 PAssert(IsClass(PASN_Set::Class()), PInvalidCast);
3759 return new PASN_Set(*this);
3763 PString PASN_Set::GetTypeAsString() const
3765 return "Set";
3769 ///////////////////////////////////////////////////////////////////////
3771 PASN_Array::PASN_Array(unsigned tag, TagClass tagClass)
3772 : PASN_ConstrainedObject(tag, tagClass)
3777 PASN_Array::PASN_Array(const PASN_Array & other)
3778 : PASN_ConstrainedObject(other),
3779 array(other.array.GetSize())
3781 for (PINDEX i = 0; i < other.array.GetSize(); i++)
3782 array.SetAt(i, other.array[i].Clone());
3786 PASN_Array & PASN_Array::operator=(const PASN_Array & other)
3788 PASN_ConstrainedObject::operator=(other);
3790 array.SetSize(other.array.GetSize());
3791 for (PINDEX i = 0; i < other.array.GetSize(); i++)
3792 array.SetAt(i, other.array[i].Clone());
3794 return *this;
3798 void PASN_Array::SetSize(PINDEX newSize)
3800 PINDEX originalSize = array.GetSize();
3801 array.SetSize(newSize);
3802 for (PINDEX i = originalSize; i < newSize; i++)
3803 array.SetAt(i, CreateObject());
3807 PObject::Comparison PASN_Array::Compare(const PObject & obj) const
3809 PAssert(obj.IsDescendant(PASN_Array::Class()), PInvalidCast);
3810 const PASN_Array & other = (const PASN_Array &)obj;
3811 return array.Compare(other.array);
3815 void PASN_Array::PrintOn(ostream & strm) const
3817 int indent = strm.precision() + 2;
3818 strm << array.GetSize() << " entries {\n";
3819 for (PINDEX i = 0; i < array.GetSize(); i++)
3820 strm << setw(indent+1) << "[" << i << "]=" << setprecision(indent) << array[i] << '\n';
3821 strm << setw(indent-1) << "}";
3825 void PASN_Array::SetConstraintBounds(ConstraintType type, int lower, unsigned upper)
3827 PAssert(lower >= 0, PInvalidParameter);
3828 PASN_ConstrainedObject::SetConstraintBounds(type, lower, upper);
3829 if (constraint != Unconstrained) {
3830 if (GetSize() < (PINDEX)lowerLimit)
3831 SetSize(lowerLimit);
3832 else if (GetSize() > (PINDEX)upperLimit)
3833 SetSize(upperLimit);
3838 PString PASN_Array::GetTypeAsString() const
3840 return "Array";
3844 PINDEX PASN_Array::GetDataLength() const
3846 PINDEX len = 0;
3847 for (PINDEX i = 0; i < array.GetSize(); i++)
3848 len += array[i].GetObjectLength();
3849 return len;
3853 BOOL PASN_Array::IsPrimitive() const
3855 return FALSE;
3859 BOOL PASN_Array::Decode(PASN_Stream & strm)
3861 return strm.ArrayDecode(*this);
3865 void PASN_Array::Encode(PASN_Stream & strm) const
3867 strm.ArrayEncode(*this);
3871 BOOL PBER_Stream::ArrayDecode(PASN_Array & array)
3873 array.RemoveAll();
3875 unsigned len;
3876 if (!HeaderDecode(array, len))
3877 return FALSE;
3879 PINDEX endOffset = byteOffset + len;
3880 PINDEX count = 0;
3881 while (byteOffset < endOffset) {
3882 array.SetSize(count+1);
3883 if (!array[count].Decode(*this))
3884 return FALSE;
3885 count++;
3888 byteOffset = endOffset;
3890 return TRUE;
3894 void PBER_Stream::ArrayEncode(const PASN_Array & array)
3896 HeaderEncode(array);
3897 for (PINDEX i = 0; i < array.GetSize(); i++)
3898 array[i].Encode(*this);
3902 BOOL PPER_Stream::ArrayDecode(PASN_Array & array)
3904 array.RemoveAll();
3906 unsigned size;
3907 if (array.ConstrainedLengthDecode(*this, size) < 0)
3908 return FALSE;
3910 array.SetSize(size);
3912 for (PINDEX i = 0; i < (PINDEX)size; i++) {
3913 if (!array[i].Decode(*this))
3914 return FALSE;
3917 return TRUE;
3921 void PPER_Stream::ArrayEncode(const PASN_Array & array)
3923 PINDEX size = array.GetSize();
3924 array.ConstrainedLengthEncode(*this, size);
3925 for (PINDEX i = 0; i < size; i++)
3926 array[i].Encode(*this);
3930 ///////////////////////////////////////////////////////////////////////
3932 PASN_Stream::PASN_Stream()
3934 Construct();
3938 PASN_Stream::PASN_Stream(const PBYTEArray & bytes)
3939 : PBYTEArray(bytes)
3941 Construct();
3945 PASN_Stream::PASN_Stream(const BYTE * buf, PINDEX size)
3946 : PBYTEArray(buf, size)
3948 Construct();
3952 void PASN_Stream::Construct()
3954 byteOffset = 0;
3955 bitOffset = 8;
3959 void PASN_Stream::PrintOn(ostream & strm) const
3961 int indent = strm.precision() + 2;
3962 strm << " size=" << GetSize()
3963 << " pos=" << byteOffset << '.' << (8-bitOffset)
3964 << " {\n";
3965 PINDEX i = 0;
3966 while (i < GetSize()) {
3967 strm << setw(indent) << " " << hex << setfill('0');
3968 PINDEX j;
3969 for (j = 0; j < 16; j++)
3970 if (i+j < GetSize())
3971 strm << setw(2) << (unsigned)(BYTE)theArray[i+j] << ' ';
3972 else
3973 strm << " ";
3974 strm << " ";
3975 for (j = 0; j < 16; j++) {
3976 if (i+j < GetSize()) {
3977 if (isprint(theArray[i+j]))
3978 strm << theArray[i+j];
3979 else
3980 strm << ' ';
3983 strm << dec << setfill(' ') << '\n';
3984 i += 16;
3986 strm << setw(indent-1) << "}";
3990 void PASN_Stream::SetPosition(PINDEX newPos)
3992 PAssert(byteOffset != P_MAX_INDEX, PLogicError);
3994 if (newPos > GetSize())
3995 byteOffset = GetSize();
3996 else
3997 byteOffset = newPos;
3998 bitOffset = 8;
4002 void PASN_Stream::ResetDecoder()
4004 byteOffset = 0;
4005 bitOffset = 8;
4009 void PASN_Stream::BeginEncoding()
4011 bitOffset = 8;
4012 byteOffset = 0;
4013 PBYTEArray::operator=(PBYTEArray(20));
4017 void PASN_Stream::CompleteEncoding()
4019 if (byteOffset != P_MAX_INDEX) {
4020 if (bitOffset != 8) {
4021 bitOffset = 8;
4022 byteOffset++;
4024 SetSize(byteOffset);
4025 byteOffset = P_MAX_INDEX;
4030 BYTE PASN_Stream::ByteDecode()
4032 if (byteOffset >= GetSize())
4033 return 0;
4035 bitOffset = 8;
4036 return theArray[byteOffset++];
4040 void PASN_Stream::ByteEncode(unsigned value)
4042 PAssert(byteOffset != P_MAX_INDEX, PLogicError);
4044 if (bitOffset != 8) {
4045 bitOffset = 8;
4046 byteOffset++;
4048 if (byteOffset >= GetSize())
4049 SetSize(byteOffset+10);
4050 theArray[byteOffset++] = (BYTE)value;
4054 unsigned PASN_Stream::BlockDecode(BYTE * bufptr, unsigned nBytes)
4056 if (nBytes == 0)
4057 return 0;
4059 ByteAlign();
4061 if (byteOffset+nBytes > (unsigned)GetSize()) {
4062 nBytes = GetSize() - byteOffset;
4063 if (nBytes == 0)
4064 return 0;
4067 memcpy(bufptr, &theArray[byteOffset], nBytes);
4068 byteOffset += nBytes;
4069 return nBytes;
4073 void PASN_Stream::BlockEncode(const BYTE * bufptr, PINDEX nBytes)
4075 PAssert(byteOffset != P_MAX_INDEX, PLogicError);
4077 if (nBytes == 0)
4078 return;
4080 ByteAlign();
4082 if (byteOffset+nBytes >= GetSize())
4083 SetSize(byteOffset+nBytes+10);
4085 memcpy(theArray+byteOffset, bufptr, nBytes);
4086 byteOffset += nBytes;
4090 void PASN_Stream::ByteAlign()
4092 PAssert(byteOffset != P_MAX_INDEX, PLogicError);
4094 if (bitOffset != 8) {
4095 bitOffset = 8;
4096 byteOffset++;
4101 ///////////////////////////////////////////////////////////////////////
4103 PBER_Stream::PBER_Stream()
4108 PBER_Stream::PBER_Stream(const PBYTEArray & bytes)
4109 : PASN_Stream(bytes)
4114 PBER_Stream::PBER_Stream(const BYTE * buf, PINDEX size)
4115 : PASN_Stream(buf, size)
4120 PBER_Stream & PBER_Stream::operator=(const PBYTEArray & bytes)
4122 PBYTEArray::operator=(bytes);
4123 ResetDecoder();
4124 return *this;
4128 BOOL PBER_Stream::Read(PChannel & chan)
4130 SetSize(0);
4131 PINDEX offset = 0;
4133 // read the sequence header
4134 int b;
4135 if ((b = chan.ReadChar()) < 0)
4136 return FALSE;
4138 SetAt(offset++, (char)b);
4140 // only support direct read of simple sequences
4141 if ((b&0x1f) == 0x1f) {
4142 do {
4143 if ((b = chan.ReadChar()) < 0)
4144 return FALSE;
4145 SetAt(offset++, (char)b);
4146 } while ((b & 0x80) != 0);
4149 // read the first byte of the ASN length
4150 if ((b = chan.ReadChar()) < 0)
4151 return FALSE;
4153 SetAt(offset++, (char)b);
4155 // determine how many bytes in the length
4156 PINDEX dataLen = 0;
4157 if ((b & 0x80) == 0)
4158 dataLen = b;
4159 else {
4160 PINDEX lenLen = b&0x7f;
4161 SetSize(lenLen+2);
4162 while (lenLen-- > 0) {
4163 // read the length
4164 if ((b = chan.ReadChar()) < 0)
4165 return FALSE;
4166 dataLen = (dataLen << 8) | b;
4167 SetAt(offset++, (char)b);
4171 // read the data, all of it
4172 BYTE * bufptr = GetPointer(dataLen+offset) + offset;
4173 while (dataLen > 0) {
4174 if (!chan.Read(bufptr, dataLen))
4175 return FALSE;
4176 PINDEX readbytes = chan.GetLastReadCount();
4177 bufptr += readbytes;
4178 dataLen -= readbytes;
4180 return TRUE;
4184 BOOL PBER_Stream::Write(PChannel & chan)
4186 CompleteEncoding();
4187 return chan.Write(theArray, GetSize());
4191 PASN_Object * PBER_Stream::CreateObject(unsigned tag,
4192 PASN_Object::TagClass tagClass,
4193 BOOL primitive) const
4195 if (tagClass == PASN_Object::UniversalTagClass) {
4196 switch (tag) {
4197 case PASN_Object::UniversalBoolean :
4198 return new PASN_Boolean();
4200 case PASN_Object::UniversalInteger :
4201 return new PASN_Integer();
4203 case PASN_Object::UniversalBitString :
4204 return new PASN_BitString();
4206 case PASN_Object::UniversalOctetString :
4207 return new PASN_OctetString();
4209 case PASN_Object::UniversalNull :
4210 return new PASN_Null();
4212 case PASN_Object::UniversalObjectId :
4213 return new PASN_ObjectId();
4215 case PASN_Object::UniversalReal :
4216 return new PASN_Real();
4218 case PASN_Object::UniversalEnumeration :
4219 return new PASN_Enumeration();
4221 case PASN_Object::UniversalSequence :
4222 return new PASN_Sequence();
4224 case PASN_Object::UniversalSet :
4225 return new PASN_Set();
4227 case PASN_Object::UniversalNumericString :
4228 return new PASN_NumericString();
4230 case PASN_Object::UniversalPrintableString :
4231 return new PASN_PrintableString();
4233 case PASN_Object::UniversalIA5String :
4234 return new PASN_IA5String();
4236 case PASN_Object::UniversalVisibleString :
4237 return new PASN_VisibleString();
4239 case PASN_Object::UniversalGeneralString :
4240 return new PASN_GeneralString();
4242 case PASN_Object::UniversalBMPString :
4243 return new PASN_BMPString();
4247 if (primitive)
4248 return new PASN_OctetString(tag, tagClass);
4249 else
4250 return new PASN_Sequence(tag, tagClass, 0, FALSE, 0);
4254 BOOL PBER_Stream::HeaderDecode(unsigned & tagVal,
4255 PASN_Object::TagClass & tagClass,
4256 BOOL & primitive,
4257 unsigned & len)
4259 BYTE ident = ByteDecode();
4260 tagClass = (PASN_Object::TagClass)(ident>>6);
4261 primitive = (ident&0x20) == 0;
4262 tagVal = ident&31;
4263 if (tagVal == 31) {
4264 BYTE b;
4265 tagVal = 0;
4266 do {
4267 if (IsAtEnd())
4268 return FALSE;
4270 b = ByteDecode();
4271 tagVal = (tagVal << 7) | (b&0x7f);
4272 } while ((b&0x80) != 0);
4275 if (IsAtEnd())
4276 return FALSE;
4278 BYTE len_len = ByteDecode();
4279 if ((len_len & 0x80) == 0) {
4280 len = len_len;
4281 return TRUE;
4284 len_len &= 0x7f;
4286 len = 0;
4287 while (len_len-- > 0) {
4288 if (IsAtEnd())
4289 return FALSE;
4291 len = (len << 8) | ByteDecode();
4294 return TRUE;
4298 BOOL PBER_Stream::HeaderDecode(PASN_Object & obj, unsigned & len)
4300 PINDEX pos = byteOffset;
4302 unsigned tagVal;
4303 PASN_Object::TagClass tagClass;
4304 BOOL primitive;
4305 if (HeaderDecode(tagVal, tagClass, primitive, len) &&
4306 tagVal == obj.GetTag() && tagClass == obj.GetTagClass())
4307 return TRUE;
4309 byteOffset = pos;
4310 return FALSE;
4314 void PBER_Stream::HeaderEncode(const PASN_Object & obj)
4316 BYTE ident = (BYTE)(obj.GetTagClass() << 6);
4317 if (!obj.IsPrimitive())
4318 ident |= 0x20;
4319 unsigned tag = obj.GetTag();
4320 if (tag < 31)
4321 ByteEncode(ident|tag);
4322 else {
4323 ByteEncode(ident|31);
4324 unsigned count = (CountBits(tag)+6)/7;
4325 while (count-- > 1)
4326 ByteEncode((tag >> (count*7))&0x7f);
4327 ByteEncode(tag&0x7f);
4330 PINDEX len = obj.GetDataLength();
4331 if (len < 128)
4332 ByteEncode(len);
4333 else {
4334 PINDEX count = (CountBits(len+1)+7)/8;
4335 ByteEncode(count|0x80);
4336 while (count-- > 0)
4337 ByteEncode(len >> (count*8));
4343 ///////////////////////////////////////////////////////////////////////
4345 PPER_Stream::PPER_Stream(BOOL alignment)
4347 aligned = alignment;
4351 PPER_Stream::PPER_Stream(const PBYTEArray & bytes, BOOL alignment)
4352 : PASN_Stream(bytes)
4354 aligned = alignment;
4358 PPER_Stream::PPER_Stream(const BYTE * buf, PINDEX size, BOOL alignment)
4359 : PASN_Stream(buf, size)
4361 aligned = alignment;
4365 PPER_Stream & PPER_Stream::operator=(const PBYTEArray & bytes)
4367 PBYTEArray::operator=(bytes);
4368 ResetDecoder();
4369 aligned = TRUE;
4370 return *this;
4374 unsigned PPER_Stream::GetBitsLeft() const
4376 return (GetSize() - byteOffset)*8 - (8 - bitOffset);
4380 BOOL PPER_Stream::Read(PChannel & chan)
4382 ResetDecoder();
4383 SetSize(0);
4385 // Get RFC1006 TPKT length
4386 BYTE tpkt[4];
4387 if (!chan.ReadBlock(tpkt, sizeof(tpkt)))
4388 return FALSE;
4390 if (tpkt[0] != 3) // Only support version 3
4391 return TRUE;
4393 PINDEX data_len = ((tpkt[2] << 8)|tpkt[3]) - 4;
4395 return chan.ReadBlock(GetPointer(data_len), data_len);
4399 BOOL PPER_Stream::Write(PChannel & chan)
4401 CompleteEncoding();
4403 PINDEX size = GetSize();
4405 // Put RFC1006 TPKT length
4406 BYTE tpkt[4];
4407 tpkt[0] = 3; // Version 3
4408 tpkt[1] = 0;
4410 PINDEX len = size + sizeof(tpkt);
4411 tpkt[2] = (BYTE)(len >> 8);
4412 tpkt[3] = (BYTE)len;
4414 return chan.Write(tpkt, sizeof(tpkt)) && chan.Write(theArray, size);
4418 BOOL PPER_Stream::SingleBitDecode()
4420 if ((GetSize() - byteOffset)*8 - (8 - bitOffset) == 0)
4421 return FALSE;
4423 bitOffset--;
4424 BOOL value = (theArray[byteOffset] & (1 << bitOffset)) != 0;
4426 if (bitOffset == 0) {
4427 bitOffset = 8;
4428 byteOffset++;
4431 return value;
4435 void PPER_Stream::SingleBitEncode(BOOL value)
4437 PAssert(byteOffset != P_MAX_INDEX, PLogicError);
4439 if (byteOffset >= GetSize())
4440 SetSize(byteOffset+10);
4442 bitOffset--;
4444 if (value)
4445 theArray[byteOffset] |= 1 << bitOffset;
4447 if (bitOffset == 0)
4448 ByteAlign();
4452 BOOL PPER_Stream::MultiBitDecode(unsigned nBits, unsigned & value)
4454 if (nBits > sizeof(value)*8)
4455 return FALSE;
4457 unsigned bitsLeft = (GetSize() - byteOffset)*8 - (8 - bitOffset);
4458 if (nBits > bitsLeft)
4459 return FALSE;
4461 if (nBits == 0) {
4462 value = 0;
4463 return TRUE;
4466 if (nBits < bitOffset) {
4467 bitOffset -= nBits;
4468 value = (theArray[byteOffset] >> bitOffset) & ((1 << nBits) - 1);
4469 return TRUE;
4472 value = theArray[byteOffset] & ((1 << bitOffset) - 1);
4473 nBits -= bitOffset;
4474 bitOffset = 8;
4475 byteOffset++;
4477 while (nBits >= 8) {
4478 value = (value << 8) | (BYTE)theArray[byteOffset];
4479 byteOffset++;
4480 nBits -= 8;
4483 if (nBits > 0) {
4484 bitOffset = 8 - nBits;
4485 value = (value << nBits) | ((BYTE)theArray[byteOffset] >> bitOffset);
4488 return TRUE;
4492 void PPER_Stream::MultiBitEncode(unsigned value, unsigned nBits)
4494 PAssert(byteOffset != P_MAX_INDEX, PLogicError);
4496 if (nBits == 0)
4497 return;
4499 if (byteOffset+nBits/8+1 >= (unsigned)GetSize())
4500 SetSize(byteOffset+10);
4502 // Make sure value is in bounds of bit available.
4503 if (nBits < sizeof(int)*8)
4504 value &= ((1 << nBits) - 1);
4506 if (nBits < bitOffset) {
4507 bitOffset -= nBits;
4508 theArray[byteOffset] |= value << bitOffset;
4509 return;
4512 nBits -= bitOffset;
4513 theArray[byteOffset] |= (BYTE)(value >> nBits);
4514 bitOffset = 8;
4515 byteOffset++;
4517 while (nBits >= 8) {
4518 nBits -= 8;
4519 theArray[byteOffset] = (BYTE)(value >> nBits);
4520 byteOffset++;
4523 if (nBits > 0) {
4524 bitOffset = 8 - nBits;
4525 theArray[byteOffset] |= (BYTE)((value & ((1 << nBits)-1)) << bitOffset);
4530 BOOL PPER_Stream::SmallUnsignedDecode(unsigned & value)
4532 // X.691 Section 10.6
4534 if (!SingleBitDecode())
4535 return MultiBitDecode(6, value); // 10.6.1
4537 unsigned len;
4538 if (LengthDecode(0, INT_MAX, len) != 0) // 10.6.2
4539 return FALSE;
4541 ByteAlign();
4542 return MultiBitDecode(len*8, value);
4546 void PPER_Stream::SmallUnsignedEncode(unsigned value)
4548 if (value < 64) {
4549 MultiBitEncode(value, 7);
4550 return;
4553 SingleBitEncode(1); // 10.6.2
4555 PINDEX len = 4;
4556 if (value < 256)
4557 len = 1;
4558 else if (value < 65536)
4559 len = 2;
4560 else if (value < 0x1000000)
4561 len = 3;
4562 LengthEncode(len, 0, INT_MAX); // 10.9
4563 ByteAlign();
4564 MultiBitEncode(value, len*8);
4568 int PPER_Stream::UnsignedDecode(unsigned lower, unsigned upper, unsigned & value)
4570 // X.691 section 10.5
4572 if (lower == upper) { // 10.5.4
4573 value = lower;
4574 return 0;
4577 if (IsAtEnd())
4578 return -1;
4580 unsigned range = (upper - lower) + 1;
4581 unsigned nBits = CountBits(range);
4583 if (aligned && (range == 0 || range > 255)) { // not 10.5.6 and not 10.5.7.1
4584 if (nBits > 16) { // not 10.5.7.4
4585 LengthDecode(1, (nBits+7)/8, nBits); // 12.2.6
4586 nBits *= 8;
4588 else if (nBits > 8) // not 10.5.7.2
4589 nBits = 16; // 10.5.7.3
4590 ByteAlign(); // 10.7.5.2 - 10.7.5.4
4593 if (!MultiBitDecode(nBits, value))
4594 return -1;
4596 value += lower;
4597 return 0;
4601 void PPER_Stream::UnsignedEncode(int value, unsigned lower, unsigned upper)
4603 // X.691 section 10.5
4605 if (lower == upper) // 10.5.4
4606 return;
4608 unsigned range = (upper - lower) + 1;
4609 PINDEX nBits = CountBits(range);
4611 if (aligned && (range == 0 || range > 255)) { // not 10.5.6 and not 10.5.7.1
4612 if (nBits > 16) { // not 10.5.7.4
4613 int numBytes = value == 0 ? 1 : (((CountBits(value - lower + 1))+7)/8);
4614 LengthEncode(numBytes, 1, (nBits+7)/8); // 12.2.6
4615 nBits = numBytes*8;
4617 else if (nBits > 8) // not 10.5.7.2
4618 nBits = 16; // 10.5.7.3
4619 ByteAlign(); // 10.7.5.2 - 10.7.5.4
4622 MultiBitEncode(value - lower, nBits);
4626 int PPER_Stream::LengthDecode(unsigned lower, unsigned upper, unsigned & len)
4628 // X.691 section 10.9
4630 if (upper != INT_MAX && !aligned) {
4631 if (upper - lower > 0xffff)
4632 return -1; // 10.9.4.2 unsupported
4633 unsigned base;
4634 if (!MultiBitDecode(CountBits(upper - lower + 1), base))
4635 return -1;
4636 return lower + base; // 10.9.4.1
4639 if (upper < 65536) // 10.9.3.3
4640 return UnsignedDecode(lower, upper, len);
4642 // 10.9.3.5
4643 ByteAlign();
4644 if (IsAtEnd())
4645 return -1;
4647 if (SingleBitDecode() == 0)
4648 return MultiBitDecode(7, len) ? 0 : -1; // 10.9.3.6
4650 if (SingleBitDecode() == 0)
4651 return MultiBitDecode(14, len) ? 0 : -1; // 10.9.3.7
4653 return -1; // 10.9.3.8 unsupported
4657 void PPER_Stream::LengthEncode(unsigned len, unsigned lower, unsigned upper)
4659 // X.691 section 10.9
4661 if (upper != INT_MAX && !aligned) {
4662 PAssert(upper - lower < 0x10000, PUnimplementedFunction); // 10.9.4.2 unsupperted
4663 MultiBitEncode(len - lower, CountBits(upper - lower + 1)); // 10.9.4.1
4664 return;
4667 if (upper < 65536) { // 10.9.3.3
4668 UnsignedEncode(len, lower, upper);
4669 return;
4672 ByteAlign();
4674 if (len < 128) {
4675 MultiBitEncode(len, 8); // 10.9.3.6
4676 return;
4679 SingleBitEncode(TRUE);
4681 if (len < 0x2000) {
4682 MultiBitEncode(len, 15); // 10.9.3.7
4683 return;
4686 SingleBitEncode(TRUE);
4687 PAssert(len < 0x2000, PUnimplementedFunction); // 10.9.3.8 unsupported
4691 void PPER_Stream::AnyTypeEncode(const PASN_Object * value)
4693 PPER_Stream substream;
4695 if (value != NULL)
4696 value->Encode(substream);
4698 if (substream.GetPosition() == 0) // Make sure extension has at least one
4699 substream.SingleBitEncode(FALSE); // byte in its ANY type encoding.
4701 substream.CompleteEncoding();
4703 PINDEX nBytes = substream.GetSize();
4704 LengthEncode(nBytes, 0, INT_MAX);
4705 BlockEncode(substream.GetPointer(), nBytes);
4709 // PERASN.CXX