Added IsSupportingRTP function to simplify detecting when STUN supports RTP
[pwlib.git] / src / ptclib / asnber.cxx
blob2345ddd125cbd3f3a006d1358c83cf76a287e9d4
1 /*
2 * asnber.cxx
4 * Abstract Syntax Notation 1 Encoding Rules
6 * Portable Windows Library
8 */
10 ///////////////////////////////////////////////////////////////////////
12 BOOL PBER_Stream::NullDecode(PASN_Null & value)
14 unsigned len;
15 if (!HeaderDecode(value, len))
16 return FALSE;
18 byteOffset += len;
19 return TRUE;
23 void PBER_Stream::NullEncode(const PASN_Null & value)
25 HeaderEncode(value);
28 ///////////////////////////////////////////////////////////////////////
30 BOOL PBER_Stream::BooleanDecode(PASN_Boolean & value)
32 unsigned len;
33 if (!HeaderDecode(value, len))
34 return FALSE;
36 while (len-- > 0) {
37 if (IsAtEnd())
38 return FALSE;
39 value = (BOOL)ByteDecode();
42 return TRUE;
46 void PBER_Stream::BooleanEncode(const PASN_Boolean & value)
48 HeaderEncode(value);
49 ByteEncode((BOOL)value);
52 ///////////////////////////////////////////////////////////////////////
54 BOOL PBER_Stream::IntegerDecode(PASN_Integer & value)
56 unsigned len;
57 if (!HeaderDecode(value, len) || len == 0 || IsAtEnd())
58 return FALSE;
60 int accumulator = (char)ByteDecode(); // sign extended first byte
61 while (--len > 0) {
62 if (IsAtEnd())
63 return FALSE;
64 accumulator = (accumulator << 8) | ByteDecode();
67 value = accumulator;
68 return TRUE;
72 void PBER_Stream::IntegerEncode(const PASN_Integer & value)
74 HeaderEncode(value);
75 // output the integer bits
76 for (int count = GetIntegerDataLength(value)-1; count >= 0; count--)
77 ByteEncode(value >> (count*8));
80 ///////////////////////////////////////////////////////////////////////
82 BOOL PBER_Stream::EnumerationDecode(PASN_Enumeration & value)
84 unsigned len;
85 if (!HeaderDecode(value, len) || len == 0 || IsAtEnd())
86 return FALSE;
88 unsigned val = 0;
89 while (len-- > 0) {
90 if (IsAtEnd())
91 return FALSE;
92 val = (val << 8) | ByteDecode();
95 value = val;
96 return TRUE;
100 void PBER_Stream::EnumerationEncode(const PASN_Enumeration & value)
102 HeaderEncode(value);
103 // output the integer bits
104 for (int count = GetIntegerDataLength(value)-1; count >= 0; count--)
105 ByteEncode(value >> (count*8));
108 ///////////////////////////////////////////////////////////////////////
110 BOOL PBER_Stream::RealDecode(PASN_Real & value)
112 unsigned len;
113 if (!HeaderDecode(value, len) || len == 0 || IsAtEnd())
114 return FALSE;
116 PAssertAlways(PUnimplementedFunction);
117 byteOffset += len;
119 return TRUE;
123 void PBER_Stream::RealEncode(const PASN_Real &)
125 PAssertAlways(PUnimplementedFunction);
128 ///////////////////////////////////////////////////////////////////////
130 BOOL PBER_Stream::ObjectIdDecode(PASN_ObjectId & value)
132 unsigned len;
133 if (!HeaderDecode(value, len))
134 return FALSE;
136 return value.CommonDecode(*this, len);
140 void PBER_Stream::ObjectIdEncode(const PASN_ObjectId & value)
142 HeaderEncode(value);
143 PBYTEArray data;
144 value.CommonEncode(data);
145 BlockEncode(data, data.GetSize());
148 ///////////////////////////////////////////////////////////////////////
150 BOOL PASN_BitString::DecodeBER(PBER_Stream & strm, unsigned len)
152 totalBits = len*8 - strm.ByteDecode();
153 unsigned nBytes = (totalBits+7)/8;
154 return strm.BlockDecode(bitData.GetPointer(nBytes), nBytes) == nBytes;
158 void PASN_BitString::EncodeBER(PBER_Stream & strm) const
160 if (totalBits == 0)
161 strm.ByteEncode(0);
162 else {
163 strm.ByteEncode(8-totalBits%8);
164 strm.BlockEncode(bitData, (totalBits+7)/8);
168 ///////////////////////////////////////////////////////////////////////
170 BOOL PBER_Stream::BitStringDecode(PASN_BitString & value)
172 unsigned len;
173 if (!HeaderDecode(value, len) || len == 0 || IsAtEnd())
174 return FALSE;
176 return value.DecodeBER(*this, len);
180 void PBER_Stream::BitStringEncode(const PASN_BitString & value)
182 HeaderEncode(value);
183 value.EncodeBER(*this);
186 ///////////////////////////////////////////////////////////////////////
188 BOOL PBER_Stream::OctetStringDecode(PASN_OctetString & value)
190 unsigned len;
191 if (!HeaderDecode(value, len))
192 return FALSE;
194 return BlockDecode(value.GetPointer(len), len) == len;
198 void PBER_Stream::OctetStringEncode(const PASN_OctetString & value)
200 HeaderEncode(value);
201 BlockEncode(value, value.GetSize());
204 ///////////////////////////////////////////////////////////////////////
206 BOOL PASN_ConstrainedString::DecodeBER(PBER_Stream & strm, unsigned len)
208 return strm.BlockDecode((BYTE *)value.GetPointer(len+1), len) == len;
212 void PASN_ConstrainedString::EncodeBER(PBER_Stream & strm) const
214 strm.BlockEncode(value, value.GetSize()-1);
217 ///////////////////////////////////////////////////////////////////////
219 BOOL PBER_Stream::ConstrainedStringDecode(PASN_ConstrainedString & value)
221 unsigned len;
222 if (!HeaderDecode(value, len))
223 return FALSE;
225 return value.DecodeBER(*this, len);
229 void PBER_Stream::ConstrainedStringEncode(const PASN_ConstrainedString & value)
231 HeaderEncode(value);
232 value.EncodeBER(*this);
235 ///////////////////////////////////////////////////////////////////////
237 BOOL PASN_BMPString::DecodeBER(PBER_Stream & strm, unsigned len)
239 value.SetSize(len/2);
240 return strm.BlockDecode((BYTE *)value.GetPointer(len), len) == len;
244 void PASN_BMPString::EncodeBER(PBER_Stream & strm) const
246 strm.BlockEncode((const BYTE *)(const WORD *)value, value.GetSize()*2);
249 ///////////////////////////////////////////////////////////////////////
251 BOOL PBER_Stream::BMPStringDecode(PASN_BMPString & value)
253 unsigned len;
254 if (!HeaderDecode(value, len))
255 return FALSE;
257 return value.DecodeBER(*this, len);
261 void PBER_Stream::BMPStringEncode(const PASN_BMPString & value)
263 HeaderEncode(value);
264 value.EncodeBER(*this);
267 ///////////////////////////////////////////////////////////////////////
269 BOOL PBER_Stream::ChoiceDecode(PASN_Choice & value)
271 PINDEX savedPosition = GetPosition();
273 unsigned tag;
274 PASN_Object::TagClass tagClass;
275 BOOL primitive;
276 unsigned entryLen;
277 if (!HeaderDecode(tag, tagClass, primitive, entryLen))
278 return FALSE;
280 SetPosition(savedPosition);
282 value.SetTag(tag, tagClass);
283 if (value.IsValid())
284 return value.GetObject().Decode(*this);
286 return TRUE;
289 void PBER_Stream::ChoiceEncode(const PASN_Choice & value)
291 if (value.IsValid())
292 value.GetObject().Encode(*this);
295 ///////////////////////////////////////////////////////////////////////
297 BOOL PASN_Sequence::PreambleDecodeBER(PBER_Stream & strm)
299 fields.RemoveAll();
301 unsigned len;
302 if (!strm.HeaderDecode(*this, len))
303 return FALSE;
305 endBasicEncoding = strm.GetPosition() + len;
306 return !strm.IsAtEnd();
310 void PASN_Sequence::PreambleEncodeBER(PBER_Stream & strm) const
312 strm.HeaderEncode(*this);
316 BOOL PASN_Sequence::KnownExtensionDecodeBER(PBER_Stream & strm, PINDEX, PASN_Object & field)
318 if (strm.GetPosition() >= endBasicEncoding)
319 return FALSE;
321 return field.Decode(strm);
325 void PASN_Sequence::KnownExtensionEncodeBER(PBER_Stream & strm, PINDEX, const PASN_Object & field) const
327 field.Encode(strm);
331 BOOL PASN_Sequence::UnknownExtensionsDecodeBER(PBER_Stream & strm)
333 while (strm.GetPosition() < endBasicEncoding) {
334 PINDEX savedPosition = strm.GetPosition();
336 unsigned tag;
337 PASN_Object::TagClass tagClass;
338 BOOL primitive;
339 unsigned entryLen;
340 if (!strm.HeaderDecode(tag, tagClass, primitive, entryLen))
341 return FALSE;
343 PINDEX nextEntryPosition = strm.GetPosition() + entryLen;
344 strm.SetPosition(savedPosition);
346 PASN_Object * obj = strm.CreateObject(tag, tagClass, primitive);
347 if (obj == NULL)
348 strm.SetPosition(nextEntryPosition);
349 else {
350 if (!obj->Decode(strm))
351 return FALSE;
353 fields.Append(obj);
357 return TRUE;
361 void PASN_Sequence::UnknownExtensionsEncodeBER(PBER_Stream & strm) const
363 for (PINDEX i = 0; i < fields.GetSize(); i++)
364 fields[i].Encode(strm);
367 ///////////////////////////////////////////////////////////////////////
369 BOOL PBER_Stream::SequencePreambleDecode(PASN_Sequence & seq)
371 return seq.PreambleDecodeBER(*this);
375 void PBER_Stream::SequencePreambleEncode(const PASN_Sequence & seq)
377 seq.PreambleEncodeBER(*this);
381 BOOL PBER_Stream::SequenceKnownDecode(PASN_Sequence & seq, PINDEX fld, PASN_Object & field)
383 return seq.KnownExtensionDecodeBER(*this, fld, field);
387 void PBER_Stream::SequenceKnownEncode(const PASN_Sequence & seq, PINDEX fld, const PASN_Object & field)
389 seq.KnownExtensionEncodeBER(*this, fld, field);
393 BOOL PBER_Stream::SequenceUnknownDecode(PASN_Sequence & seq)
395 return seq.UnknownExtensionsDecodeBER(*this);
399 void PBER_Stream::SequenceUnknownEncode(const PASN_Sequence & seq)
401 seq.UnknownExtensionsEncodeBER(*this);
404 ///////////////////////////////////////////////////////////////////////
406 BOOL PBER_Stream::ArrayDecode(PASN_Array & array)
408 array.RemoveAll();
410 unsigned len;
411 if (!HeaderDecode(array, len))
412 return FALSE;
414 PINDEX endOffset = byteOffset + len;
415 PINDEX count = 0;
416 while (byteOffset < endOffset) {
417 if (!array.SetSize(count+1))
418 return FALSE;
419 if (!array[count].Decode(*this))
420 return FALSE;
421 count++;
424 byteOffset = endOffset;
426 return TRUE;
430 void PBER_Stream::ArrayEncode(const PASN_Array & array)
432 HeaderEncode(array);
433 for (PINDEX i = 0; i < array.GetSize(); i++)
434 array[i].Encode(*this);
437 ///////////////////////////////////////////////////////////////////////
439 PBER_Stream::PBER_Stream()
444 PBER_Stream::PBER_Stream(const PBYTEArray & bytes)
445 : PASN_Stream(bytes)
450 PBER_Stream::PBER_Stream(const BYTE * buf, PINDEX size)
451 : PASN_Stream(buf, size)
456 PBER_Stream & PBER_Stream::operator=(const PBYTEArray & bytes)
458 PBYTEArray::operator=(bytes);
459 ResetDecoder();
460 return *this;
463 BOOL PBER_Stream::Read(PChannel & chan)
465 SetSize(0);
466 PINDEX offset = 0;
468 // read the sequence header
469 int b;
470 if ((b = chan.ReadChar()) < 0)
471 return FALSE;
473 SetAt(offset++, (char)b);
475 // only support direct read of simple sequences
476 if ((b&0x1f) == 0x1f) {
477 do {
478 if ((b = chan.ReadChar()) < 0)
479 return FALSE;
480 SetAt(offset++, (char)b);
481 } while ((b & 0x80) != 0);
484 // read the first byte of the ASN length
485 if ((b = chan.ReadChar()) < 0)
486 return FALSE;
488 SetAt(offset++, (char)b);
490 // determine how many bytes in the length
491 PINDEX dataLen = 0;
492 if ((b & 0x80) == 0)
493 dataLen = b;
494 else {
495 PINDEX lenLen = b&0x7f;
496 SetSize(lenLen+2);
497 while (lenLen-- > 0) {
498 // read the length
499 if ((b = chan.ReadChar()) < 0)
500 return FALSE;
501 dataLen = (dataLen << 8) | b;
502 SetAt(offset++, (char)b);
506 // read the data, all of it
507 BYTE * bufptr = GetPointer(dataLen+offset) + offset;
508 while (dataLen > 0) {
509 if (!chan.Read(bufptr, dataLen))
510 return FALSE;
511 PINDEX readbytes = chan.GetLastReadCount();
512 bufptr += readbytes;
513 dataLen -= readbytes;
515 return TRUE;
519 BOOL PBER_Stream::Write(PChannel & chan)
521 CompleteEncoding();
522 return chan.Write(theArray, GetSize());
526 PASN_Object * PBER_Stream::CreateObject(unsigned tag,
527 PASN_Object::TagClass tagClass,
528 BOOL primitive) const
530 if (tagClass == PASN_Object::UniversalTagClass) {
531 switch (tag) {
532 case PASN_Object::UniversalBoolean :
533 return new PASN_Boolean();
535 case PASN_Object::UniversalInteger :
536 return new PASN_Integer();
538 case PASN_Object::UniversalBitString :
539 return new PASN_BitString();
541 case PASN_Object::UniversalOctetString :
542 return new PASN_OctetString();
544 case PASN_Object::UniversalNull :
545 return new PASN_Null();
547 case PASN_Object::UniversalObjectId :
548 return new PASN_ObjectId();
550 case PASN_Object::UniversalReal :
551 return new PASN_Real();
553 case PASN_Object::UniversalEnumeration :
554 return new PASN_Enumeration();
556 case PASN_Object::UniversalSequence :
557 return new PASN_Sequence();
559 case PASN_Object::UniversalSet :
560 return new PASN_Set();
562 case PASN_Object::UniversalNumericString :
563 return new PASN_NumericString();
565 case PASN_Object::UniversalPrintableString :
566 return new PASN_PrintableString();
568 case PASN_Object::UniversalIA5String :
569 return new PASN_IA5String();
571 case PASN_Object::UniversalVisibleString :
572 return new PASN_VisibleString();
574 case PASN_Object::UniversalGeneralString :
575 return new PASN_GeneralString();
577 case PASN_Object::UniversalBMPString :
578 return new PASN_BMPString();
582 if (primitive)
583 return new PASN_OctetString(tag, tagClass);
584 else
585 return new PASN_Sequence(tag, tagClass, 0, FALSE, 0);
588 BOOL PBER_Stream::HeaderDecode(unsigned & tagVal,
589 PASN_Object::TagClass & tagClass,
590 BOOL & primitive,
591 unsigned & len)
593 BYTE ident = ByteDecode();
594 tagClass = (PASN_Object::TagClass)(ident>>6);
595 primitive = (ident&0x20) == 0;
596 tagVal = ident&31;
597 if (tagVal == 31) {
598 BYTE b;
599 tagVal = 0;
600 do {
601 if (IsAtEnd())
602 return FALSE;
604 b = ByteDecode();
605 tagVal = (tagVal << 7) | (b&0x7f);
606 } while ((b&0x80) != 0);
609 if (IsAtEnd())
610 return FALSE;
612 BYTE len_len = ByteDecode();
613 if ((len_len & 0x80) == 0) {
614 len = len_len;
615 return TRUE;
618 len_len &= 0x7f;
620 len = 0;
621 while (len_len-- > 0) {
622 if (IsAtEnd())
623 return FALSE;
625 len = (len << 8) | ByteDecode();
628 return TRUE;
632 BOOL PBER_Stream::HeaderDecode(PASN_Object & obj, unsigned & len)
634 PINDEX pos = byteOffset;
636 unsigned tagVal;
637 PASN_Object::TagClass tagClass;
638 BOOL primitive;
639 if (HeaderDecode(tagVal, tagClass, primitive, len) &&
640 tagVal == obj.GetTag() && tagClass == obj.GetTagClass())
641 return TRUE;
643 byteOffset = pos;
644 return FALSE;
648 void PBER_Stream::HeaderEncode(const PASN_Object & obj)
650 BYTE ident = (BYTE)(obj.GetTagClass() << 6);
651 if (!obj.IsPrimitive())
652 ident |= 0x20;
653 unsigned tag = obj.GetTag();
654 if (tag < 31)
655 ByteEncode(ident|tag);
656 else {
657 ByteEncode(ident|31);
658 unsigned count = (CountBits(tag)+6)/7;
659 while (count-- > 1)
660 ByteEncode((tag >> (count*7))&0x7f);
661 ByteEncode(tag&0x7f);
664 PINDEX len = obj.GetDataLength();
665 if (len < 128)
666 ByteEncode(len);
667 else {
668 PINDEX count = (CountBits(len+1)+7)/8;
669 ByteEncode(count|0x80);
670 while (count-- > 0)
671 ByteEncode(len >> (count*8));
675 ///////////////////////////////////////////////////////////////////////