Working with Octet Strings

Octet String is an SMI data type used to process arrays of Byte values. Unlike what the name suggests, this data type is not limited to string values but can store any byte based data type (including binary data).

In the Snmp#Net library, Octet String data type is represented with the OctetString class.

Calling base OctetString constructor initializes a new instance of the class with the internal byte buffer set to null:


OctetString ostr = new OctetString();
Console.WriteLine("OctetString.Length: {0}", ostr.Length);
// Prints: OctetString.Length: 0

If you have data you wish to initialize the OctetString class with, then there are class constructors that will allow you to do that at the class initialization:

Most basic constructor that initializes the class data takes a byte array as an argument:


byte[] buf = new byte[] { 0x11, 0xfa, 0xbb, 0xba, 0x00 };
OctetString ostr = new OctetString(buf);
Console.WriteLine("OctetString.Length: {0}", ostr.Length);
// Prints: OctetString.Length: 5
Console.WriteLine("OctetString: {0}", ostr.ToString());
// Prints: OctetString: 11 FA BB BA 00

In the above example, we have initialized the class with binary values (outside of the ASCII character set value range), and you can see that OctetString.ToString() method recognized that values contained within the class are not printable ASCII characters and it returned them as hex value representations formatted into a string.

You can test OctetString class instances to see if they contain non printable characters by accessing OctetString.IsHex property. This property has one caveat and that is that hex value 0x00 at the end of the buffer is not considered a hex value. This is a standard way of terminating strings in C/C++ programming languages and some of the agents encode OctetString data without trimming this character from the end of ASCII string values.

You can also force printable string to be returned as a hex value represented string by calling OctetString.ToHexString() method.

There is no way to force hex string to be represented as a printable ASCII string.

Coming back to the constructor example above, one feature of this example is that byte array that is passed to the class is duplicated before being assigned to the class internal value removing any relationship between the class instance and the argument.

This is easily demonstrated this way:


byte[] buf = new byte[] { 0x11, 0xfa, 0xbb, 0xba, 0x00 };
OctetString ostr = new OctetString(buf);
Console.WriteLine("OctetString: {0}", ostr.ToString());
// Prints: OctetString: 11 FA BB BA 00
buf[0] = 0x10;
Console.WriteLine("OctetString: {0}", ostr.ToString());
// Prints: OctetString: 11 FA BB BA 00

As you can see from the above example, once OctetString is initialized with the byte array argument, changes to the array do not affect contents of the class. This behavior comes with a slight performance and memory usage penalty as the new byte array is allocated for the internal use by the OctetString class and data is copied from the argument into the internal buffer.

If you wish to avoid this overhead, or would like to retain direct access to the byte array, you can assign data to the class “by reference” this way:


byte[] buf = new byte[] { 0x11, 0xfa, 0xbb, 0xba, 0x00 };
OctetString ostr = new OctetString(buf, true);
Console.WriteLine("OctetString: {0}", ostr.ToString());
// Prints: OctetString: 11 FA BB BA 00
buf[0] = 0x10;
Console.WriteLine("OctetString: {0}", ostr.ToString());
// Prints: OctetString: 10 FA BB BA 00

Second argument to the constructor of OctetString in this example is a boolean flag telling the class if internal class buffer should be set by reference (true) or not (false). When set to true, any changes to the byte array outside of the OctetString class will be reflected in the class value as demonstrated by the example above.

Since OctetString data type is used to transport both binary and ASCII text data, it only makes sense for there to be a constructor allowing class value to be set to a string value:


OctetString ostr = new OctetString("Example OctetString");
Console.WriteLine("OctetString length {0} isHex {1}: {2}",
ostr.Length, ostr.IsHex.ToString(), ostr.ToString());
// Prints: OctetString length 19 isHex False: Example OctetString

Constructor that takes a string value as an argument only functions with UTF8 encoded string (single byte per character). For other encoding types, first convert the string to a byte array using System.Text namespace classes and then initialize the OctetString class with the result.

There are two more constructors available in the OctetString class. First is the copy constructor that takes another instance of OctetString as an argument and copies data from it into the new class instance. Second takes a single byte argument and initializes the class to length 1 and value of a single byte.

With a constructed OctetString you can manipulate data in a number of ways. First you can change class data by using OctetString.Set(…) methods. They mirror the constructors in the functionality the provide:


OctetString ostr = new OctetString();
Console.WriteLine("OctetString.Length: {0}", ostr.Length);
// Prints: OctetString.Length: 0
byte[] buf = new byte[] { 0x11, 0xfa, 0xbb, 0xba, 0x00 };
ostr.Set(buf);
Console.WriteLine("OctetString length {0}: {1}", ostr.Length, ostr.ToString());
// Prints: OctetString length 5: 11 FA BB BA 00
ostr.SetRef(buf);
Console.WriteLine("OctetString length {0}: {1}", ostr.Length, ostr.ToString());
// Prints: OctetString length 5: 11 FA BB BA 00
buf[0] = 0x10;
Console.WriteLine("OctetString length {0}: {1}", ostr.Length, ostr.ToString());
// Prints: OctetString length 5: 10 FA BB BA 00
ostr.Set("Example OctetString");
Console.WriteLine("OctetString length {0} isHex {1}: {2}",
ostr.Length, ostr.IsHex.ToString(), ostr.ToString());
// Prints: OctetString length 19 isHex False: Example OctetString

OctetString.SetRef() method deviates from the method naming to make it as distinctive as possible to reflect the potential danger in setting internal class value by using assignments by reference.

Ability to append data to the existing class value is provided by OctetString.Append() methods. You can append the same data types as you can use with the constructors and Set methods.

Accessing data stored in the OctetString class can be done using the indexed access:


byte[] buf = new byte[] { 0x11, 0xfa, 0xbb, 0xba, 0x00 };
OctetString ostr = new OctetString(buf);
for (int i = 0; i < buf.Length; i++) Console.Write("{0}:{1:x2} ", i, buf[i]); Console.WriteLine(""); // Prints: 0:11 1:fa 2:bb 3:ba 4:00

When using indexed access and requesting index position outside of the bounds of the internal byte array of the OctetString class will not result in an Exception being thrown but a value of 0 being returned. This can cause you to process invalid information if not careful.

Second way to access internal OctetString information is to request a copy of the internal byte array using OctetString.ToArray() method. You can also get the same affect by casting an instance of OctetString class to byte[]:


byte[] buf = new byte[] { 0x11, 0xfa, 0xbb, 0xba, 0x00 };
OctetString ostr = new OctetString(buf);
byte[] outbuf = ostr.ToArray();
SnmpConstants.DumpHex(outbuf);
// Prints: 0000 11 fa bb ba 00
SnmpConstants.DumpHex((byte[])ostr);
// Prints: 0000 11 fa bb ba 00

byte[] operator is implicitly defined meaning you can perform any operation you can with a byte array by simply passing the OctetString class to the method without a cast.

To get a string representation of OctetString class value, you can call OctetString.ToString() method which will test the string for non-printable characters and return it as a list of hex values if any are found or as a text string if not. As mentioned earlier, you can force hex representation to be returned by using OctetString.ToHexString() method. One special case method is OctetString.ToMACAddressString() method which will only work on Ethernet addresses (strictly 6 bytes in length) and will return it in the hex format xxxx.xxxx.xxxx.

For Ethernet MAC address specific functionality, see Snmp#Net EthernetAddress class and its methods.

OctetString class supports comparison operations: ==, !=, CompareTo() and Equals(). CompareTo will compare class contents against a byte array. Equals will compare class contents with value of another OctetString class or a string.