1 /*_############################################################################
6 _## -----------------------------------------------
7 _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
9 _## This software is based on SNMP++2.6 from Hewlett Packard:
11 _## Copyright (c) 1996
12 _## Hewlett-Packard Company
14 _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
15 _## Permission to use, copy, modify, distribute and/or sell this software
16 _## and/or its documentation is hereby granted without fee. User agrees
17 _## to display the above copyright notice and this license notice in all
18 _## copies of the software and any documentation of the software. User
19 _## agrees to assume all liability for the use of the software;
20 _## Hewlett-Packard and Jochen Katz make no representations about the
21 _## suitability of this software for any purpose. It is provided
22 _## "AS-IS" without warranty of any kind, either express or implied. User
23 _## hereby grants a royalty-free license to any and all derivatives based
24 _## upon this software code base.
26 _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
28 _##########################################################################*/
29 /*===================================================================
32 Hewlett-Packard Company
34 ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
35 Permission to use, copy, modify, distribute and/or sell this software
36 and/or its documentation is hereby granted without fee. User agrees
37 to display the above copyright notice and this license notice in all
38 copies of the software and any documentation of the software. User
39 agrees to assume all liability for the use of the software; Hewlett-Packard
40 makes no representations about the suitability of this software for any
41 purpose. It is provided "AS-IS" without warranty of any kind,either express
42 or implied. User hereby grants a royalty-free license to any and all
43 derivatives based upon this software code base.
47 OCTETSTR CLASS IMPLEMENTATION
49 DESIGN + AUTHOR: Peter E Mellquist
52 This class is fully contained and does not rely on or any other
53 SNMP libraries. This class is portable across any platform
55 =====================================================================*/
56 char octet_cpp_version[]="@(#) SNMP++ $Id: octet.cpp 1824 2010-08-29 19:47:08Z katz $";
58 #include "snmp_pp/octet.h" // include definition for octet class
59 #include <ctype.h> // for isprint() used by get_printable()
60 #include <stdio.h> // for sprintf() used by get_printable_hex()
61 #include <string.h> // for strlen() and memcpy()
63 #ifdef SNMP_PP_NAMESPACE
67 enum OctetStr::OutputType OctetStr::hex_output_type
68 = OctetStr::OutputHexAndClear;
69 char OctetStr::nonprintable_char = '.';
72 char OctetStr::linefeed_chars[3] = "\n";
74 char OctetStr::linefeed_chars[3] = "\r\n";
78 //============[ constructor using no arguments ]======================
80 : output_buffer(0), output_buffer_len(0), m_changed(true), validity(true)
82 smival.syntax = sNMP_SYNTAX_OCTETS;
83 smival.value.string.ptr = 0;
84 smival.value.string.len = 0;
87 //============[ constructor using a string ]=========================
88 OctetStr::OctetStr(const char *str)
89 : output_buffer(0), output_buffer_len(0), m_changed(true), validity(true)
91 smival.syntax = sNMP_SYNTAX_OCTETS;
92 smival.value.string.ptr = 0;
93 smival.value.string.len = 0;
97 // check for null string
98 if (!str || !((z = strlen(str))))
102 smival.value.string.ptr = (SmiLPBYTE) new unsigned char[z];
104 if (smival.value.string.ptr)
106 MEMCPY(smival.value.string.ptr, str, z);
107 smival.value.string.len = SAFE_INT_CAST(z);
114 //============[ constructor using an unsigned char * ]================
115 OctetStr::OctetStr(const unsigned char *str, unsigned long len)
116 : output_buffer(0), output_buffer_len(0), m_changed(true), validity(true)
118 smival.syntax = sNMP_SYNTAX_OCTETS;
119 smival.value.string.ptr = 0;
120 smival.value.string.len = 0;
122 if (!str || !len) return; // check for zero len
124 // get the mem needed
125 smival.value.string.ptr = (SmiLPBYTE) new unsigned char[len];
127 if (smival.value.string.ptr)
129 MEMCPY(smival.value.string.ptr, str, (size_t) len);
130 smival.value.string.len = len;
136 //============[ constructor using another octet object ]==============
137 OctetStr::OctetStr (const OctetStr &octet)
138 : output_buffer(0), output_buffer_len(0), m_changed(true), validity(true)
140 smival.syntax = sNMP_SYNTAX_OCTETS;
141 smival.value.string.ptr = 0;
142 smival.value.string.len = 0;
144 if (octet.smival.value.string.len == 0) return; // check for zero len case
146 // must be a valid object
153 // get the mem needed
154 smival.value.string.ptr = (SmiLPBYTE) new unsigned char[octet.smival.value.string.len];
156 if (smival.value.string.ptr)
158 MEMCPY(smival.value.string.ptr,
159 octet.smival.value.string.ptr,
160 (size_t) octet.smival.value.string.len);
161 smival.value.string.len = octet.smival.value.string.len;
167 //=============[ destructor ]=========================================
168 OctetStr::~OctetStr()
170 // if not empty, free it up
171 if (smival.value.string.ptr) delete [] smival.value.string.ptr;
172 smival.value.string.len = 0;
173 smival.value.string.ptr = 0;
174 if (output_buffer) delete [] output_buffer;
176 output_buffer_len = 0;
180 //============[ set the data on an already constructed Octet ]============
181 void OctetStr::set_data(const unsigned char *str, unsigned long len)
183 // free up already used space
184 if (smival.value.string.ptr)
186 delete [] smival.value.string.ptr;
187 smival.value.string.ptr = 0;
189 smival.value.string.len = 0;
192 // check for zero len
199 // get the mem needed
200 smival.value.string.ptr = (SmiLPBYTE) new unsigned char[len];
202 if (smival.value.string.ptr)
204 MEMCPY(smival.value.string.ptr, str, len);
205 smival.value.string.len = len;
212 //=============[ assignment to a string operator overloaded ]=========
213 OctetStr& OctetStr::operator=(const char *str)
217 // free up previous memory if needed
218 if (smival.value.string.ptr)
220 delete [] smival.value.string.ptr;
221 smival.value.string.ptr = 0;
222 smival.value.string.len = 0;
227 // if empty then we are done; get the string size
228 if (!str || !((nz = strlen(str))))
235 smival.value.string.ptr = (SmiLPBYTE) new unsigned char[nz];
237 if (smival.value.string.ptr)
239 MEMCPY(smival.value.string.ptr, str, nz);
240 smival.value.string.len = SAFE_INT_CAST(nz);
246 return *this; // return self reference
249 //=============[ assignment to another oid object overloaded ]========
250 OctetStr& OctetStr::operator=(const OctetStr &octet)
252 if (this == &octet) return *this; // protect against assignment from self
254 if (!octet.validity) return *this; // don't assign from invalid objs
256 set_data(octet.smival.value.string.ptr, octet.smival.value.string.len);
258 return *this; // return self reference
261 //==============[ equivlence operator overloaded ]====================
262 int operator==(const OctetStr &lhs, const OctetStr &rhs)
264 if (lhs.smival.value.string.len != rhs.smival.value.string.len)
266 return (lhs.nCompare(rhs.smival.value.string.len, rhs) == 0);
269 //==============[ not equivlence operator overloaded ]================
270 int operator!=(const OctetStr &lhs, const OctetStr &rhs)
272 if (lhs.smival.value.string.len != rhs.smival.value.string.len)
274 return (lhs.nCompare(rhs.smival.value.string.len, rhs) != 0);
277 //==============[ less than < overloaded ]============================
278 int operator<(const OctetStr &lhs, const OctetStr &rhs)
280 int maxlen = lhs.smival.value.string.len > rhs.smival.value.string.len
281 ? lhs.smival.value.string.len : rhs.smival.value.string.len;
282 return (lhs.nCompare(maxlen, rhs) < 0);
285 //==============[ less than <= overloaded ]===========================
286 int operator<=(const OctetStr &lhs, const OctetStr &rhs)
288 int maxlen = lhs.smival.value.string.len > rhs.smival.value.string.len
289 ? lhs.smival.value.string.len : rhs.smival.value.string.len;
290 return (lhs.nCompare(maxlen, rhs) <= 0);
293 //===============[ greater than > overloaded ]========================
294 int operator>(const OctetStr &lhs, const OctetStr &rhs)
296 int maxlen = lhs.smival.value.string.len > rhs.smival.value.string.len
297 ? lhs.smival.value.string.len : rhs.smival.value.string.len;
298 return (lhs.nCompare(maxlen, rhs) > 0);
301 //===============[ greater than >= overloaded ]=======================
302 int operator>=(const OctetStr &lhs, const OctetStr &rhs)
304 int maxlen = lhs.smival.value.string.len > rhs.smival.value.string.len
305 ? lhs.smival.value.string.len : rhs.smival.value.string.len;
306 return (lhs.nCompare(maxlen, rhs) >=0);
309 //===============[ equivlence operator overloaded ]===================
310 int operator==(const OctetStr &lhs, const char *rhs)
313 if (lhs.smival.value.string.len != to.smival.value.string.len)
315 return (lhs.nCompare(to.smival.value.string.len, to) == 0);
318 //===============[ not equivlence operator overloaded ]===============
319 int operator!=(const OctetStr &lhs, const char *rhs)
322 if (lhs.smival.value.string.len != to.smival.value.string.len)
324 return (lhs.nCompare(to.smival.value.string.len, to) != 0);
327 //===============[ less than < operator overloaded ]==================
328 int operator<(const OctetStr &lhs, const char *rhs)
331 int maxlen = lhs.smival.value.string.len > to.smival.value.string.len
332 ? lhs.smival.value.string.len : to.smival.value.string.len;
333 return (lhs.nCompare(maxlen,to) < 0);
336 //===============[ less than <= operator overloaded ]=================
337 int operator<=(const OctetStr &lhs, const char *rhs)
340 int maxlen = lhs.smival.value.string.len > to.smival.value.string.len
341 ? lhs.smival.value.string.len : to.smival.value.string.len;
342 return (lhs.nCompare(maxlen, to) <= 0);
345 //===============[ greater than > operator overloaded ]===============
346 int operator>(const OctetStr &lhs, const char *rhs)
349 int maxlen = lhs.smival.value.string.len > to.smival.value.string.len
350 ? lhs.smival.value.string.len : to.smival.value.string.len;
351 return (lhs.nCompare(maxlen, to) > 0);
354 //===============[ greater than >= operator overloaded ]==============
355 int operator>=(const OctetStr &lhs, const char *rhs)
358 int maxlen = lhs.smival.value.string.len > to.smival.value.string.len
359 ? lhs.smival.value.string.len : to.smival.value.string.len;
360 return (lhs.nCompare(maxlen, to) >= 0);
363 //===============[ append operator, appends a string ]================
364 OctetStr& OctetStr::operator+=(const char *a)
370 if (!a || ((slen = strlen(a)) == 0))
373 nlen = slen + (size_t) smival.value.string.len; // total len of new octet
374 tmp = (SmiLPBYTE) new unsigned char[nlen]; // get mem needed
378 // copy in the original 1st
379 MEMCPY(tmp, smival.value.string.ptr, smival.value.string.len);
380 // copy in the string
381 MEMCPY(tmp + smival.value.string.len, a, slen);
382 // delete the original
383 if (smival.value.string.ptr)
384 delete [] smival.value.string.ptr;
385 // point to the new one
386 smival.value.string.ptr = tmp;
387 smival.value.string.len = SAFE_INT_CAST(nlen);
394 //================[ append one OctetStr to another ]==================
395 OctetStr& OctetStr::operator+=(const OctetStr& octet)
400 if (!octet.validity || !((slen = (size_t)octet.len())))
403 nlen = slen + (size_t) smival.value.string.len; // total len of new octet
404 tmp = (SmiLPBYTE) new unsigned char[nlen]; // get mem needed
408 // copy in the original 1st
409 MEMCPY(tmp, smival.value.string.ptr, smival.value.string.len);
410 // copy in the string
411 MEMCPY(tmp + smival.value.string.len, octet.data(), slen);
412 // delete the original
413 if (smival.value.string.ptr )
414 delete [] smival.value.string.ptr;
415 // point to the new one
416 smival.value.string.ptr = tmp;
417 smival.value.string.len = SAFE_INT_CAST(nlen);
424 //================[ appends a char ]==================================
425 OctetStr& OctetStr::operator+=(const unsigned char c)
429 // get the memory needed plus one extra byte
430 tmp = (SmiLPBYTE) new unsigned char[smival.value.string.len + 1];
434 MEMCPY(tmp, smival.value.string.ptr, smival.value.string.len);
435 tmp[smival.value.string.len] = c; // assign in new byte
437 if (smival.value.string.ptr) // delete the original
438 delete [] smival.value.string.ptr;
440 smival.value.string.ptr = tmp; // point to new one
441 smival.value.string.len++; // up the len
445 return *this; // return self reference
448 //================[ compare n elements of an Octet ]==================
449 int OctetStr::nCompare(const unsigned long n, const OctetStr &o) const
452 unsigned long w,str_len;
454 if (n == 0) return 0; // Nothing to compare, strings are equal
456 // both are empty, they are equal
457 if ((smival.value.string.len == 0) && (o.smival.value.string.len == 0))
460 // self is empty and param has something
461 if ((smival.value.string.len == 0) && (o.smival.value.string.len > 0))
464 // self has something and param has nothing
465 if ((smival.value.string.len > 0) && (o.smival.value.string.len == 0))
468 // now: n > 0; this.len > 0; o.len > 0 !!!
470 // pick the Min of n, this and the param len
471 // this is the maximum # to iterate a search
472 str_len = smival.value.string.len < o.smival.value.string.len
473 ? smival.value.string.len : o.smival.value.string.len;
474 w = (n <= str_len) ? n : str_len;
479 if (smival.value.string.ptr[z] < o.smival.value.string.ptr[z])
480 return -1; // less than
481 if (smival.value.string.ptr[z] > o.smival.value.string.ptr[z])
482 return 1; // greater than
487 // set n_max to min(n, max(len of strings))
488 n_max = smival.value.string.len > o.smival.value.string.len
489 ? smival.value.string.len : o.smival.value.string.len;
490 if (n< n_max) n_max = n;
492 if (w < n_max) // ==> we have compared too few bytes
494 if (smival.value.string.len < o.smival.value.string.len)
502 //================[ ASCII format return ]=============================
503 const char *OctetStr::get_printable() const
505 if ((m_changed == false) &&
506 (output_last_function == OutputFunctionDefault))
507 return output_buffer;
509 for (unsigned long i=0; i < smival.value.string.len; i++)
511 if ((smival.value.string.ptr[i] != '\r')&&
512 (smival.value.string.ptr[i] != '\n')&&
513 (isprint((int) (smival.value.string.ptr[i]))==0))
514 switch (hex_output_type)
516 case OutputClear: return get_printable_clear();
517 case OutputHexAndClear:
519 default: return get_printable_hex();
523 OctetStr *ncthis = PP_CONST_CAST(OctetStr*, this);
524 if (output_buffer_len < smival.value.string.len + 1)
526 if (output_buffer) delete [] ncthis->output_buffer;
528 ncthis->output_buffer = new char[smival.value.string.len + 1];
529 if (!ncthis->output_buffer)
531 ncthis->output_buffer_len = 0;
532 return output_buffer;
534 ncthis->output_buffer_len = smival.value.string.len + 1;
536 if (smival.value.string.len)
537 MEMCPY(ncthis->output_buffer,
538 smival.value.string.ptr, (unsigned int) smival.value.string.len);
539 ncthis->output_buffer[smival.value.string.len] = '\0';
541 ncthis->m_changed = false;
542 ncthis->output_last_function = OutputFunctionDefault;
544 return output_buffer;
547 //================[ ASCII format return ]=============================
548 const char *OctetStr::get_printable_clear() const
550 if ((m_changed == false) &&
551 (output_last_np_char == nonprintable_char) &&
552 (output_last_function == OutputFunctionClear))
553 return output_buffer;
555 OctetStr *ncthis = PP_CONST_CAST(OctetStr*, this);
556 if (output_buffer_len < smival.value.string.len + 1)
558 if (output_buffer) delete [] ncthis->output_buffer;
560 ncthis->output_buffer = new char[smival.value.string.len + 1];
561 if (!ncthis->output_buffer)
563 ncthis->output_buffer_len = 0;
564 return output_buffer;
566 ncthis->output_buffer_len = smival.value.string.len + 1;
569 if (smival.value.string.len)
571 for (unsigned long i=0; i < smival.value.string.len; i++)
573 if (isprint((int) (smival.value.string.ptr[i]))==0)
574 ncthis->output_buffer[i] = nonprintable_char;
576 ncthis->output_buffer[i] = smival.value.string.ptr[i];
580 ncthis->output_buffer[smival.value.string.len] = '\0';
582 ncthis->output_last_np_char = nonprintable_char;
583 ncthis->m_changed = false;
584 ncthis->output_last_function = OutputFunctionClear;
586 return output_buffer;
590 //================[ general Value = operator ]========================
591 SnmpSyntax& OctetStr::operator=(const SnmpSyntax &val)
593 if (this == &val) return *this; // protect against assignment from self
595 // blow away the old value
596 if (smival.value.string.ptr)
598 delete [] smival.value.string.ptr;
599 smival.value.string.ptr = 0;
601 smival.value.string.len = 0;
605 switch (val.get_syntax()){
606 case sNMP_SYNTAX_OPAQUE:
607 case sNMP_SYNTAX_BITS:
608 case sNMP_SYNTAX_OCTETS:
609 case sNMP_SYNTAX_IPADDR:
610 set_data(((OctetStr &)val).smival.value.string.ptr,
611 ((OctetStr &)val).smival.value.string.len);
619 #define ATOI(x) if ((x >= 48) && (x <= 57)) x = x-48; /* 0-9 */ \
620 else if ((x >= 65) && (x <= 70)) x = x-55; /* A-F */ \
621 else if ((x >= 97) && (x <=102)) x = x-87; /* a-f */ \
624 //=======[ create an octet string from a hex string ]===================
625 OctetStr OctetStr::from_hex_string(const OctetStr &hex_string)
629 unsigned int hex_len = 0;
631 // make sure the string has at least one byte
632 if (hex_string.len() == 0) return val;
634 // allocate max needed space for copy without spaces
635 unsigned char *hex, *hex_ptr;
636 hex = hex_ptr = new unsigned char[hex_string.len()];
637 if (!hex) return val;
640 const unsigned char *ptr = hex_string.smival.value.string.ptr;
641 for (p = hex_string.len(); p > 0; p--)
643 unsigned char c = *ptr++;
651 // leading 0 may be omitted
654 unsigned char c = hex[0];
666 unsigned char c = hex[p++];
667 unsigned char d = hex[p++];
679 //================[ format the output into hex ]========================
680 const char *OctetStr::get_printable_hex() const
682 if ((m_changed == false) && (output_last_type == hex_output_type) &&
683 (output_last_np_char == nonprintable_char) &&
684 (output_last_function == OutputFunctionHex))
685 return output_buffer;
688 char char_buf[80]; // holds ASCII representation of data
689 char *buf_ptr; // pointer into ASCII listing
690 char *line_ptr; // pointer into Hex listing
691 unsigned int storageNeeded; // how much space do we need ?
692 int local_len = (int) smival.value.string.len;
693 unsigned char *bytes = smival.value.string.ptr;
695 storageNeeded = (unsigned int) ((smival.value.string.len/16)+1) * 72 + 1;
696 OctetStr *ncthis = PP_CONST_CAST(OctetStr*, this);
698 if (output_buffer_len < storageNeeded)
700 if (output_buffer) delete [] ncthis->output_buffer;
702 ncthis->output_buffer = new char[storageNeeded];
703 if (!ncthis->output_buffer)
705 ncthis->output_buffer_len = 0;
706 return output_buffer;
708 ncthis->output_buffer_len = storageNeeded;
711 line_ptr = ncthis->output_buffer;
713 /*----------------------------------------*/
714 /* processing loop for entire data buffer */
715 /*----------------------------------------*/
716 while (local_len > 0)
718 cnt = 16; /* print 16 bytes per line */
720 sprintf(line_ptr, " ");
721 line_ptr += 2; /* indent */
723 /*-----------------------*/
724 /* process a single line */
725 /*-----------------------*/
726 while (cnt-- > 0 && local_len-- > 0)
728 sprintf(line_ptr, "%2.2X ", *bytes);
730 line_ptr +=3; /* the display of a byte always 3 chars long */
734 *buf_ptr++ = nonprintable_char;
738 *buf_ptr = 0; // null terminate string
740 /*----------------------------------------------------------*/
741 /* this is to make sure that the ASCII displays line up for */
742 /* incomplete lines of hex */
743 /*----------------------------------------------------------*/
751 /*------------------------------------------*/
752 /* append the ASCII display to the Hex line */
753 /*------------------------------------------*/
754 if (hex_output_type == OutputHex)
757 sprintf(line_ptr," %s%s", char_buf, linefeed_chars);
758 line_ptr += 3 + strlen(char_buf) + strlen(linefeed_chars);
761 ncthis->output_last_type = hex_output_type;
762 ncthis->output_last_np_char = nonprintable_char;
763 ncthis->m_changed = false;
764 ncthis->output_last_function = OutputFunctionHex;
766 return output_buffer;
770 //==============[ Null out the contents of the string ]===================
771 void OctetStr::clear()
773 if (smival.value.string.len > 0)
775 memset(smival.value.string.ptr, 0, smival.value.string.len);
776 smival.value.string.len = 0;
780 memset(output_buffer, 0, output_buffer_len);
784 //============[Return the space needed for serialization]=================
785 int OctetStr::get_asn1_length() const
787 if (smival.value.string.len < 0x80)
788 return smival.value.string.len + 2;
789 else if (smival.value.string.len < 0x100)
790 return smival.value.string.len + 3;
791 else if (smival.value.string.len < 0x10000)
792 return smival.value.string.len + 4;
793 else if (smival.value.string.len < 0x1000000)
794 return smival.value.string.len + 5;
795 return smival.value.string.len + 6; // should be safe for some time...
798 //========[Set the character for linefeeds in get_printable() functions]====
799 bool OctetStr::set_linefeed_chars(const char* lf_chars)
801 if (!lf_chars) return false;
802 if (strlen(lf_chars) > 2) return false;
804 linefeed_chars[2] = 0;
805 linefeed_chars[1] = lf_chars[1];
806 linefeed_chars[0] = lf_chars[0];
811 //===============[ append or shorten the data buffer ]================
812 bool OctetStr::set_len(const unsigned long new_len)
816 if (new_len <= smival.value.string.len)
818 smival.value.string.len = new_len;
823 if (smival.value.string.ptr) delete [] smival.value.string.ptr;
824 smival.value.string.ptr = 0;
830 tmp = (SmiLPBYTE) new unsigned char[new_len]; // get mem needed
832 if (!tmp) return false;
834 if (smival.value.string.ptr)
835 MEMCPY(tmp, smival.value.string.ptr, smival.value.string.len);
836 memset(tmp + smival.value.string.len, 0, new_len - smival.value.string.len);
837 if (smival.value.string.ptr)
838 delete [] smival.value.string.ptr;
839 smival.value.string.ptr = tmp;
840 smival.value.string.len = new_len;
849 #ifdef SNMP_PP_NAMESPACE
850 }; // end of namespace Snmp_pp