Many and various changes to support new Visual C++ 2003
[pwlib.git] / src / ptclib / pasn.cxx
blobacc776461464283d05a295d21ba33161dfde6615
1 /*
2 * pasn.cxx
4 * ASN classes in support of the SNMP code.
6 * Portable Windows Library
8 * Copyright (c) 1993-2002 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
26 * $Log$
27 * Revision 1.16 2004/04/03 06:54:25 rjongbloed
28 * Many and various changes to support new Visual C++ 2003
30 * Revision 1.15 2002/11/06 22:47:25 robertj
31 * Fixed header comment (copyright etc)
33 * Revision 1.14 2000/05/05 10:08:29 robertj
34 * Fixed some GNU compiler warnings
36 * Revision 1.13 1999/05/01 11:29:20 robertj
37 * Alpha linux port changes.
39 * Revision 1.12 1999/05/01 03:52:20 robertj
40 * Fixed various egcs warnings.
42 * Revision 1.11 1999/03/02 01:53:38 craigs
43 * Fixed problem with creating IpAddress objects
45 * Revision 1.10 1999/02/16 08:08:06 robertj
46 * MSVC 6.0 compatibility changes.
48 * Revision 1.9 1998/11/30 04:52:04 robertj
49 * New directory structure
51 * Revision 1.8 1998/10/13 14:06:31 robertj
52 * Complete rewrite of memory leak detection code.
54 * Revision 1.7 1998/09/23 06:22:27 robertj
55 * Added open source copyright license.
57 * Revision 1.6 1998/02/16 06:57:05 robertj
58 * Moved pragma implemenetation in here so do not need upasn.cxx file.
60 * Revision 1.7 1998/01/26 02:49:21 robertj
61 * GNU support.
63 * Revision 1.6 1998/01/26 01:45:36 robertj
64 * Removed unused variable.
66 * Revision 1.5 1997/08/20 09:00:37 craigs
67 * Fixed problems with decoding of PASNNull
69 * Revision 1.4 1997/07/20 08:34:37 craigs
70 * Added ASN NULL type
72 * Revision 1.3 1997/07/16 05:52:48 craigs
73 * Changed ASN constructors to store value length separately so
74 * ASNString consctructor will worki correctly
76 * Revision 1.2 1996/11/04 03:58:34 robertj
77 * Added ASN types to class.
79 * Revision 1.1 1996/09/14 13:02:18 robertj
80 * Initial revision
84 #ifdef __GNUC__
85 #pragma implementation "pasn.h"
86 #endif
88 #include <ptlib.h>
89 #include <ptclib/pasn.h>
91 #define new PNEW
94 #define ASN_BOOLEAN (0x01)
95 #define ASN_INTEGER (0x02)
96 #define ASN_BIT_STR (0x03)
97 #define ASN_OCTET_STR (0x04)
98 #define ASN_NULL (0x05)
99 #define ASN_OBJECT_ID (0x06)
100 #define ASN_SEQUENCE (0x10)
101 #define ASN_SET (0x11)
103 #define ASN_UNIVERSAL (0x00)
104 #define ASN_APPLICATION (0x40)
105 #define ASN_CONTEXT (0x80)
106 #define ASN_PRIVATE (0xC0)
108 #define ASN_PRIMITIVE (0x00)
109 #define ASN_CONSTRUCTOR (0x20)
111 #define ASN_LONG_LEN (0x80)
112 #define ASN_EXTENSION_ID (0x1F)
113 #define ASN_BIT8 (0x80)
115 #define MAX_OID_LEN 64
118 static char cannotPerformOnBaseTypeMsg[] =
119 "Cannot perform operation on base type PASNObject";
122 BYTE PASNObject::ASNTypeToType[] = {
123 ASN_INTEGER | ASN_UNIVERSAL | ASN_PRIMITIVE, // Integer
124 ASN_OCTET_STR | ASN_UNIVERSAL | ASN_PRIMITIVE, // String
125 ASN_OBJECT_ID | ASN_UNIVERSAL | ASN_PRIMITIVE, // ObjectID
126 ASN_CONSTRUCTOR | ASN_SEQUENCE, // Sequence
127 ASN_CONSTRUCTOR | ASN_CONTEXT, // Choice
128 ASN_APPLICATION | 0, // IPAddress
129 ASN_APPLICATION | 1, // Counter32
130 ASN_APPLICATION | 2, // Gauge32
131 ASN_APPLICATION | 3, // TimeTicks
133 // SNMP v2 types
134 ASN_APPLICATION | 4, // Opaque
135 ASN_APPLICATION | 5, // NsapAddress
136 ASN_APPLICATION | 6, // Counter64
137 ASN_APPLICATION | 7, // UInteger32
139 // Oops - missed the Null type
140 ASN_NULL | ASN_UNIVERSAL | ASN_PRIMITIVE, // Null
142 0, // Unknown
147 //////////////////////////////////////////////////////////////////////////
149 // PASNObject
150 // All ASN objects descend from this class. It is the primitive type
151 // which can be put into the ASNSequence class
154 PASNObject::PASNObject()
159 void PASNObject::PrintOn(ostream &) const
161 PAssertAlways(cannotPerformOnBaseTypeMsg);
165 void PASNObject::Encode(PBYTEArray &)
167 PAssertAlways(cannotPerformOnBaseTypeMsg);
171 WORD PASNObject::GetEncodedLength()
173 PAssertAlways(cannotPerformOnBaseTypeMsg);
174 return 0;
178 PASNObject::ASNType PASNObject::GetType() const
180 PAssertAlways(cannotPerformOnBaseTypeMsg);
181 return Unknown;
185 PString PASNObject::GetTypeAsString() const
187 PAssertAlways(cannotPerformOnBaseTypeMsg);
188 return PString();
192 PObject * PASNObject::Clone() const
194 PAssertAlways(cannotPerformOnBaseTypeMsg);
195 return NULL;
199 void PASNObject::EncodeASNLength (PBYTEArray & buffer, WORD length)
201 PINDEX offs = buffer.GetSize();
203 // handle lengths less then 128
204 if (length < 128)
205 buffer[offs++] = (BYTE)length;
207 // handle lengths less than 256
208 else if (length < 256) {
209 buffer[offs++] = (BYTE)(0x01 | ASN_LONG_LEN);
210 buffer[offs++] = (BYTE)length;
213 // handle lengths up to 0xffff
214 else {
215 buffer[offs++] = (u_char)(0x02 | ASN_LONG_LEN);
216 buffer[offs++] = (u_char)((length >> 8) & 0xFF);
217 buffer[offs++] = (u_char)(length & 0xFF);
222 BOOL PASNObject::DecodeASNLength (const PBYTEArray & buffer, PINDEX & ptr, WORD & len)
224 PINDEX s = buffer.GetSize();
226 if (ptr >= s)
227 return FALSE;
229 BYTE ch = buffer[ptr++];
231 if ((ch & ASN_LONG_LEN) == 0)
232 len = (WORD)ch;
233 else if ((ch & ~ASN_LONG_LEN) == 0x01) {
234 if (ptr >= s)
235 return FALSE;
236 len = (WORD)buffer[ptr++];
237 } else {
238 if (ptr + 1 >= s)
239 return FALSE;
240 len = (WORD)((buffer[ptr] << 8) + buffer[ptr+1]);
241 ptr += 2;
243 return TRUE;
247 WORD PASNObject::GetASNLengthLength (WORD length)
249 // handle lengths less then 128
250 if (length < 128)
251 return 1;
253 // handle lengths less than 256
254 else if (length < 256)
255 return 2;
257 // handle lengths up to 0xffff
258 else
259 return 3;
263 void PASNObject::EncodeASNSequenceStart(PBYTEArray & buffer, BYTE type, WORD length)
265 buffer[buffer.GetSize()] = type;
266 EncodeASNLength(buffer, length);
270 WORD PASNObject::GetASNSequenceStartLength(WORD length)
272 return (WORD)(1 + GetASNLengthLength(length));
276 void PASNObject::EncodeASNHeader(PBYTEArray & buffer, PASNObject::ASNType type, WORD length)
279 buffer[buffer.GetSize()] = ASNTypeToType[type];
280 EncodeASNLength(buffer, length);
284 WORD PASNObject::GetASNHeaderLength(WORD length)
286 return (WORD)(1 + GetASNLengthLength(length));
290 void PASNObject::EncodeASNInteger (PBYTEArray & buffer, PASNInt data, PASNObject::ASNType type)
292 DWORD mask;
293 WORD intsize = sizeof(data);
295 // create a mask which is the top nine bits of a DWORD, or 0xFF800000
296 // on a big endian machine
297 mask = 0x1FFUL << ((8 * (sizeof(DWORD) - 1)) - 1);
299 // remove all sequences of nine 0's or 1's at the start of the value
300 while ((((data & mask) == 0) || ((data & mask) == mask))
301 && intsize > 1) {
302 intsize--;
303 data <<= 8;
306 // insert the header
307 EncodeASNHeader(buffer, type, intsize);
309 // insert the data
310 PINDEX offs = buffer.GetSize();
311 mask = 0xFFUL << (8 * (sizeof(DWORD) - 1));
312 while (intsize--) {
313 buffer[offs++] = (u_char)((data & mask) >> (8 * (sizeof(DWORD) - 1)));
314 data <<= 8;
319 void PASNObject::EncodeASNUnsigned (PBYTEArray & buffer, PASNUnsigned data, PASNObject::ASNType type)
321 long mask;
322 WORD intsize = sizeof(data);
323 int add_null_byte = 0;
325 mask = 0xFFUL << (8 * (sizeof(long) - 1));
326 /* mask is 0xFF000000 on a big-endian machine */
327 if ((u_char)((data & mask) >> (8 * (sizeof(PASNUnsigned) - 1))) & 0x80){
328 /* if MSB is set */
329 add_null_byte = 1;
330 intsize++;
333 // create a mask which is the top nine bits of a DWORD, or 0xFF800000
334 // on a big endian machine
335 mask = 0x1FFL << ((8 * (sizeof(DWORD) - 1)) - 1);
337 // remove all sequences of nine 0's or 1's at the start of the value
338 while ((((data & mask) == 0) || (((long)data & mask) == mask))
339 && intsize > 1) {
340 intsize--;
341 data <<= 8;
344 // insert the header
345 EncodeASNHeader(buffer, type, intsize);
347 // insert the data
348 PINDEX offs = buffer.GetSize();
349 mask = 0xFFL << (8 * (sizeof(DWORD) - 1));
350 while (intsize--) {
351 buffer[offs++] = (u_char)((data & mask) >> (8 * (sizeof(DWORD) - 1)));
352 data <<= 8;
355 if (add_null_byte == 1)
356 buffer[offs++] = 0;
360 BOOL PASNObject::DecodeASNInteger(const PBYTEArray & buffer, PINDEX & ptr, PASNInt & value, PASNObject::ASNType theType)
362 if (buffer[ptr++] != ASNTypeToType[theType])
363 return FALSE;
365 WORD len;
366 if (!DecodeASNLength(buffer, ptr, len))
367 return FALSE;
369 if (ptr + len > buffer.GetSize())
370 return FALSE;
372 if (buffer[ptr] & 0x80)
373 value = -1; /* integer is negative */
374 else
375 value = 0;
377 while (len--)
378 value = (value << 8) | buffer[ptr++];
379 return TRUE;
383 BOOL PASNObject::DecodeASNUnsigned(const PBYTEArray & buffer, PINDEX & ptr, PASNUnsigned & value, PASNObject::ASNType theType)
385 if (buffer[ptr++] != ASNTypeToType[theType])
386 return FALSE;
388 WORD len;
389 if (!DecodeASNLength(buffer, ptr, len))
390 return FALSE;
392 if (ptr + len > buffer.GetSize())
393 return FALSE;
395 // if (buffer[ptr] & 0x80)
396 // value = -1; /* integer is negative */
398 value = 0;
399 while (len--)
400 value = (value << 8) | buffer[ptr++];
401 return TRUE;
405 WORD PASNObject::GetASNIntegerLength(PASNInt data)
407 DWORD mask;
408 WORD intsize = sizeof(data);
410 // create a mask which is the top nine bits of a DWORD, or 0xFF800000
411 // on a big endian machine
412 mask = 0x1FFUL << ((8 * (sizeof(DWORD) - 1)) - 1);
414 // remove all sequences of nine 0's or 1's at the start of the value
415 while ((((data & mask) == 0) || ((data & mask) == mask))
416 && intsize > 1) {
417 intsize--;
418 data <<= 8;
421 // get the length of the header
422 return (WORD)(intsize + GetASNHeaderLength(intsize));
426 WORD PASNObject::GetASNUnsignedLength (PASNUnsigned data)
428 long mask;
429 WORD intsize = sizeof(data);
430 int add_null_byte = 0;
432 mask = 0xFFL << (8 * (sizeof(long) - 1));
433 /* mask is 0xFF000000 on a big-endian machine */
434 if ((u_char)((data & mask) >> (8 * (sizeof(PASNUnsigned) - 1))) & 0x80) {
435 /* if MSB is set */
436 add_null_byte = 1;
437 intsize++;
440 // create a mask which is the top nine bits of a DWORD, or 0xFF800000
441 // on a big endian machine
442 mask = 0x1FFL << ((8 * (sizeof(DWORD) - 1)) - 1);
444 // remove all sequences of nine 0's or 1's at the start of the value
445 while ((((data & mask) == 0) || (((long)data & mask) == mask))
446 && intsize > 1) {
447 intsize--;
448 data <<= 8;
451 // insert the header
452 return (WORD)(intsize + GetASNHeaderLength(intsize) + add_null_byte);
456 PASNInt PASNObject::GetInteger () const
458 PAssertAlways("Cannot return ASN object as Integer");
459 return 0;
463 PString PASNObject::GetString () const
465 PAssertAlways("Cannot return ASN object as String");
466 return PString();
470 PASNUnsigned PASNObject::GetUnsigned() const
472 PAssertAlways("Cannot return ASN object as Unsigned");
473 return 0;
477 const PASNSequence & PASNObject::GetSequence() const
479 PAssertAlways("Cannot return ASN object as Sequence");
480 PASNSequence * ptr = NULL;
481 return (PASNSequence &)*ptr;
485 PIPSocket::Address PASNObject::GetIPAddress () const
487 PAssertAlways("Cannot return ASN object as IP Address");
488 return PIPSocket::Address();
492 //////////////////////////////////////////////////////////////////////////
494 // PASNInteger
495 // A descendant of PASNObject which is a simple ASN integer type
498 PASNInteger::PASNInteger(PASNInt val)
500 value = val;
504 PASNInteger::PASNInteger(const PBYTEArray & buffer, PINDEX & ptr)
506 DecodeASNInteger(buffer, ptr, value, Integer);
510 void PASNInteger::PrintOn(ostream & strm) const
512 strm << "Integer: "
513 << value
514 << endl;
517 void PASNInteger::Encode(PBYTEArray & buffer)
519 EncodeASNInteger(buffer, value, Integer);
523 WORD PASNInteger::GetEncodedLength()
525 return GetASNIntegerLength(value);
529 PASNObject::ASNType PASNInteger::GetType() const
531 return Integer;
535 PString PASNInteger::GetTypeAsString() const
537 return PString("Integer");
541 PASNInt PASNInteger::GetInteger () const
543 return value;
547 PString PASNInteger::GetString () const
549 return PString(PString::Signed, (long)value);
553 PObject * PASNInteger::Clone() const
555 return new PASNInteger(*this);
559 //////////////////////////////////////////////////////////////////////////
561 // PASNString
562 // A descendant of PASNObject which is a simple ASN OctetStr type
565 PASNString::PASNString(const PString & str)
567 value = str;
568 valueLen = (WORD)str.GetLength();
571 PASNString::PASNString(const BYTE * ptr, int len)
573 value = PString((const char *)ptr, len);
574 valueLen = (WORD)len;
577 PASNString::PASNString(const PBYTEArray & buffer, PASNObject::ASNType type)
579 PINDEX ptr = 0;
580 Decode(buffer, ptr, type);
584 PASNString::PASNString(const PBYTEArray & buffer, PINDEX & ptr, PASNObject::ASNType type)
586 Decode(buffer, ptr, type);
590 BOOL PASNString::Decode(const PBYTEArray & buffer, PINDEX & ptr, PASNObject::ASNType type)
592 valueLen = 0;
593 if (buffer[ptr++] != ASNTypeToType[type])
594 return FALSE;
596 if (!DecodeASNLength(buffer, ptr, valueLen))
597 return FALSE;
599 if (ptr + valueLen > buffer.GetSize())
600 return FALSE;
602 value = PString(ptr + (const char *)(const BYTE *)buffer, valueLen);
603 ptr += valueLen;
605 return TRUE;
609 void PASNString::PrintOn(ostream & strm) const
611 strm << GetTypeAsString()
612 << ": "
613 << value
614 << endl;
618 void PASNString::Encode(PBYTEArray & buffer, PASNObject::ASNType type)
620 // insert the header
621 EncodeASNHeader(buffer, type, valueLen);
623 // add the string
624 PINDEX offs = buffer.GetSize();
625 for (PINDEX i = 0; i < valueLen; i++)
626 buffer[offs+i] = value[i];
630 WORD PASNString::GetEncodedLength()
632 return (WORD)(GetASNHeaderLength(valueLen) + (int)valueLen);
636 PASNObject::ASNType PASNString::GetType() const
638 return String;
642 PString PASNString::GetTypeAsString() const
644 return PString("String");
648 PString PASNString::GetString () const
650 return value;
654 PObject * PASNString::Clone() const
656 return new PASNString(*this);
660 //////////////////////////////////////////////////////////////////////////
662 // PASNUnsignedInteger
663 // A descendant of PASNObject which is an unsigned integer
665 BOOL PASNUnsignedInteger::Decode(const PBYTEArray & buffer, PINDEX & ptr, PASNObject::ASNType theType)
667 return DecodeASNUnsigned(buffer, ptr, value, theType);
671 void PASNUnsignedInteger::Encode(PBYTEArray & buffer, PASNObject::ASNType theType)
673 EncodeASNUnsigned(buffer, value, theType);
677 void PASNUnsignedInteger::PrintOn(ostream & strm) const
679 strm << GetTypeAsString()
680 << " : "
681 << value
682 << endl;
686 WORD PASNUnsignedInteger::GetEncodedLength()
688 return GetASNUnsignedLength(value);
692 PString PASNUnsignedInteger::GetString() const
694 return PString(PString::Unsigned, (long)value);
698 PASNUnsigned PASNUnsignedInteger::GetUnsigned() const
700 return value;
704 //////////////////////////////////////////////////////////////////////////
706 // PASNObjectID
707 // A descendant of PASNObject which is a simple ASN ObjID type
710 PASNObjectID::PASNObjectID(PASNOid * val, BYTE theLen)
712 value.SetSize(theLen);
713 memcpy(value.GetPointer(theLen), val, theLen * sizeof(PASNOid));
717 PASNObjectID::PASNObjectID(const PString & str)
719 PINDEX strLen = str.GetLength();
721 PINDEX i = 0;
722 PINDEX len = 0;
723 while (i < strLen) {
725 // find the first non-dot character
726 while (str[i] == '.' && i < strLen)
727 i++;
729 // find the next dot
730 PINDEX j = str.Find('.', i);
732 // convert to a PASNOid
733 value.SetSize(len+1);
734 value.SetAt(len++, str(i, j).AsInteger());
735 i = j;
740 PASNObjectID::PASNObjectID(const PBYTEArray & buffer)
742 PINDEX ptr = 0;
743 Decode(buffer, ptr);
747 PASNObjectID::PASNObjectID(const PBYTEArray & buffer, PINDEX & ptr)
749 Decode(buffer, ptr);
753 void PASNObjectID::PrintOn(ostream & strm) const
755 strm << "ObjectId: ";
756 for (PINDEX i = 0 ; i < value.GetSize(); i++) {
757 strm << value[i];
758 if (i != value.GetSize()-1)
759 strm << '.';
761 strm << endl;
765 void PASNObjectID::Encode(PBYTEArray & buffer)
767 PBYTEArray eObjId;
768 PINDEX offs = 0;
769 PASNOid subId, mask, testmask;
770 int bits, testbits;
771 PINDEX objIdLen = value.GetSize();
772 PASNOid *objId = value.GetPointer();
774 if (objIdLen < 2) {
775 eObjId [offs++] = 0;
776 objIdLen = 0;
777 } else {
778 eObjId [offs++] = (BYTE)(objId[1] + (objId[0] * 40));
779 objIdLen -= 2;
780 objId += 2;
783 while (objIdLen-- > 0) {
784 subId = *objId++;
785 if (subId < 128)
786 eObjId [offs++] = (BYTE)subId;
787 else {
788 mask = 0x7F; /* handle subid == 0 case */
789 bits = 0;
791 /* testmask *MUST* !!!! be of an unsigned type */
792 for (testmask = 0x7F, testbits = 0;
793 testmask != 0;
794 testmask <<= 7, testbits += 7) {
795 if (subId & testmask) { /* if any bits set */
796 mask = testmask;
797 bits = testbits;
801 /* mask can't be zero here */
802 for(;mask != 0x7F; mask >>= 7, bits -= 7) {
803 /* fix a mask that got truncated above */
804 if (mask == 0x1E00000)
805 mask = 0xFE00000;
806 eObjId [offs++] = (u_char)(((subId & mask) >> bits) | ASN_BIT8);
808 eObjId [offs++] = (u_char)(subId & mask);
812 PINDEX s = eObjId.GetSize();
813 EncodeASNHeader (buffer, ObjectID, (WORD)s);
814 offs = buffer.GetSize();
815 for (PINDEX i = 0; i < s; i++)
816 buffer [offs + i] = eObjId[i];
820 WORD PASNObjectID::GetEncodedLength()
822 PASNOid subId, mask, testmask;
823 int bits, testbits;
824 PINDEX objIdLen = value.GetSize();
825 WORD theLen = 0;
826 PASNOid *objId = value.GetPointer();
828 if (objIdLen < 2) {
829 theLen++;
830 objIdLen = 0;
831 } else {
832 theLen++;
833 objIdLen -= 2;
834 objId += 2;
837 while (objIdLen-- > 0) {
838 subId = *objId++;
839 if (subId < 128)
840 theLen++;
841 else {
842 mask = 0x7F; /* handle subid == 0 case */
843 bits = 0;
845 /* testmask *MUST* !!!! be of an unsigned type */
846 for (testmask = 0x7F, testbits = 0;
847 testmask != 0;
848 testmask <<= 7, testbits += 7) {
849 if (subId & testmask) { /* if any bits set */
850 mask = testmask;
851 bits = testbits;
855 /* mask can't be zero here */
856 for(;mask != 0x7F; mask >>= 7, bits -= 7) {
857 /* fix a mask that got truncated above */
858 if (mask == 0x1E00000)
859 mask = 0xFE00000;
860 theLen++;
862 theLen++;
866 return (WORD)(theLen + GetASNHeaderLength(theLen));
870 PASNObject::ASNType PASNObjectID::GetType() const
872 return ObjectID;
876 PString PASNObjectID::GetTypeAsString() const
878 return PString("Object ID");
882 PString PASNObjectID::GetString() const
884 PStringStream str;
886 for (PINDEX i = 0; i < value.GetSize(); i++) {
887 if (i > 0)
888 str << '.';
889 str << value[i];
892 return str;
896 BOOL PASNObjectID::Decode(const PBYTEArray & buffer, PINDEX & offs)
898 BYTE type = buffer[offs++];
899 PAssert(type == (ASN_OBJECT_ID | ASN_UNIVERSAL | ASN_PRIMITIVE),
900 "Attempt to decode non-objectID");
901 PASNOid subId;
903 WORD dataLen;
904 if (!DecodeASNLength(buffer, offs, dataLen))
905 return FALSE;
907 value.SetSize(2);
909 // handle zero length strings correctly
910 if (dataLen != 0) {
912 // start at the second identifier in the buffer, because we will later
913 // expand the first number into the first two IDs
914 PINDEX i = 1;
915 PINDEX s = buffer.GetSize();
917 while (dataLen > 0) {
918 subId = 0;
919 do { /* shift and add in low order 7 bits */
920 if (dataLen == 0 || offs >= s)
921 return FALSE;
922 subId = (subId << 7) + (buffer[offs] & ~ASN_BIT8);
923 dataLen--;
924 } while (buffer[offs++] & ASN_BIT8);
925 value.SetAt(i++, subId);
929 * The first two subidentifiers are encoded into the first component
930 * with the value (X * 40) + Y, where:
931 * X is the value of the first subidentifier.
932 * Y is the value of the second subidentifier.
934 subId = value[1];
935 if (subId == 0x2B) {
936 value[0] = 1;
937 value[1] = 3;
938 } else {
939 value[1] = subId % 40;
940 value[0] = (subId - value[1]) / 40;
944 return TRUE;
948 PObject * PASNObjectID::Clone() const
950 return new PASNObjectID(*this);
955 //////////////////////////////////////////////////////////////////////////
957 // PASNSequence
958 // A descendant of PASNObject which is the complex sequence type
961 PASNSequence::PASNSequence()
963 encodedLen = 0;
964 type = ASNTypeToType[Sequence];
965 asnType = Sequence;
969 PASNSequence::PASNSequence(BYTE selector)
971 encodedLen = 0;
972 PAssert(selector < ASN_CONSTRUCTOR, "Sequence selector too big");
973 type = (BYTE)(ASNTypeToType[Choice] | selector);
974 asnType = Choice;
978 void PASNSequence::Append(PASNObject * obj)
980 sequence.Append(obj);
984 void PASNSequence::AppendInteger(PASNInt value)
986 Append(new PASNInteger(value));
990 void PASNSequence::AppendString (const PString & str)
992 Append(new PASNString(str));
996 void PASNSequence::AppendObjectID(const PString & str)
998 Append(new PASNObjectID(str));
1002 void PASNSequence::AppendObjectID(PASNOid * val, BYTE len)
1004 Append(new PASNObjectID(val, len));
1008 void PASNSequence::PrintOn(ostream & strm) const
1010 strm << "Sequence:" << endl;
1011 for (PINDEX i = 0; i < sequence.GetSize(); i++)
1012 strm << sequence[i];
1013 strm << "End Sequence" << endl;
1017 void PASNSequence::Encode(PBYTEArray & buffer)
1019 // calculate the length of the sequence, if it hasn't already been done
1020 if (encodedLen == 0)
1021 (void)GetEncodedLength();
1023 // create the header for the sequence. Note that seqLen was calculated
1024 // by the call to GetEncodedLength above
1025 EncodeASNSequenceStart(buffer, type, seqLen);
1027 // now encode the sequence itself
1028 for (PINDEX i = 0; i < sequence.GetSize(); i++)
1029 sequence[i].Encode(buffer);
1032 BOOL PASNSequence::Encode(PBYTEArray & buffer, PINDEX maxLen)
1034 // calculate the length of the sequence, if it hasn't already been done
1035 if (encodedLen == 0)
1036 (void)GetEncodedLength();
1038 // create the header for the sequence. Note that seqLen was calculated
1039 // by the call to GetEncodedLength above
1040 EncodeASNSequenceStart(buffer, type, seqLen);
1042 // now encode the sequence itself
1043 for (PINDEX i = 0; i < sequence.GetSize(); i++) {
1044 sequence[i].Encode(buffer);
1045 if (buffer.GetSize() > maxLen)
1046 return FALSE;
1049 return TRUE;
1053 WORD PASNSequence::GetEncodedLength()
1055 // calculate the length of the sequence
1056 if (encodedLen == 0) {
1057 seqLen = 0;
1058 for (PINDEX i = 0; i < sequence.GetSize(); i++)
1059 seqLen = (WORD)(seqLen + sequence[i].GetEncodedLength());
1060 encodedLen = (WORD)(GetASNSequenceStartLength(seqLen) + seqLen);
1062 return encodedLen;
1066 PASNObject::ASNType PASNSequence::GetType() const
1068 return asnType;
1072 int PASNSequence::GetChoice() const
1074 return type;
1078 PString PASNSequence::GetTypeAsString() const
1080 return PString("Sequence");
1084 PASNSequence::PASNSequence(const PBYTEArray & buffer)
1087 PINDEX ptr = 0;
1088 if (!Decode(buffer, ptr))
1089 sequence.RemoveAll();
1093 PASNSequence::PASNSequence(const PBYTEArray & buffer, PINDEX & ptr)
1095 if (!Decode(buffer, ptr))
1096 sequence.RemoveAll();
1100 BOOL PASNSequence::Decode(const PBYTEArray & buffer, PINDEX & ptr)
1102 PINDEX s = buffer.GetSize();
1103 BYTE c;
1105 // all sequences start with a sequence start
1106 if (ptr >= s)
1107 return FALSE;
1109 // get the sequence header
1110 c = buffer[ptr++];
1111 if (c == (ASN_CONSTRUCTOR | ASN_SEQUENCE))
1112 asnType = Sequence;
1113 else if ((c & ~ASN_EXTENSION_ID) == (ASN_CONSTRUCTOR | ASN_CONTEXT)) {
1114 type = (BYTE)(c & ASN_EXTENSION_ID);
1115 asnType = Choice;
1116 } else
1117 return FALSE;
1119 // get the sequence length
1120 WORD len;
1121 if (!DecodeASNLength(buffer, ptr, len))
1122 return FALSE;
1124 // check the length
1125 if (ptr + len > s)
1126 return FALSE;
1128 // set new length
1129 s = ptr + len;
1131 // now decode the elements
1132 BOOL ok = TRUE;
1133 while (ptr < s && ok) {
1134 c = buffer[ptr];
1135 if ((c & ~ASN_EXTENSION_ID) == (ASN_CONSTRUCTOR | ASN_CONTEXT))
1136 sequence.Append(new PASNSequence(buffer, ptr));
1137 else switch (c) {
1139 // Integer
1140 case ASN_INTEGER | ASN_UNIVERSAL | ASN_PRIMITIVE:
1141 sequence.Append(new PASNInteger(buffer, ptr));
1142 break;
1144 // Octet String
1145 case ASN_OCTET_STR | ASN_UNIVERSAL | ASN_PRIMITIVE:
1146 sequence.Append(new PASNString(buffer, ptr));
1147 break;
1149 // NULL
1150 case ASN_NULL | ASN_UNIVERSAL | ASN_PRIMITIVE:
1151 sequence.Append(new PASNNull(buffer, ptr));
1152 break;
1154 // Object ID
1155 case ASN_OBJECT_ID | ASN_UNIVERSAL | ASN_PRIMITIVE:
1156 sequence.Append(new PASNObjectID(buffer, ptr));
1157 break;
1159 // Sequence
1160 case ASN_CONSTRUCTOR | ASN_SEQUENCE:
1161 sequence.Append(new PASNSequence(buffer, ptr));
1162 break;
1164 // TimeTicks
1165 case ASN_APPLICATION | 3:
1166 sequence.Append(new PASNTimeTicks(buffer, ptr));
1167 break;
1169 // Counter
1170 case ASN_APPLICATION | 1:
1171 sequence.Append(new PASNCounter(buffer, ptr));
1172 break;
1174 // Gauge
1175 case ASN_APPLICATION | 2:
1176 sequence.Append(new PASNGauge(buffer, ptr));
1177 break;
1179 // IP Address
1180 case ASN_APPLICATION | 0:
1181 sequence.Append(new PASNIPAddress(buffer, ptr));
1182 break;
1184 default:
1185 return TRUE;
1189 return ok;
1193 PINDEX PASNSequence::GetSize() const
1195 return sequence.GetSize();
1199 PASNObject & PASNSequence::operator [] (PINDEX idx) const
1201 return sequence[idx];
1205 const PASNSequence & PASNSequence::GetSequence() const
1207 return *this;
1211 PString PASNTimeTicks::GetTypeAsString() const
1213 return PString("TimeTicks");
1217 PString PASNCounter::GetTypeAsString() const
1219 return PString("Counter");
1223 PString PASNGauge::GetTypeAsString() const
1225 return PString("Gauge");
1229 PString PASNIPAddress::GetTypeAsString() const
1231 return PString("IPAddress");
1235 PString PASNIPAddress::GetString() const
1237 PINDEX len = value.GetSize();
1238 if (len == 0)
1239 return "(empty)";
1241 if (len < 4) {
1242 PString out = "Hex";
1243 for (PINDEX i = 0; i < len; i++)
1244 out &= psprintf("%02x", (BYTE)value[i]);
1245 return out;
1248 return psprintf("%i.%i.%i.%i",
1249 (BYTE)value[0], (BYTE)value[1],
1250 (BYTE)value[2], (BYTE)value[3]);
1254 PASNIPAddress::PASNIPAddress(const PString & str)
1255 : PASNString("")
1257 value.SetSize(4);
1259 PIPSocket::Address addr;
1260 if (!PIPSocket::GetHostAddress(str, addr))
1261 addr = 0;
1263 int i;
1264 for (i = 0; i < 4; i++)
1265 value[i] = addr[i];
1267 valueLen = 4;
1271 PIPSocket::Address PASNIPAddress::GetIPAddress () const
1273 return PIPSocket::Address((BYTE)value[0], (BYTE)value[1],
1274 (BYTE)value[2], (BYTE)value[3]);
1277 PASNNull::PASNNull()
1281 PASNNull::PASNNull(const PBYTEArray & buffer, PINDEX & ptr)
1283 PAssert(((buffer.GetSize() - ptr) >= 2) &&
1284 (buffer[ptr+0] == 0x05) &&
1285 (buffer[ptr+1] == 0x00),
1286 "Attempt to decode non-null");
1287 ptr += 2 ;
1290 void PASNNull::PrintOn(ostream & strm) const
1292 strm << "Null"
1293 << endl;
1296 void PASNNull::Encode(PBYTEArray & buffer)
1298 EncodeASNHeader(buffer, Null, 0);
1301 WORD PASNNull::GetEncodedLength()
1303 return 2;
1306 PObject * PASNNull::Clone() const
1308 return new PASNNull();
1311 PASNObject::ASNType PASNNull::GetType() const
1313 return Null;
1316 PString PASNNull::GetTypeAsString() const
1318 return PString("Null");
1321 PString PASNNull::GetString() const
1323 return PString();
1328 // End Of File ///////////////////////////////////////////////////////////////