Trim/Truncate string to a maximum number of bytes - vb.net

I am working with some MP3s in ASP.NET coding in VB and have come across a couple of problems with the ID3 tag length limits.
It seems that most tags have a limit of 30 bytes.
I know how to get the length in bytes of a string, but want to be able to trim a string to a maximum of 30 bytes, minus however many bytes ... is, so that where needed I can trim a title to "this is part of a title..." where the total is <= 30 bytes.
EDIT:
For clarification;
The titles are string values, that must be <= 30 bytes.
Using ServiceStack I am able to easily convert my string to a byte array:
Dim bytes as byte() = "This title".ToAsciiBytes()
Then I get the length in bytes:
Dim L as integer = bytes.length()
What I need next is to grab just the first 30 bytes and convert back to a string (which is simply bytes.FromAsciiBytes())

Public Function FormatTitle(ByVal title As String) As String
Dim byte() As Byte = Encoding.ASCII.GetBytes(title)
If bytes.Length > 30 Then
Dim dot As Byte = 46 'ascii value of "."
bytes(27) = dot
bytes(28) = dot
bytes(29) = dot
Array.Resize(bytes, 30)
End If
Return Encoding.ASCII.GetString(bytes)
End Function

Related

How can I read a specific byte in a byte array in VB.NET?

I have a binary file being loaded into a Byte array using Dim settingsBinary As Byte() = My.Computer.FileSystem.ReadAllBytes(settingsFile) where settingsFile is the path to my binary file.
Let's say that my binary file has got three bytes and I want to read the first byte as a Boolean (00 = False, 01 = True). How can I get those bytes? I have tried to use this question's answer to read those three bytes, but I can't wrap my head around it.
Just to clarify, I need to get the three bytes separately: Get the first byte, then set CheckBox1.Checked to the first byte, and so on with the other bytes.
A byte array works just like any other array: You can use an indexer to access a specific element.
Dim firstByte As Byte = settingsBinary(0)
Dim secondByte As Byte = settingsBinary(1)
Dim thirdByte As Byte = settingsBinary(2)
And then you can convert the byte into a boolean:
Dim firstBoolean As Boolean
Select Case firstByte
Case 0
firstBoolean = False
Case 1
firstBoolean = True
Case Else
Throw New Exception("Invalid first byte in settings file: " & firstByte)
End Select
(Generalizing the conversion logic into a method that can be used for all three bytes is left as an exercise to the reader.)

Get first three bits from a byte

My question is simple, i need to convert the first three bits of a byte to a integer (Enum) value. However the things i try i always get a 0 back. This is wat the document says:
Bit 0-3: These bits indicate the connection state.
Value 0 to 14 indicate the connection state. Value 3 = Connected
Now the response i get (from a serial device) is a encoded byte stream of ASCII hex values, so i first need to convert it from a hex string to byte array and then get the bits from it. This is my code so far:
Dim strResonse As String = "0C03" 'This should result in a connection state value of 3
Dim ConState(2) As Byte
ConState = HexStringToByteArray(strResonse)
Dim int As Integer = ConState(1) << 1 And ConState(1) << 2 And ConState(1) << 3
Debug.Print(int.ToString)
Private Function HexStringToByteArray(ByVal shex As String) As Byte()
Dim B As Byte() = Enumerable.Range(0, shex.Length).Where(Function(x) x Mod 2 = 0).[Select](Function(x) Convert.ToByte(shex.Substring(x, 2), 16)).ToArray()
Return Enumerable.Range(0, shex.Length).Where(Function(x) x Mod 2 = 0).[Select](Function(x) Convert.ToByte(shex.Substring(x, 2), 16)).ToArray()
End Function
It would be easier to use bit operation
Dim connectionState As Integer
Dim response As Integer = &HC03
' Get the first 4 bits. 15 in binary is 1111
connectionState = response And 15
If your input is really a string, there a built-in way to convert to integer.
Dim response As Integer = Convert.ToInt32("C03", 16)
If you really want to get an array, I suggest you use the built in method.
Dim allBits As Byte() = BitConverter.GetBytes(response)
There also the BitArray class that can be handy.

VB Hex to DocX Object

I have a selection of docx files stored as blob data in hexadecimal, I need to retrieve these so I can access the text within.
So far, I have converted the hex to string format with the following:
Dim blob = BLOB DATA
Dim con As String = String.Empty
For x = 2 To st.Length - 2 Step 2
con &= ChrW(CInt("&H" & st.Substring(x, 2)))
Next
However, if I then save the output from this as a .docx the file will not open because it is 'corrupt'. I presume that is why when I load this string into a memorystream and then try and use Novacode.DocX.Load(memoryStream) it gives me a similar corruption error.
I have tried splitting to byte array in two fashions, both give me different results.
System.Text.Encoding.Default.GetBytes(hex)
I have also tried.
Public Function HexToByteArray(hex As String) As Byte()
Dim upperBound As Integer = hex.Length \ 2
If hex.Length Mod 2 = 0 Then
upperBound -= 1
Else
hex = "0" & hex
End If
Dim bytes(upperBound) As Byte
For i As Integer = 2 To upperBound
bytes(i) = Convert.ToByte(hex.Substring(i * 2, 2), 16)
Next
Return bytes
End Function
I then tried converting them both to a memory stream and using them to create a DocX object like so:
Dim doc As DocX = DocX.Load(New MemoryStream(bytes))
docx is not a text format, it's a binary format. Thus, converting it to a string is just plain wrong. Your end result needs to be a byte array.
Knowing that, your problem can be split into two simpler problems:
Split your hex string into strings of two characters each. See this SO question for details (or keep your existing loop, which is perfectly fine):
How to split a string by x amount of characters
Convert those "small" strings, which contain the hexadecimal representation of a byte, into bytes. See this SO question for details:
How do I convert a Hexidecimal string to a Byte Array?
Combining those two solutions is left as an exercise to the reader. We don't want to spoil all the fun or ruin the learning experience. ;-)

