Changed output and intermediate directories, tuned up compile parameters for Windows...
[pwlib.git] / src / ptclib / asnper.cxx
blob34ca3d8be8320fd0640a5e44da3b7096d3702fff
1 /*
2 * asnper.cxx
4 * Abstract Syntax Notation 1 Encoding Rules
6 * Portable Windows Library
8 * $Log$
9 * Revision 1.10 2004/07/11 12:33:47 csoutheren
10 * Added guards against illegal PDU values causing crashes
12 * Revision 1.9 2004/03/23 04:53:57 csoutheren
13 * Fixed problem with incorrect encoding of ASN NULL under some circumstances
14 * Thanks to Ed Day of Objective Systems
16 * Revision 1.8 2004/01/17 17:43:42 csoutheren
17 * Fixed problem with the upper limit on various constrained types not being correctly enforced
19 * Revision 1.7 2004/01/17 09:23:43 csoutheren
20 * Fixed problem with the upper limit on constrained unsigned integers not being correctly enforced
22 * Revision 1.6 2003/12/14 10:21:29 rjongbloed
23 * Fixed bug in length incorrectlty decoded from ASN and (apparently) rare circumstances. Thanks pangxg@hotmail.com.
24 * Cleaned up return values to be BOOL rather than int for some functions.
26 * Revision 1.5 2003/12/03 03:50:03 csoutheren
27 * Reversed last change as it broke decoding in some circumstances
32 ///////////////////////////////////////////////////////////////////////
34 BOOL PPER_Stream::NullDecode(PASN_Null &)
36 return TRUE;
40 void PPER_Stream::NullEncode(const PASN_Null &)
44 ///////////////////////////////////////////////////////////////////////
46 BOOL PASN_ConstrainedObject::ConstrainedLengthDecode(PPER_Stream & strm, unsigned & length)
48 // The execution order is important in the following. The SingleBitDecode() function
49 // must be called if extendable is TRUE, no matter what.
50 if ((extendable && strm.SingleBitDecode()) || constraint == Unconstrained)
51 return strm.LengthDecode(0, INT_MAX, length);
52 else
53 return strm.LengthDecode(lowerLimit, upperLimit, length);
57 void PASN_ConstrainedObject::ConstrainedLengthEncode(PPER_Stream & strm, unsigned length) const
59 if (ConstraintEncode(strm, length)) // 26.4
60 strm.LengthEncode(length, 0, INT_MAX);
61 else
62 strm.LengthEncode(length, lowerLimit, upperLimit);
66 BOOL PASN_ConstrainedObject::ConstraintEncode(PPER_Stream & strm, unsigned value) const
68 if (!extendable)
69 return constraint != FixedConstraint;
71 BOOL needsExtending = value > upperLimit;
73 if (!needsExtending) {
74 if (lowerLimit < 0) {
75 if ((int)value < lowerLimit)
76 needsExtending = TRUE;
78 else {
79 if (value < (unsigned)lowerLimit)
80 needsExtending = TRUE;
84 strm.SingleBitEncode(needsExtending);
86 return needsExtending;
89 ///////////////////////////////////////////////////////////////////////
91 BOOL PPER_Stream::BooleanDecode(PASN_Boolean & value)
93 if (IsAtEnd())
94 return FALSE;
96 // X.691 Section 11
97 value = (BOOL)SingleBitDecode();
98 return TRUE;
102 void PPER_Stream::BooleanEncode(const PASN_Boolean & value)
104 // X.691 Section 11
105 SingleBitEncode((BOOL)value);
108 BOOL PPER_Stream::IntegerDecode(PASN_Integer & value)
110 return value.DecodePER(*this);
114 void PPER_Stream::IntegerEncode(const PASN_Integer & value)
116 value.EncodePER(*this);
119 ///////////////////////////////////////////////////////////////////////
121 BOOL PASN_Integer::DecodePER(PPER_Stream & strm)
123 // X.691 Sections 12
125 switch (constraint) {
126 case FixedConstraint : // 12.2.1 & 12.2.2
127 break;
129 case ExtendableConstraint :
130 if (!strm.SingleBitDecode()) // 12.1
131 break;
132 // Fall into default case for unconstrained or partially constrained
134 default : // 12.2.6
135 unsigned len;
136 if (!strm.LengthDecode(0, INT_MAX, len))
137 return FALSE;
139 len *= 8;
140 if (!strm.MultiBitDecode(len, value))
141 return FALSE;
143 if (IsUnsigned())
144 value += lowerLimit;
145 else if ((value&(1<<(len-1))) != 0) // Negative
146 value |= UINT_MAX << len; // Sign extend
147 return TRUE;
150 if ((unsigned)lowerLimit != upperLimit) // 12.2.2
151 return strm.UnsignedDecode(lowerLimit, upperLimit, value); // which devolves to 10.5
153 // 12.2.1
154 value = lowerLimit;
155 return TRUE;
159 void PASN_Integer::EncodePER(PPER_Stream & strm) const
161 // X.691 Sections 12
163 // 12.1
164 if (ConstraintEncode(strm, (int)value)) {
165 // 12.2.6
166 unsigned adjusted_value = value - lowerLimit;
168 PINDEX nBits = 1; // Allow for sign bit
169 if (IsUnsigned())
170 nBits = CountBits(adjusted_value+1);
171 else if ((int)adjusted_value > 0)
172 nBits += CountBits(adjusted_value+1);
173 else
174 nBits += CountBits(-(int)adjusted_value+1);
176 // Round up to nearest number of whole octets
177 PINDEX nBytes = (nBits+7)/8;
178 strm.LengthEncode(nBytes, 0, INT_MAX);
179 strm.MultiBitEncode(adjusted_value, nBytes*8);
180 return;
183 if ((unsigned)lowerLimit == upperLimit) // 12.2.1
184 return;
186 // 12.2.2 which devolves to 10.5
187 strm.UnsignedEncode(value, lowerLimit, upperLimit);
190 ///////////////////////////////////////////////////////////////////////
192 BOOL PPER_Stream::EnumerationDecode(PASN_Enumeration & value)
194 return value.DecodePER(*this);
198 void PPER_Stream::EnumerationEncode(const PASN_Enumeration & value)
200 value.EncodePER(*this);
204 BOOL PASN_Enumeration::DecodePER(PPER_Stream & strm)
206 // X.691 Section 13
208 if (extendable) { // 13.3
209 if (strm.SingleBitDecode()) {
210 unsigned len = 0;
211 return strm.SmallUnsignedDecode(len) &&
212 len > 0 &&
213 strm.UnsignedDecode(0, len-1, value);
217 return strm.UnsignedDecode(0, maxEnumValue, value); // 13.2
221 void PASN_Enumeration::EncodePER(PPER_Stream & strm) const
223 // X.691 Section 13
225 if (extendable) { // 13.3
226 BOOL extended = value > maxEnumValue;
227 strm.SingleBitEncode(extended);
228 if (extended) {
229 strm.SmallUnsignedEncode(1+value);
230 strm.UnsignedEncode(value, 0, value);
231 return;
235 strm.UnsignedEncode(value, 0, maxEnumValue); // 13.2
238 ///////////////////////////////////////////////////////////////////////
240 BOOL PPER_Stream::RealDecode(PASN_Real &)
242 // X.691 Section 14
244 if (IsAtEnd())
245 return FALSE;
247 unsigned len;
248 if (!MultiBitDecode(8, len))
249 return FALSE;
251 PAssertAlways(PUnimplementedFunction);
252 byteOffset += len+1;
253 return TRUE;
257 void PPER_Stream::RealEncode(const PASN_Real &)
259 // X.691 Section 14
261 MultiBitEncode(0, 8);
262 PAssertAlways(PUnimplementedFunction);
263 MultiBitEncode(0, 8);
266 ///////////////////////////////////////////////////////////////////////
268 BOOL PPER_Stream::ObjectIdDecode(PASN_ObjectId & value)
270 // X.691 Section 23
272 unsigned dataLen;
273 if (!LengthDecode(0, 255, dataLen))
274 return FALSE;
276 ByteAlign();
277 return value.CommonDecode(*this, dataLen);
281 void PPER_Stream::ObjectIdEncode(const PASN_ObjectId & value)
283 // X.691 Section 23
285 PBYTEArray eObjId;
286 value.CommonEncode(eObjId);
287 LengthEncode(eObjId.GetSize(), 0, 255);
288 BlockEncode(eObjId, eObjId.GetSize());
291 ///////////////////////////////////////////////////////////////////////
293 BOOL PASN_BitString::DecodeSequenceExtensionBitmap(PPER_Stream & strm)
295 if (!strm.SmallUnsignedDecode(totalBits))
296 return FALSE;
298 totalBits++;
300 if (!SetSize(totalBits))
301 return FALSE;
303 if (totalBits > strm.GetBitsLeft())
304 return FALSE;
306 unsigned theBits;
308 PINDEX idx = 0;
309 unsigned bitsLeft = totalBits;
310 while (bitsLeft >= 8) {
311 if (!strm.MultiBitDecode(8, theBits))
312 return FALSE;
313 bitData[idx++] = (BYTE)theBits;
314 bitsLeft -= 8;
317 if (bitsLeft > 0) {
318 if (!strm.MultiBitDecode(bitsLeft, theBits))
319 return FALSE;
320 bitData[idx] = (BYTE)(theBits << (8-bitsLeft));
323 return TRUE;
327 void PASN_BitString::EncodeSequenceExtensionBitmap(PPER_Stream & strm) const
329 PAssert(totalBits > 0, PLogicError);
331 unsigned bitsLeft = totalBits;
332 while (bitsLeft > 1 && !(*this)[bitsLeft-1])
333 bitsLeft--;
335 strm.SmallUnsignedEncode(bitsLeft-1);
337 PINDEX idx = 0;
338 while (bitsLeft >= 8) {
339 strm.MultiBitEncode(bitData[idx++], 8);
340 bitsLeft -= 8;
343 if (bitsLeft > 0)
344 strm.MultiBitEncode(bitData[idx] >> (8 - bitsLeft), bitsLeft);
348 BOOL PASN_BitString::DecodePER(PPER_Stream & strm)
350 // X.691 Section 15
352 if (!ConstrainedLengthDecode(strm, totalBits))
353 return FALSE;
355 if (!SetSize(totalBits))
356 return FALSE;
358 if (totalBits == 0)
359 return TRUE; // 15.7
361 if (totalBits > strm.GetBitsLeft())
362 return FALSE;
364 if (totalBits > 16) {
365 unsigned nBytes = (totalBits+7)/8;
366 return strm.BlockDecode(bitData.GetPointer(), nBytes) == nBytes; // 15.9
369 unsigned theBits;
370 if (totalBits <= 8) {
371 if (!strm.MultiBitDecode(totalBits, theBits))
372 return FALSE;
374 bitData[0] = (BYTE)(theBits << (8-totalBits));
376 else { // 15.8
377 if (!strm.MultiBitDecode(8, theBits))
378 return FALSE;
380 bitData[0] = (BYTE)theBits;
382 if (!strm.MultiBitDecode(totalBits-8, theBits))
383 return FALSE;
385 bitData[1] = (BYTE)(theBits << (16-totalBits));
388 return TRUE;
392 void PASN_BitString::EncodePER(PPER_Stream & strm) const
394 // X.691 Section 15
396 ConstrainedLengthEncode(strm, totalBits);
398 if (totalBits == 0)
399 return;
401 if (totalBits > 16)
402 strm.BlockEncode(bitData, (totalBits+7)/8); // 15.9
403 else if (totalBits <= 8) // 15.8
404 strm.MultiBitEncode(bitData[0] >> (8 - totalBits), totalBits);
405 else {
406 strm.MultiBitEncode(bitData[0], 8);
407 strm.MultiBitEncode(bitData[1] >> (16 - totalBits), totalBits-8);
411 ///////////////////////////////////////////////////////////////////////
413 BOOL PPER_Stream::BitStringDecode(PASN_BitString & value)
415 return value.DecodePER(*this);
419 void PPER_Stream::BitStringEncode(const PASN_BitString & value)
421 value.EncodePER(*this);
424 ///////////////////////////////////////////////////////////////////////
426 BOOL PASN_OctetString::DecodeSubType(PASN_Object & obj) const
428 PPER_Stream stream = GetValue();
429 return obj.Decode(stream);
433 void PASN_OctetString::EncodeSubType(const PASN_Object & obj)
435 PPER_Stream stream;
436 obj.Encode(stream);
437 stream.CompleteEncoding();
438 SetValue(stream);
441 BOOL PASN_OctetString::DecodePER(PPER_Stream & strm)
443 // X.691 Section 16
445 unsigned nBytes;
446 if (!ConstrainedLengthDecode(strm, nBytes))
447 return FALSE;
449 if (!SetSize(nBytes)) // 16.5
450 return FALSE;
452 if ((int)upperLimit != lowerLimit)
453 return strm.BlockDecode(value.GetPointer(), nBytes) == nBytes;
455 unsigned theBits;
456 switch (nBytes) {
457 case 0 :
458 break;
460 case 1 : // 16.6
461 if (!strm.MultiBitDecode(8, theBits))
462 return FALSE;
463 value[0] = (BYTE)theBits;
464 break;
466 case 2 : // 16.6
467 if (!strm.MultiBitDecode(8, theBits))
468 return FALSE;
469 value[0] = (BYTE)theBits;
470 if (!strm.MultiBitDecode(8, theBits))
471 return FALSE;
472 value[1] = (BYTE)theBits;
473 break;
475 default: // 16.7
476 return strm.BlockDecode(value.GetPointer(), nBytes) == nBytes;
479 return TRUE;
483 void PASN_OctetString::EncodePER(PPER_Stream & strm) const
485 // X.691 Section 16
487 PINDEX nBytes = value.GetSize();
488 ConstrainedLengthEncode(strm, nBytes);
490 if ((int)upperLimit != lowerLimit) {
491 strm.BlockEncode(value, nBytes);
492 return;
495 switch (nBytes) {
496 case 0 : // 16.5
497 break;
499 case 1 : // 16.6
500 strm.MultiBitEncode(value[0], 8);
501 break;
503 case 2 : // 16.6
504 strm.MultiBitEncode(value[0], 8);
505 strm.MultiBitEncode(value[1], 8);
506 break;
508 default: // 16.7
509 strm.BlockEncode(value, nBytes);
513 BOOL PPER_Stream::OctetStringDecode(PASN_OctetString & value)
515 return value.DecodePER(*this);
519 void PPER_Stream::OctetStringEncode(const PASN_OctetString & value)
521 value.EncodePER(*this);
524 ///////////////////////////////////////////////////////////////////////
526 BOOL PASN_ConstrainedString::DecodePER(PPER_Stream & strm)
528 // X.691 Section 26
530 unsigned len;
531 if (!ConstrainedLengthDecode(strm, len))
532 return FALSE;
534 if (len == 0) { // 10.9.3.3
535 value.SetSize(1);
536 value[0] = '\0';
537 return TRUE;
540 unsigned nBits = strm.IsAligned() ? charSetAlignedBits : charSetUnalignedBits;
541 unsigned totalBits = upperLimit*nBits;
543 if (constraint == Unconstrained ||
544 (lowerLimit == (int)upperLimit ? (totalBits > 16) : (totalBits >= 16))) {
545 if (nBits == 8)
546 return strm.BlockDecode((BYTE *)value.GetPointer(len+1), len) == len;
547 if (strm.IsAligned())
548 strm.ByteAlign();
551 if ((PINDEX)len > MaximumStringSize)
552 return FALSE;
554 if (!value.SetSize(len+1))
555 return FALSE;
557 PINDEX i;
558 for (i = 0; i < (PINDEX)len; i++) {
559 unsigned theBits;
560 if (!strm.MultiBitDecode(nBits, theBits))
561 return FALSE;
562 if (nBits >= canonicalSetBits && canonicalSetBits > 4)
563 value[i] = (char)theBits;
564 else
565 value[i] = characterSet[(PINDEX)theBits];
567 value[i] = '\0';
569 return TRUE;
573 void PASN_ConstrainedString::EncodePER(PPER_Stream & strm) const
575 // X.691 Section 26
577 PINDEX len = value.GetSize()-1;
578 ConstrainedLengthEncode(strm, len);
580 if (len == 0) // 10.9.3.3
581 return;
583 unsigned nBits = strm.IsAligned() ? charSetAlignedBits : charSetUnalignedBits;
584 unsigned totalBits = upperLimit*nBits;
586 if (constraint == Unconstrained ||
587 (lowerLimit == (int)upperLimit ? (totalBits > 16) : (totalBits >= 16))) {
588 // 26.5.7
589 if (nBits == 8) {
590 strm.BlockEncode((const BYTE *)(const char *)value, len);
591 return;
593 if (strm.IsAligned())
594 strm.ByteAlign();
597 for (PINDEX i = 0; i < len; i++) {
598 if (nBits >= canonicalSetBits && canonicalSetBits > 4)
599 strm.MultiBitEncode(value[i], nBits);
600 else {
601 const void * ptr = memchr(characterSet, value[i], characterSet.GetSize());
602 PINDEX pos = 0;
603 if (ptr != NULL)
604 pos = ((const char *)ptr - (const char *)characterSet);
605 strm.MultiBitEncode(pos, nBits);
610 ///////////////////////////////////////////////////////////////////////
612 BOOL PPER_Stream::ConstrainedStringDecode(PASN_ConstrainedString & value)
614 return value.DecodePER(*this);
618 void PPER_Stream::ConstrainedStringEncode(const PASN_ConstrainedString & value)
620 value.EncodePER(*this);
623 ///////////////////////////////////////////////////////////////////////
625 BOOL PASN_BMPString::DecodePER(PPER_Stream & strm)
627 // X.691 Section 26
629 unsigned len;
630 if (!ConstrainedLengthDecode(strm, len))
631 return FALSE;
633 if ((PINDEX)len > MaximumStringSize)
634 return FALSE;
636 if (!value.SetSize(len))
637 return FALSE;
639 PINDEX nBits = strm.IsAligned() ? charSetAlignedBits : charSetUnalignedBits;
641 if ((constraint == Unconstrained || upperLimit*nBits > 16) && strm.IsAligned())
642 strm.ByteAlign();
644 for (PINDEX i = 0; i < (PINDEX)len; i++) {
645 unsigned theBits;
646 if (!strm.MultiBitDecode(nBits, theBits))
647 return FALSE;
648 if (characterSet.IsEmpty())
649 value[i] = (WORD)(theBits + firstChar);
650 else
651 value[i] = characterSet[(PINDEX)theBits];
654 return TRUE;
658 void PASN_BMPString::EncodePER(PPER_Stream & strm) const
660 // X.691 Section 26
662 PINDEX len = value.GetSize();
663 ConstrainedLengthEncode(strm, len);
665 PINDEX nBits = strm.IsAligned() ? charSetAlignedBits : charSetUnalignedBits;
667 if ((constraint == Unconstrained || upperLimit*nBits > 16) && strm.IsAligned())
668 strm.ByteAlign();
670 for (PINDEX i = 0; i < len; i++) {
671 if (characterSet.IsEmpty())
672 strm.MultiBitEncode(value[i] - firstChar, nBits);
673 else {
674 for (PINDEX pos = 0; pos < characterSet.GetSize(); pos++) {
675 if (characterSet[pos] == value[i]) {
676 strm.MultiBitEncode(pos, nBits);
677 break;
685 BOOL PPER_Stream::BMPStringDecode(PASN_BMPString & value)
687 return value.DecodePER(*this);
691 void PPER_Stream::BMPStringEncode(const PASN_BMPString & value)
693 value.EncodePER(*this);
696 ///////////////////////////////////////////////////////////////////////
698 BOOL PASN_Choice::DecodePER(PPER_Stream & strm)
700 // X.691 Section 22
701 delete choice;
702 choice = NULL;
704 if (strm.IsAtEnd())
705 return FALSE;
707 if (extendable) {
708 if (strm.SingleBitDecode()) {
709 if (!strm.SmallUnsignedDecode(tag))
710 return FALSE;
712 tag += numChoices;
714 unsigned len;
715 if (!strm.LengthDecode(0, INT_MAX, len))
716 return FALSE;
718 BOOL ok;
719 if (CreateObject()) {
720 PINDEX nextPos = strm.GetPosition() + len;
721 ok = choice->Decode(strm);
722 strm.SetPosition(nextPos);
724 else {
725 PASN_OctetString * open_type = new PASN_OctetString;
726 open_type->SetConstraints(PASN_ConstrainedObject::FixedConstraint, len);
727 ok = open_type->Decode(strm);
728 if (open_type->GetSize() > 0)
729 choice = open_type;
730 else {
731 delete open_type;
732 ok = FALSE;
735 return ok;
739 if (numChoices < 2)
740 tag = 0;
741 else {
742 if (!strm.UnsignedDecode(0, numChoices-1, tag))
743 return FALSE;
746 return CreateObject() && choice->Decode(strm);
750 void PASN_Choice::EncodePER(PPER_Stream & strm) const
752 PAssert(CheckCreate(), PLogicError);
754 if (extendable) {
755 BOOL extended = tag >= numChoices;
756 strm.SingleBitEncode(extended);
757 if (extended) {
758 strm.SmallUnsignedEncode(tag - numChoices);
759 strm.AnyTypeEncode(choice);
760 return;
764 if (numChoices > 1)
765 strm.UnsignedEncode(tag, 0, numChoices-1);
767 choice->Encode(strm);
771 BOOL PPER_Stream::ChoiceDecode(PASN_Choice & value)
773 return value.DecodePER(*this);
777 void PPER_Stream::ChoiceEncode(const PASN_Choice & value)
779 value.EncodePER(*this);
782 ///////////////////////////////////////////////////////////////////////
784 BOOL PASN_Sequence::PreambleDecodePER(PPER_Stream & strm)
786 // X.691 Section 18
788 if (extendable) {
789 if (strm.IsAtEnd())
790 return FALSE;
791 totalExtensions = strm.SingleBitDecode() ? -1 : 0; // 18.1
793 else
794 totalExtensions = 0;
795 return optionMap.Decode(strm); // 18.2
799 void PASN_Sequence::PreambleEncodePER(PPER_Stream & strm) const
801 // X.691 Section 18
803 if (extendable) {
804 BOOL hasExtensions = FALSE;
805 for (unsigned i = 0; i < extensionMap.GetSize(); i++) {
806 if (extensionMap[i]) {
807 hasExtensions = TRUE;
808 break;
811 strm.SingleBitEncode(hasExtensions); // 18.1
812 ((PASN_Sequence*)this)->totalExtensions = hasExtensions ? -1 : 0;
814 optionMap.Encode(strm); // 18.2
818 BOOL PASN_Sequence::NoExtensionsToDecode(PPER_Stream & strm)
820 if (totalExtensions == 0)
821 return TRUE;
823 if (totalExtensions < 0) {
824 if (!extensionMap.DecodeSequenceExtensionBitmap(strm))
825 return FALSE;
826 totalExtensions = extensionMap.GetSize();
829 return FALSE;
833 BOOL PASN_Sequence::NoExtensionsToEncode(PPER_Stream & strm)
835 if (totalExtensions == 0)
836 return TRUE;
838 if (totalExtensions < 0) {
839 totalExtensions = extensionMap.GetSize();
840 extensionMap.EncodeSequenceExtensionBitmap(strm);
843 return FALSE;
847 BOOL PASN_Sequence::KnownExtensionDecodePER(PPER_Stream & strm, PINDEX fld, PASN_Object & field)
849 if (NoExtensionsToDecode(strm))
850 return TRUE;
852 if (!extensionMap[fld-optionMap.GetSize()])
853 return TRUE;
855 unsigned len;
856 if (!strm.LengthDecode(0, INT_MAX, len))
857 return FALSE;
859 PINDEX nextExtensionPosition = strm.GetPosition() + len;
860 BOOL ok = field.Decode(strm);
861 strm.SetPosition(nextExtensionPosition);
862 return ok;
866 void PASN_Sequence::KnownExtensionEncodePER(PPER_Stream & strm, PINDEX fld, const PASN_Object & field) const
868 if (((PASN_Sequence*)this)->NoExtensionsToEncode(strm))
869 return;
871 if (!extensionMap[fld-optionMap.GetSize()])
872 return;
874 strm.AnyTypeEncode(&field);
878 BOOL PASN_Sequence::UnknownExtensionsDecodePER(PPER_Stream & strm)
880 if (NoExtensionsToDecode(strm))
881 return TRUE;
883 if (totalExtensions <= knownExtensions)
884 return TRUE; // Already read them
886 PINDEX unknownCount = totalExtensions - knownExtensions;
887 if (fields.GetSize() >= unknownCount)
888 return TRUE; // Already read them
890 if (unknownCount > MaximumArraySize)
891 return FALSE;
893 if (!fields.SetSize(unknownCount))
894 return FALSE;
896 PINDEX i;
897 for (i = 0; i < fields.GetSize(); i++)
898 fields.SetAt(i, new PASN_OctetString);
900 for (i = knownExtensions; i < (PINDEX)extensionMap.GetSize(); i++) {
901 if (extensionMap[i])
902 if (!fields[i-knownExtensions].Decode(strm))
903 return FALSE;
906 return TRUE;
910 void PASN_Sequence::UnknownExtensionsEncodePER(PPER_Stream & strm) const
912 if (((PASN_Sequence*)this)->NoExtensionsToEncode(strm))
913 return;
915 int i;
916 for (i = knownExtensions; i < totalExtensions; i++) {
917 if (extensionMap[i]) {
918 PINDEX f = i - knownExtensions;
919 if (f < fields.GetSize())
920 fields[f].Encode(strm);
921 else {
922 PASN_OctetString dummy;
923 dummy.Encode(strm);
930 BOOL PPER_Stream::SequencePreambleDecode(PASN_Sequence & seq)
932 return seq.PreambleDecodePER(*this);
936 void PPER_Stream::SequencePreambleEncode(const PASN_Sequence & seq)
938 seq.PreambleEncodePER(*this);
942 BOOL PPER_Stream::SequenceKnownDecode(PASN_Sequence & seq, PINDEX fld, PASN_Object & field)
944 return seq.KnownExtensionDecodePER(*this, fld, field);
948 void PPER_Stream::SequenceKnownEncode(const PASN_Sequence & seq, PINDEX fld, const PASN_Object & field)
950 seq.KnownExtensionEncodePER(*this, fld, field);
954 BOOL PPER_Stream::SequenceUnknownDecode(PASN_Sequence & seq)
956 return seq.UnknownExtensionsDecodePER(*this);
960 void PPER_Stream::SequenceUnknownEncode(const PASN_Sequence & seq)
962 seq.UnknownExtensionsEncodePER(*this);
965 ///////////////////////////////////////////////////////////////////////
967 BOOL PPER_Stream::ArrayDecode(PASN_Array & array)
969 array.RemoveAll();
971 unsigned size;
972 if (!array.ConstrainedLengthDecode(*this, size))
973 return FALSE;
975 if (!array.SetSize(size))
976 return FALSE;
978 for (PINDEX i = 0; i < (PINDEX)size; i++) {
979 if (!array[i].Decode(*this))
980 return FALSE;
983 return TRUE;
987 void PPER_Stream::ArrayEncode(const PASN_Array & array)
989 PINDEX size = array.GetSize();
990 array.ConstrainedLengthEncode(*this, size);
991 for (PINDEX i = 0; i < size; i++)
992 array[i].Encode(*this);
995 ///////////////////////////////////////////////////////////////////////
997 PPER_Stream::PPER_Stream(BOOL alignment)
999 aligned = alignment;
1003 PPER_Stream::PPER_Stream(const PBYTEArray & bytes, BOOL alignment)
1004 : PASN_Stream(bytes)
1006 aligned = alignment;
1010 PPER_Stream::PPER_Stream(const BYTE * buf, PINDEX size, BOOL alignment)
1011 : PASN_Stream(buf, size)
1013 aligned = alignment;
1017 PPER_Stream & PPER_Stream::operator=(const PBYTEArray & bytes)
1019 PBYTEArray::operator=(bytes);
1020 ResetDecoder();
1021 aligned = TRUE;
1022 return *this;
1026 unsigned PPER_Stream::GetBitsLeft() const
1028 return (GetSize() - byteOffset)*8 - (8 - bitOffset);
1032 BOOL PPER_Stream::Read(PChannel & chan)
1034 ResetDecoder();
1035 SetSize(0);
1037 // Get RFC1006 TPKT length
1038 BYTE tpkt[4];
1039 if (!chan.ReadBlock(tpkt, sizeof(tpkt)))
1040 return FALSE;
1042 if (tpkt[0] != 3) // Only support version 3
1043 return TRUE;
1045 PINDEX data_len = ((tpkt[2] << 8)|tpkt[3]) - 4;
1047 return chan.ReadBlock(GetPointer(data_len), data_len);
1051 BOOL PPER_Stream::Write(PChannel & chan)
1053 CompleteEncoding();
1055 PINDEX size = GetSize();
1057 // Put RFC1006 TPKT length
1058 BYTE tpkt[4];
1059 tpkt[0] = 3; // Version 3
1060 tpkt[1] = 0;
1062 PINDEX len = size + sizeof(tpkt);
1063 tpkt[2] = (BYTE)(len >> 8);
1064 tpkt[3] = (BYTE)len;
1066 return chan.Write(tpkt, sizeof(tpkt)) && chan.Write(theArray, size);
1070 BOOL PPER_Stream::SingleBitDecode()
1072 if (!CheckByteOffset(byteOffset) || ((GetSize() - byteOffset)*8 - (8 - bitOffset) == 0))
1073 return FALSE;
1075 bitOffset--;
1077 BOOL value = (theArray[byteOffset] & (1 << bitOffset)) != 0;
1079 if (bitOffset == 0) {
1080 bitOffset = 8;
1081 byteOffset++;
1084 return value;
1088 void PPER_Stream::SingleBitEncode(BOOL value)
1090 if (!CheckByteOffset(byteOffset))
1091 return;
1093 if (byteOffset >= GetSize())
1094 SetSize(byteOffset+10);
1096 bitOffset--;
1098 if (value)
1099 theArray[byteOffset] |= 1 << bitOffset;
1101 if (bitOffset == 0)
1102 ByteAlign();
1106 BOOL PPER_Stream::MultiBitDecode(unsigned nBits, unsigned & value)
1108 if (nBits > sizeof(value)*8)
1109 return FALSE;
1111 unsigned bitsLeft = (GetSize() - byteOffset)*8 - (8 - bitOffset);
1112 if (nBits > bitsLeft)
1113 return FALSE;
1115 if (nBits == 0) {
1116 value = 0;
1117 return TRUE;
1120 if (!CheckByteOffset(byteOffset))
1121 return FALSE;
1123 if (nBits < bitOffset) {
1124 bitOffset -= nBits;
1125 value = (theArray[byteOffset] >> bitOffset) & ((1 << nBits) - 1);
1126 return TRUE;
1129 value = theArray[byteOffset] & ((1 << bitOffset) - 1);
1130 nBits -= bitOffset;
1131 bitOffset = 8;
1132 byteOffset++;
1134 while (nBits >= 8) {
1135 value = (value << 8) | (BYTE)theArray[byteOffset];
1136 byteOffset++;
1137 nBits -= 8;
1140 if (nBits > 0) {
1141 bitOffset = 8 - nBits;
1142 value = (value << nBits) | ((BYTE)theArray[byteOffset] >> bitOffset);
1145 return TRUE;
1149 void PPER_Stream::MultiBitEncode(unsigned value, unsigned nBits)
1151 PAssert(byteOffset != P_MAX_INDEX, PLogicError);
1153 if (nBits == 0)
1154 return;
1156 if (byteOffset+nBits/8+1 >= (unsigned)GetSize())
1157 SetSize(byteOffset+10);
1159 // Make sure value is in bounds of bit available.
1160 if (nBits < sizeof(int)*8)
1161 value &= ((1 << nBits) - 1);
1163 if (!CheckByteOffset(byteOffset))
1164 return;
1166 if (nBits < bitOffset) {
1167 bitOffset -= nBits;
1168 theArray[byteOffset] |= value << bitOffset;
1169 return;
1172 nBits -= bitOffset;
1173 theArray[byteOffset] |= (BYTE)(value >> nBits);
1174 bitOffset = 8;
1175 byteOffset++;
1177 while (nBits >= 8) {
1178 nBits -= 8;
1179 theArray[byteOffset] = (BYTE)(value >> nBits);
1180 byteOffset++;
1183 if (nBits > 0) {
1184 bitOffset = 8 - nBits;
1185 theArray[byteOffset] |= (BYTE)((value & ((1 << nBits)-1)) << bitOffset);
1190 BOOL PPER_Stream::SmallUnsignedDecode(unsigned & value)
1192 // X.691 Section 10.6
1194 if (!SingleBitDecode())
1195 return MultiBitDecode(6, value); // 10.6.1
1197 unsigned len;
1198 if (!LengthDecode(0, INT_MAX, len)) // 10.6.2
1199 return FALSE;
1201 ByteAlign();
1202 return MultiBitDecode(len*8, value);
1206 void PPER_Stream::SmallUnsignedEncode(unsigned value)
1208 if (value < 64) {
1209 MultiBitEncode(value, 7);
1210 return;
1213 SingleBitEncode(1); // 10.6.2
1215 PINDEX len = 4;
1216 if (value < 256)
1217 len = 1;
1218 else if (value < 65536)
1219 len = 2;
1220 else if (value < 0x1000000)
1221 len = 3;
1222 LengthEncode(len, 0, INT_MAX); // 10.9
1223 ByteAlign();
1224 MultiBitEncode(value, len*8);
1228 BOOL PPER_Stream::UnsignedDecode(unsigned lower, unsigned upper, unsigned & value)
1230 // X.691 section 10.5
1232 if (lower == upper) { // 10.5.4
1233 value = lower;
1234 return TRUE;
1237 if (IsAtEnd())
1238 return FALSE;
1240 unsigned range = (upper - lower) + 1;
1241 unsigned nBits = CountBits(range);
1243 if (aligned && (range == 0 || range > 255)) { // not 10.5.6 and not 10.5.7.1
1244 if (nBits > 16) { // not 10.5.7.4
1245 if (!LengthDecode(1, (nBits+7)/8, nBits)) // 12.2.6
1246 return FALSE;
1247 nBits *= 8;
1249 else if (nBits > 8) // not 10.5.7.2
1250 nBits = 16; // 10.5.7.3
1251 ByteAlign(); // 10.7.5.2 - 10.7.5.4
1254 if (!MultiBitDecode(nBits, value))
1255 return FALSE;
1257 value += lower;
1259 // clamp value to upper limit
1260 if (value > upper)
1261 value = upper;
1263 return TRUE;
1267 void PPER_Stream::UnsignedEncode(int value, unsigned lower, unsigned upper)
1269 // X.691 section 10.5
1271 if (lower == upper) // 10.5.4
1272 return;
1274 unsigned range = (upper - lower) + 1;
1275 PINDEX nBits = CountBits(range);
1277 if ((unsigned)value < lower)
1278 value = 0;
1279 else
1280 value -= lower;
1282 if (aligned && (range == 0 || range > 255)) { // not 10.5.6 and not 10.5.7.1
1283 if (nBits > 16) { // not 10.5.7.4
1284 int numBytes = value == 0 ? 1 : (((CountBits(value + 1))+7)/8);
1285 LengthEncode(numBytes, 1, (nBits+7)/8); // 12.2.6
1286 nBits = numBytes*8;
1288 else if (nBits > 8) // not 10.5.7.2
1289 nBits = 16; // 10.5.7.3
1290 ByteAlign(); // 10.7.5.2 - 10.7.5.4
1293 MultiBitEncode(value, nBits);
1297 BOOL PPER_Stream::LengthDecode(unsigned lower, unsigned upper, unsigned & len)
1299 // X.691 section 10.9
1301 if (upper != INT_MAX && !aligned) {
1302 if (upper - lower > 0xffff)
1303 return FALSE; // 10.9.4.2 unsupported
1304 unsigned base;
1305 if (!MultiBitDecode(CountBits(upper - lower + 1), base))
1306 return FALSE;
1307 len = lower + base; // 10.9.4.1
1309 // clamp value to upper limit
1310 if (len > upper)
1311 len = upper;
1313 return TRUE;
1316 if (upper < 65536) // 10.9.3.3
1317 return UnsignedDecode(lower, upper, len);
1319 // 10.9.3.5
1320 ByteAlign();
1321 if (IsAtEnd())
1322 return FALSE;
1324 if (SingleBitDecode() == 0) {
1325 if (!MultiBitDecode(7, len)) // 10.9.3.6
1326 return FALSE; // 10.9.3.8 unsupported
1329 else if (SingleBitDecode() == 0) {
1330 if (!MultiBitDecode(14, len)) // 10.9.3.7
1331 return FALSE; // 10.9.3.8 unsupported
1334 // clamp value to upper limit
1335 if (len > upper)
1336 len = upper;
1338 return TRUE;
1342 void PPER_Stream::LengthEncode(unsigned len, unsigned lower, unsigned upper)
1344 // X.691 section 10.9
1346 if (upper != INT_MAX && !aligned) {
1347 PAssert(upper - lower < 0x10000, PUnimplementedFunction); // 10.9.4.2 unsupperted
1348 MultiBitEncode(len - lower, CountBits(upper - lower + 1)); // 10.9.4.1
1349 return;
1352 if (upper < 65536) { // 10.9.3.3
1353 UnsignedEncode(len, lower, upper);
1354 return;
1357 ByteAlign();
1359 if (len < 128) {
1360 MultiBitEncode(len, 8); // 10.9.3.6
1361 return;
1364 SingleBitEncode(TRUE);
1366 if (len < 0x4000) {
1367 MultiBitEncode(len, 15); // 10.9.3.7
1368 return;
1371 SingleBitEncode(TRUE);
1372 PAssertAlways(PUnimplementedFunction); // 10.9.3.8 unsupported
1376 void PPER_Stream::AnyTypeEncode(const PASN_Object * value)
1378 PPER_Stream substream;
1380 if (value != NULL)
1381 value->Encode(substream);
1383 substream.CompleteEncoding();
1385 PINDEX nBytes = substream.GetSize();
1386 if (nBytes == 0) {
1387 const BYTE null[1] = { 0 };
1388 nBytes = sizeof(null);
1389 substream = PBYTEArray(null, nBytes, FALSE);
1392 LengthEncode(nBytes, 0, INT_MAX);
1393 BlockEncode(substream.GetPointer(), nBytes);
1396 ///////////////////////////////////////////////////////////////////////