Class TlvReader
Use this class to parse TLV (tag-length-value) constructions.
public sealed class TlvReader
- Inheritance
-
objectTlvReader
Remarks
See the User's Manual entry on TLV for an in-depth discussion of what TLV is and a general description of how to use this class.
Constructors
TlvReader(ReadOnlyMemory<byte>)
Build a new Reader object based on the given encoding.
public TlvReader(ReadOnlyMemory<byte> encoding)
Parameters
encoding
ReadOnlyMemory<byte>The TLV encoding to read.
Remarks
This sets the position of the reader to the leading byte, the first tag.
Note that the object will copy a reference to the encoding. Do not clear or alter the encoding until after the full encoding has been read and each value operated on.
Properties
HasData
Indicates whether there is more data to read or not.
public bool HasData { get; }
Property Value
- bool
Methods
PeekLength(int)
Skip the tagLength
bytes and read the length octets, decode and return
the length without advancing the reader.
public int PeekLength(int tagLength = 1)
Parameters
tagLength
intThe length of the tag to read. If this argument is not given the default length of 1 will be used.
Returns
- int
The length.
Remarks
For example, if the next byte after the tag is 0x20, this method will return 0x00000020. If the next bytes are 0x81 80, this method will return 0x00000080. For 0x82 01 00, the return is 0x0000000100.
If the next byte after the tag is an invalid or unsupported initial length octet, the method will throw an exception. Invalid initial length octets are those where the most significant bit is set but the value is not 0x81, 0x82, or 0x83. Although 0x84, and 0x85 (and higher) are valid initial length octets, they are not supported by this class. Note that 0x80 is an unsupported initial length octet (it is BER for indefinite length, and this class supports only DER length rules).
If there are not enough bytes left in the encoding to build the
length, this method will throw an exception. For example, if there
are only two bytes left in encoding, and you pass in 2 for the tag
length, this method will throw an exception. If there are two bytes
left in encoding, you pass in 1 as the tagLength
, and the initial
length octet is0x81 (which means there should be one length octet
following the 0x81), the method will throw an exception.
Note that this method does not verify if there are at least length octets available in the encoding after the tag and length, it only returns the length and the number of octets that make up the length. For example, if at the current pointer in the encoding are the octets 01 81 80, and nothing more, the method will return 0x00000080. If you try to decode (i.e. call ReadValue), that will throw an exception. But this method will return the length, even though the encoding is not valid.
Exceptions
- TlvException
The
tagLength
is unsupported, the length read is unsupported, or there was not enough data to read.
PeekTag(int)
Read the tag at the current data position, without advancing the reader.
public int PeekTag(int tagLength = 1)
Parameters
tagLength
intThe length of the tag to read. If this argument is not given the default length of 1 will be used.
Returns
- int
The tag as an int.
Remarks
The caller passes in either no argument, or 1 or 2 as the tag length. No argument passed in means the default tag length of 1 will be used. If 1, the method returns the next byte as an int. If 2, the method returns the next two bytes as an int (e.g. 71 01 is returned as 0x00007101). If you pass in any other length other than 1 or 2, this method will throw an exception.
If there is no data at the current position (the entire encoding has
been read), this method will throw an exception (check the HasData
property to verify there is a tag available). If the tagLength
is 2 and there is only one byte left in the encoding, this method throws
an exception.
Exceptions
- TlvException
The
tagLength
is unsupported, or there was not enough data to read.
ReadByte(int)
Read the TLV at the current position, return the value as a byte, and move the position to the byte beyond the current TLV.
public byte ReadByte(int expectedTag)
Parameters
expectedTag
intThe tag that should be at the current position.
Returns
- byte
A byte, the value.
Remarks
The method will verify that the tag is expected. If it is, it will read the length, verify that it is one, then read that one-byte value, and return it.
If the length of the value is not 1 (even if it is 0), this method will not advance the reader and throw an exception.
If the tag at the current position in the encoding is not what was given as the expectedTag, or if the tag and/or length make up an invalid encoding, or if there are not enough bytes left in the encoding to read the tag, length, and value, this method will not advance the reader and throw an exception.
Exceptions
- TlvException
The tag was not the expected value, the tag or length is unsupported, or there was not enough data for the lengths given.
ReadEncoded(int)
Return the entire encoding of the next element.
public ReadOnlyMemory<byte> ReadEncoded(int expectedTag)
Parameters
expectedTag
intThe tag that should be at the current position.
Returns
- ReadOnlyMemory<byte>
A new ReadOnlyMemory object containing the tag, length and value of the current TLV.
Remarks
The method will verify that the tag is expected. If it is, it will read the length, verify that the encoding has at least that many bytes, then create a new ReadOnlyMemory object that points to the entire TLV (not just the value). Note that the ReadOnlyMemory object will point to the existing encoding, it will not copy the data into a new buffer.
Note that this will not treat a NestedTlv any different from a single element. That is, if the current position points to a NestedTlv, the method will return the entire encoding, including the sub-elements.
If the tag at the current position in the encoding is not what was given as the expectedTag, or if the tag and/or length make up an invalid encoding, or if there are not enough bytes left in the encoding to read the tag, length, and value, this method will throw an exception.
For example, suppose the encoding is the following.
7C 0D 01 01 14 02 02 01 80 05 04 00 89 2C 33
This is a NestedTlv
7C 0D
01 01
14
02 02
01 80
05 04
00 89 2C 33
Suppose the internal position is at 0, the beginning of full encoding.
encoded = reader.ReadEncoded(0x7C);
This will return a new ReadOnlyMemory object that points to
7C 0D 01 01 14 02 02 01 80 05 04 00 89 2C 33
Length is 15
After the call, the internal position of the reader is at the
position just after the last byte of the value, which is beyond the
end of the full encoding.
Suppose the internal position is at 5, the beginning of the second
sub-element.
value = reader.ReadEncoded(0x02);
This will return a new ReadOnlyMemory object that points to
02 02 01 80
Length is 4
After the call, the internal position of the reader is at the
position just after the last byte of the value, which is the
next TLV: 05 04 etc.
Exceptions
- TlvException
The tag was not the expected value, the tag or length is unsupported, or there was not enough data for the lengths given.
ReadInt16(int, bool)
Read the TLV at the current position, return the value as a short (a two-byte integer), and move the position to the byte beyond the current TLV.
public short ReadInt16(int expectedTag, bool bigEndian = true)
Parameters
expectedTag
intThe tag that should be at the current position.
bigEndian
boolSpecifies whether the result should be returned as big endian (true or no argument given) or little endian (false).
Returns
- short
A short, the value.
Remarks
The method will verify that the tag is expected. If it is, it will read the length, verify that it is two, then read that two-byte value, and return it as a short.
If the length of the value is not 2 (even if it is 0 or 1), this method will not advance the reader and throw an exception.
The method will return the value in big endian (most significant byte of the short is taken from value[0]), unless the bigEndian argument is false. If it is false, the result is returned in little endian (least significant byte of the short is taken from value[0]). The bigEndian argument has a default of true. This means you can call this method and leave out the bigEndian argument, and the method will return the short in big endian format.
If the tag at the current position in the encoding is not what was given as the expectedTag, or if the tag and/or length make up an invalid encoding, or if there are not enough bytes left in the encoding to read the tag, length, and value, this method will not advance the reader and throw an exception.
Exceptions
- TlvException
The tag was not the expected value, the tag or length is unsupported, or there was not enough data for the lengths given.
ReadInt32(int, bool)
Read the TLV at the current position, return the value as an int (a four-byte integer), and move the position to the byte beyond the current TLV.
public int ReadInt32(int expectedTag, bool bigEndian = true)
Parameters
expectedTag
intThe tag that should be at the current position.
bigEndian
boolSpecifies whether the result should be returned as big endian (true or no argument given) or little endian (false).
Returns
- int
An int, the value.
Remarks
The method will verify that the tag is expected. If it is, it will read the length, verify that it is four, then read that four-byte value, and return it as an int.
If the length of the value is not 4 (even if it is 0, 1, 2, or 3), this method will not advance the reader and throw an exception.
The method will return the value in big endian (most significant byte of the int is taken from value[0]), unless the bigEndian argument is false. If it is false, the result is returned in little endian (least significant byte of the int is taken from value[0]). The bigEndian argument has a default of true. This means you can call this method and leave out the bigEndian argument, and the method will return the int in big endian format.
If the tag at the current position in the encoding is not what was given as the expectedTag, or if the tag and/or length make up an invalid encoding, or if there are not enough bytes left in the encoding to read the tag, length, and value, this method will not advance the reader and throw an exception.
Exceptions
- TlvException
The tag was not the expected value, the tag or length is unsupported, or there was not enough data for the lengths given.
ReadNestedTlv(int)
Read the TLV at the current position as a NestedTlv. Return a new TlvReader object whose position is the beginning of the NestedTlv's value, which is the tag of the NestedTlv's first sub-element. Move the position of the original reader to the byte beyond the current TLV.
public TlvReader ReadNestedTlv(int expectedTag)
Parameters
expectedTag
intThe tag that should be at the current position, the NestedTlv's tag.
Returns
- TlvReader
A new TlvReader object that contains the sub-elements of the NestedTlv, with the position set at the first sub-element.
Remarks
The new object returned will contain the encoding of the sub-elements only.
If the tag at the current position in the encoding is not what was given as the expectedTag, or if the tag and/or length make up an invalid encoding, or if there are not enough bytes left in the encoding to read the tag, length, and value, this method will throw an exception.
For example, suppose the encoding is the following.
7C 0D 01 01 14 02 02 01 80 05 04 00 89 2C 33
This is a NestedTlv
7C 0D
01 01
14
02 02
01 80
05 04
00 89 2C 33
Suppose the internal position is at 0, the beginning of full encoding.
TlvReader newReader = reader.ReadNestedTlv(0x7C);
This will return a new TlvReader object:
new reader: 01 01 14 02 02 01 80 05 04 00 89 2C 33
^
+--current position
After the call, the internal position of the original reader is at
the position just after the NestedTlv's value.
original: 7C 0D 01 01 14 02 02 01 80 05 04 00 89 2C 33
^
+--current position
Suppose the original reader is parsing something like this:
01 01 14 7A 07 31 02 01 00 32 01 20 05 04 00 89 2C 33
This is a concatenation with a NestedTlv as one of the elements.
01 01
14
7A 07
31 02
01 00
32 01
20
05 04
00 89 2C 33
Suppose the internal position is at 0, the beginning of full encoding.
ReadOnlyMemory<byte> value = reader.ReadValue(0x01);
This returned a new ReadOnlyMemory object with the contents of the
first TLV, namely the byte array { 0x14 }. It moved the pointer to
the next TLV.
01 01 14 7A 07 31 02 01 00 32 01 20 05 04 00 89 2C 33
^
+--current position
TlvReader newReader = reader.ReadNestedTlv(0x7A);
This will return a new TlvReader object:
new reader: 31 02 01 00 32 01 20
^
+--current position
After the call, the internal position of the original reader is at
the position just after the NestedTlv's value.
01 01 14 7A 07 31 02 01 00 32 01 20 05 04 00 89 2C 33
^
+--current position
Exceptions
- TlvException
The tag was not the expected value, the tag or length is unsupported, or there was not enough data for the lengths given.
ReadString(int, Encoding)
Read the TLV at the current position, return the value as a string, and move the position to the byte beyond the current TLV.
public string ReadString(int expectedTag, Encoding encoding)
Parameters
expectedTag
intThe tag that should be at the current position.
encoding
EncodingThe scheme the method will use to convert the byte array into a string, such as System.Text.Encoding.ASCII or UTF8.
Returns
- string
A string, the value.
Remarks
See the documentation for the method TlvWriter.WriteString for a discussion of strings and encodings.
The method will verify that the tag is expected. If it is, it will read the length, verify that there are enough bytes in the buffer to read, then read the value (a byte array) and returning it as a string, converting the bytes array following the scheme specified by the encoding argument.
Exceptions
- ArgumentNullException
The encoding argument is null.
- TlvException
The tag was not the expected value, the tag or length is unsupported, or there was not enough data for the lengths given.
ReadUInt16(int, bool)
Read the TLV at the current position, return the value as an unsigned short (a two-byte unsigned integer), and move the position to the byte beyond the current TLV.
[CLSCompliant(false)]
public ushort ReadUInt16(int expectedTag, bool bigEndian = true)
Parameters
expectedTag
intThe tag that should be at the current position.
bigEndian
boolSpecifies whether the result should be returned as big endian (true or no argument given) or little endian (false).
Returns
- ushort
The unsigned short value.
Remarks
The method will verify that the tag is expected. If it is, it will read the length, verify that it is two, then read and return that two-byte unsigned value.
If the length of the value is not 2 (even if it is 0 or 1), this method will not advance the reader and throw an exception.
The method will return the value in big endian (most significant byte of the short is taken from value[0]), unless the bigEndian argument is false. If it is false, the result is returned in little endian (least significant byte of the short is taken from value[0]). The bigEndian argument has a default of true. This means you can call this method and leave out the bigEndian argument, and the method will return the unsigned short in big endian format.
If the tag at the current position in the encoding is not what was given as the expectedTag, or if the tag and/or length make up an invalid encoding, or if there are not enough bytes left in the encoding to read the tag, length, and value, this method will not advance the reader and throw an exception.
Exceptions
- TlvException
An unexpected error occurred while reading from the TLV.
ReadValue(int)
Read the TLV at the current position, return the value as a byte array, and move the position to the byte beyond the current TLV.
public ReadOnlyMemory<byte> ReadValue(int expectedTag)
Parameters
expectedTag
intThe tag that should be at the current position.
Returns
- ReadOnlyMemory<byte>
A new ReadOnlyMemory object containing the value, and only the value, of the current TLV. If there is no value (length is 0), the result will be an empty object (Length is 0).
Remarks
The method will verify that the tag is expected. If it is, it will read the length, verify that the encoding has at least that many bytes, then create a new ReadOnlyMemory object that points to the value. Note that the ReadOnlyMemory object will point to the existing encoding, it will not copy the data into a new buffer.
Note that this will not treat a NestedTlv any different from a single element. That is, if the current position points to a NestedTlv, the method will return a value that is the collection of sub-elements.
If the tag at the current position in the encoding is not what was given as the expectedTag, or if the tag and/or length make up an invalid encoding, or if there are not enough bytes left in the encoding to read the tag, length, and value, this method will throw an exception.
For example, suppose the encoding is the following.
7C 0D 01 01 14 02 02 01 80 05 04 00 89 2C 33
This is a NestedTlv
7C 0D
01 01
14
02 02
01 80
05 04
00 89 2C 33
Suppose the internal position is at 0, the beginning of full encoding.
value = reader.ReadValue(0x7C);
This will return a new ReadOnlyMemory object that points to
01 01 14 02 02 01 80 05 04 00 89 2C 33
Length is 13
After the call, the internal position of the reader is at the
position just after the last byte of the value, which is beyond the
end of the full encoding. There's nothing more to read.
Suppose the internal position is at 5, the beginning of the second
sub-element.
value = reader.ReadValue(0x02);
This will return a new ReadOnlyMemory object that points to
01 80
Length is 2
After the call, the internal position of the reader is at the
position just after the last byte of the value, which is the
next TLV: 05 04 etc.
Note that the value returned is a reference to the input encoding. Do not clear or alter the encoding until after the full encoding has been read and each value operated on.
Exceptions
- TlvException
The tag was not the expected value, the tag or length is unsupported, or there was not enough data for the lengths given.
TryReadByte(out byte, int)
Try to read the TLV at the current position. If this succeeds, return
true and set the value
argument to the byte that is the V part
of the TLV, and move the position to the byte beyond the current TLV.
public bool TryReadByte(out byte value, int expectedTag)
Parameters
value
byteThe output parameter where the value will be deposited.
expectedTag
intThe tag that should be at the current position.
Returns
- bool
A boolean,
true
if the read succeeds,false
otherwise.
Remarks
This is the same as ReadByte
, except this method will not
throw an exception if there is an error in reading, only return
false
. That is, if the expected tag is not found at the
current position, or the length octets are not a valid encoding, or
the value is not a single byte, or there is not enough data in the
buffer for the length given, this method will set value
to 0
and will return false
.
See the documentation for ReadByte
for more information
on what this method does.
Note that if there is a valid TLV with the expected tag, but the
length is not 1, this method will return false
.
TryReadEncoded(out ReadOnlyMemory<byte>, int)
Try to read the TLV at the current position. If this succeeds, return
true and set the encoded
argument to a new ReadOnlyMemory
object containing the full TLV, and move the position to the byte
beyond the current TLV.
public bool TryReadEncoded(out ReadOnlyMemory<byte> encoded, int expectedTag)
Parameters
encoded
ReadOnlyMemory<byte>The output parameter where the encoded TLV will be deposited.
expectedTag
intThe tag that should be at the current position.
Returns
- bool
A boolean,
true
if the read succeeds,false
otherwise.
Remarks
This is the same as ReadEncoded
, except this method will not
throw an exception if there is an error in reading, only return
false
. That is, if the expected tag is not found at the
current position, or the length octets are not a valid encoding, or
there is not enough data in the buffer for the length given, this
method will return false
.
See the documentation for ReadEncoded
for more information
on what this method does.
TryReadInt16(out short, int, bool)
Try to read the TLV at the current position. If this succeeds, return
true and set the value
argument to the short that is the V part
of the TLV, and move the position to the byte beyond the current TLV.
public bool TryReadInt16(out short value, int expectedTag, bool bigEndian = true)
Parameters
value
shortThe output parameter where the value will be deposited.
expectedTag
intThe tag that should be at the current position.
bigEndian
boolSpecifies whether the result should be returned as big endian (true or no argument given) or little endian (false).
Returns
- bool
A boolean,
true
if the read succeeds,false
otherwise.
Remarks
This is the same as ReadInt16
, except this method will not
throw an exception if there is an error in reading, only return
false
. That is, if the expected tag is not found at the
current position, or the length octets are not a valid encoding, or
the value is not exactly two bytes, or there is not enough data in
the buffer for the length given, this method will set value
to
0 and will return false
.
See the documentation for ReadInt16
for more information
on what this method does.
Note that if there is a valid TLV with the expected tag, but the
length is not 2, this method will return false
.
TryReadInt32(out int, int, bool)
Try to read the TLV at the current position. If this succeeds, return
true and set the value
argument to the int that is the V part
of the TLV, and move the position to the byte beyond the current TLV.
public bool TryReadInt32(out int value, int expectedTag, bool bigEndian = true)
Parameters
value
intThe output parameter where the value will be deposited.
expectedTag
intThe tag that should be at the current position.
bigEndian
boolSpecifies whether the result should be returned as big endian (true or no argument given) or little endian (false).
Returns
- bool
A boolean,
true
if the read succeeds,false
otherwise.
Remarks
This is the same as ReadInt32
, except this method will not
throw an exception if there is an error in reading, only return
false
. That is, if the expected tag is not found at the
current position, or the length octets are not a valid encoding, or
the value is not exactly four bytes, or there is not enough data in
the buffer for the length given, this method will set value
to
0 and will return false
.
See the documentation for ReadInt32
for more information
on what this method does.
Note that if there is a valid TLV with the expected tag, but the
length is not 4, this method will return false
.
TryReadNestedTlv(out TlvReader, int)
Try to read the TLV at the current position as a NestedTlv. If this
succeeds, return true and set the nestedReader
argument to a
new TlvReader
object whose position is the beginning of the
NestedTlv's value, which is the tag of the NestedTlv's first
sub-element. Move the position of the original reader to the byte
beyond the current TLV.
public bool TryReadNestedTlv(out TlvReader nestedReader, int expectedTag)
Parameters
nestedReader
TlvReaderOn success, receives the new
TlvReader
object.expectedTag
intThe tag that should be at the current position, the NestedTlv's tag.
Returns
- bool
Remarks
This is the same as ReadNestedTlv
, except this method will not
throw an exception if there is an error in reading, only return
false
. That is, if the expected tag is not found at the
current position, or the length octets are not a valid encoding, or
there is not enough data in the buffer for the length given, this
method will return false
.
See the documentation for ReadNestedTlv
for more information
on what this method does.
TryReadString(out string, int, Encoding)
Try to read the TLV at the current position. If this succeeds, return
true and set the value
argument to a string
, and move
the position to the byte beyond the current TLV.
public bool TryReadString(out string value, int expectedTag, Encoding encoding)
Parameters
value
stringThe output parameter where the value will be deposited.
expectedTag
intThe tag that should be at the current position.
encoding
EncodingThe scheme the method will use to convert the byte array into a string, such as System.Text.Encoding.ASCII or UTF8.
Returns
- bool
A boolean,
true
if the read succeeds,false
otherwise.
Remarks
This is the same as ReadString
, except this method will not
throw an exception if there is an error in reading, only return
false
. That is, if the expected tag is not found at the
current position, or the length octets are not a valid encoding, or
there is not enough data in the buffer for the length given, this
method will return false
.
See the documentation for ReadString
for more information
on what this method does.
TryReadUInt16(out ushort, int, bool)
Try to read the TLV at the current position. If this succeeds, return
true and set the value
argument to the unsigned short that is the
V part of the TLV, and move the position to the byte beyond the current TLV.
[CLSCompliant(false)]
public bool TryReadUInt16(out ushort value, int expectedTag, bool bigEndian = true)
Parameters
value
ushortThe output parameter where the value will be deposited.
expectedTag
intThe tag that should be at the current position.
bigEndian
boolSpecifies whether the result should be returned as big endian (true or no argument given) or little endian (false).
Returns
- bool
A boolean,
true
if the read succeeds,false
otherwise.
Remarks
This is the same as ReadUInt16(int, bool), except this method
will not throw an exception if there is an error in reading, only return
false
. That is, if the expected tag is not found at the
current position, or the length octets are not a valid encoding, or
the value is not exactly two bytes, or there is not enough data in
the buffer for the length given, this method will set value
to
0 and will return false
.
See ReadUInt16(int, bool) for more information on what this method does.
Note that if there is a valid TLV with the expected tag, but the
length is not 2, this method will return false
.
TryReadValue(out ReadOnlyMemory<byte>, int)
Try to read the TLV at the current position. If this succeeds, return
true and set the value
argument to a new ReadOnlyMemory
object containing the value as a byte array, and move the position to
the byte beyond the current TLV.
public bool TryReadValue(out ReadOnlyMemory<byte> value, int expectedTag)
Parameters
value
ReadOnlyMemory<byte>The output parameter where the value will be deposited.
expectedTag
intThe tag that should be at the current position.
Returns
- bool
A boolean,
true
if the read succeeds,false
otherwise.
Remarks
This is the same as ReadValue
, except this method will not
throw an exception if there is an error in reading, only return
false
. That is, if the expected tag is not found at the
current position, or the length octets are not a valid encoding, or
there is not enough data in the buffer for the length given, this
method will return false
.
See the documentation for ReadValue
for more information
on what this method does.
Note that the value returned is a reference to the input encoding. Do not clear or alter the encoding until after the full encoding has been read and each value operated on.