.NET - Computing SHA512 with SHA512Managed - Why two "==" when converting to string?

For some reason everytime i compute a sha512 hash and convert it to a string, the two last characters are ==. Any idea why?
Function GetSHA512FromStringAsString(ByVal strdata As String)
Dim data As Byte() = StringToByte(strdata)
Dim result() As Byte
Dim shaM As New SHA512Managed()
result = shaM.ComputeHash(data)
Return ByteToString(result)
End Function
Function ByteToString(ByVal dBytes() As Byte)
Dim strText = Convert.ToBase64String(dBytes)
Return strText
End Function
Thanks!
Base64 strings can end in = or == based on the number of bytes being encoded. See http://en.wikipedia.org/wiki/Base64#Padding
It's the Base64 padding you see: Base64 transforms groups of 4 bytes in 3 bytes, which means that the last encoded group will not always be complete - depending on the length of the input string it will contain 1, 2 or 3 bytes. This is solved by padding, and the == you see here is caused by having just 1 used byte in the last encoded group of 3.
The full explanation can be found on Wikipedia

VB.Net - Converting multi-byte hex values to decimal

How would I convert the two individual byte values (in hex) to a decimal value representing the concatenated hex values? For example, if I have the
Dim byte1 As Byte = &H99
Dim byte2 As Byte = &H99
' I want the decimal representation of the hex value "9999"
' (byte1.ToString + byte2.ToString) which should be "39321"
Currently I use the following code:
Dim decVal as integer
decVal = Val("&H" + Hex$(byte1).ToString + Hex$(byte2).ToString)
However, when I use this, the value (decVal) comes out to "-26215"
What am I doing wrong in the conversion here?
Try the following:
decVal = byte1 * 256 + byte2
Your problem is when you call Val("&H9999"), if you use CInt("&H9999") or Integer.Parse("9999", System.Globalization.NumberStyles.HexNumber) you would get the correct answer (in this case at least)
If you look at the output from:
decVal = Val("&H9999")
Console.WriteLine(decVal.ToString("X"))
you get FFFF9999
I'm not sure why this is happening, but I would see this as a reason not to use the Val function to parse hexadecimal strings
#Patrick McDonald has a good inline way of doing it and if that's what you're looking for then I recommend using that. But I can't resist not giving you the overly complicated but cross-platform and expanded versions. One thing to note, you are asking to convert bytes in big-endian mode which is a very important topic to understand if you're playing with bytes.
Both functions below take a param array and perform conversions but in two different ways. One handles an arbitrarily large byte array (bound only by platform restrictions) and the other uses the built-in converter class that reads byte arrays.
Once again, let me stress the "overly complicated" part.
Private Shared Function ConvertBytes2(ByVal ParamArray bytes() As Byte) As UInt32
''//Reverse the array order
Dim NewBytes = bytes.Reverse().ToList().ToArray()
''//Our return value
Dim Dec As UInt32 = 0
''//Temporary value for bit shifting
Dim T As UInt32
''//Loop through the bytes from left to right
For I = (NewBytes.Count - 1) To 0 Step -1
''//Grab the byte
T = NewBytes(I)
''//Shift it and add to our return value
Dec += T << (8 * I)
Next
Return Dec
End Function
Private Shared Function ConvertBytes1(ByVal ParamArray bytes() As Byte) As UInt32
''//We want to read the bytes in big-endian order but BitConverter works in little-endian mode on most Windows systems (but not all) so convert if needed
Dim NewBytes() As Byte
If BitConverter.IsLittleEndian Then
NewBytes = bytes.Reverse().ToList().ToArray()
Else
NewBytes = bytes
End If
''//Our return value
Dim Dec As UInt32
''//BitConverter can return UIn16, 32 or 64, we're only supporting 16 and 32 below
If NewBytes.Count = 2 Then
Dec = BitConverter.ToUInt16(NewBytes, 0)
ElseIf NewBytes.Count = 4 Then
Dec = BitConverter.ToUInt32(NewBytes, 0)
Else
''//Invalid number of bytes sent
Throw New ArgumentOutOfRangeException("bytes")
End If
Return Dec
End Function
Dim Byte1 As Byte = &HA
Dim Byte2 As Byte = &H99
''//&h0A99 = 2,713
Trace.WriteLine(ConvertBytes1(Byte1, Byte2))
Trace.WriteLine(ConvertBytes2(Byte1, Byte2))