none
Converting a binary structure from little endian to big endian RRS feed

  • Question

  • I need to send message from windows server to HP server to TCP/IP sockets. I am using .NET Framework 4.0 with Visual Studio 2012. I am struck in converting little to big endian.

    I store all the values that has to be sent to the other machine in a structure and then convert the structure to a byte array. This byte array is then sent through the socket. There are several message structures like this and we have developed it fully. Now it was said that the other system is HP server and we need to convert into Big Endian before sending it and also convert the Big Endian to little Endian after we receive the data. Is there any easy way for converting this in the structure form?

    The structure that I have:

    <StructLayout(LayoutKind.Sequential, Pack:=1)> Friend Structure ACMRequestMessage
            Friend MessageHeader As HeaderMessageStructure.MessageHeader
            Friend BusinessDate As Integer
            <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=CustomConstants.VariableLengths.NoOfDigitsForTradeNumber)> _
            Friend ACMReferenceID As String
            <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=CustomConstants.VariableLengths.NoOfDigitsForBaseCurrency)> _
            Friend BaseCurrency As String
            <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=CustomConstants.VariableLengths.NoOfDigitsForCounterCurrency)> _
            Friend CounterCurrency As String
            <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=CustomConstants.VariableLengths.NoOfDigitsForMemberID)> _
            Friend MemberID As String
            Friend USDSellorBuy As Char
            <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=CustomConstants.VariableLengths.NoOfDigitsForSettlementType)> _
            Friend SettlementType As String
            Friend SettlementDate As Integer
            Friend TradeAmount As Double
        End Structure

    The code that I use to convert a structure to a byte array:

    In the below code the "message" variable contains the ACMMessage Structure and the byteArray is returned back. Then the byteArray is sent through the TCP/IP socket. The copyStartIndex will be always 0 in this case.

    Public Shared Function GetByteArrayForGivenMessageStructure(ByVal message As Object, ByRef byteArray As Byte(), ByVal CopyStartIndex As Integer) As Boolean
            Try
                Dim messageSize As Integer
    
                Dim pointerToData As IntPtr
    
                messageSize = Marshal.SizeOf(message)
    
                pointerToData = Marshal.AllocHGlobal(messageSize)
    
                Marshal.StructureToPtr(message, pointerToData, True)
    
                Marshal.Copy(pointerToData, byteArray, CopyStartIndex, messageSize)
    
                Marshal.FreeHGlobal(pointerToData)
    
                Return True
            Catch ex As Exception
                Throw ex
            End Try
        End Function

    In this type of development how should I convert from litter to big endian and vice versa?


    Regards, Peri

    Tuesday, September 30, 2014 9:56 AM

Answers

  • If it is a single field like double or string or integer the it will work as you said. But I am working with a structure.

    Regards, Peri

    That doesn't really matter... you know how many bytes it takes to represent each field of the structure; this is determined by the data type for most of your fields, and by the specified size constant for the string.  You also know that each field's data is present in the declared order because you specified Sequential layout.

    So, use either proposed method of reversing a byte array and convert each sub-chunk of the overall byte array according to each field size.  Given this example layout:

    'Total size is 71 bytes
    <StructLayout(LayoutKind.Sequential, Pack:=1)> Friend Structure ACMRequestMessage
        '4 byte header
        Friend MessageHeader As HeaderMessageStructure.MessageHeader
        '4 byte integer
        Friend BusinessDate As Integer
        '10 byte string
        <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=CustomConstants.VariableLengths.NoOfDigitsForTradeNumber)> _
        Friend ACMReferenceID As String
        '10 byte string
        <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=CustomConstants.VariableLengths.NoOfDigitsForBaseCurrency)> _
        Friend BaseCurrency As String
        '10 byte string
        <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=CustomConstants.VariableLengths.NoOfDigitsForCounterCurrency)> _
        Friend CounterCurrency As String
        '10 byte string
        <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=CustomConstants.VariableLengths.NoOfDigitsForMemberID)> _
        Friend MemberID As String
        '1 byte char
        Friend USDSellorBuy As Char
        '10 byte string
        <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=CustomConstants.VariableLengths.NoOfDigitsForSettlementType)> _
        Friend SettlementType As String
        '4 byte integer
        Friend SettlementDate As Integer
        '8 byte double
        Friend TradeAmount As Double
    End Structure
    
    Public Class HeaderMessageStructure
        Public Structure MessageHeader
            Public ID As Integer
        End Structure
    End Class
    
    Public Class CustomConstants
        Public Class VariableLengths
            Public Const NoOfDigitsForTradeNumber As Integer = 10
            Public Const NoOfDigitsForBaseCurrency As Integer = 10
            Public Const NoOfDigitsForCounterCurrency As Integer = 10
            Public Const NoOfDigitsForMemberID As Integer = 10
            Public Const NoOfDigitsForSettlementType As Integer = 10
        End Class
    End Class

    You should be able to use a routine something like this:

    Dim messageSize As Integer
    Dim pointerToData As IntPtr
    
    messageSize = Marshal.SizeOf(Message)
    Dim byteArray(messageSize - 1) As Byte
    
    pointerToData = Marshal.AllocHGlobal(messageSize)
    Marshal.StructureToPtr(Message, pointerToData, True)
    Marshal.Copy(pointerToData, byteArray, 0, messageSize)
    Marshal.FreeHGlobal(pointerToData)
    
    Dim intSize As Integer = Marshal.SizeOf(New Integer)
    Dim charSize As Integer = Marshal.SizeOf(New Char)
    Dim doubleSize As Integer = Marshal.SizeOf(New Double)
    Dim index As Integer = 0
    For Each length As Integer In {intSize, intSize, CustomConstants.VariableLengths.NoOfDigitsForTradeNumber,
                                   CustomConstants.VariableLengths.NoOfDigitsForBaseCurrency,
                                   CustomConstants.VariableLengths.NoOfDigitsForCounterCurrency,
                                   CustomConstants.VariableLengths.NoOfDigitsForMemberID, charSize,
                                   CustomConstants.VariableLengths.NoOfDigitsForSettlementType, intSize, doubleSize}
        Array.Reverse(byteArray, index, length)
        index = length
    Next
    


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    • Proposed as answer by dbasnett Wednesday, October 1, 2014 10:53 AM
    • Marked as answer by Carl CaiModerator Tuesday, October 7, 2014 6:02 AM
    Tuesday, September 30, 2014 5:11 PM
    Moderator

All replies

  • Have you tried

    Array.Reverse(byteArray)
    ?



    'Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it.'  JohnWein

    Multics

    My Serial Port Answer

    Tuesday, September 30, 2014 10:28 AM
  • Yes. This will reverse the entire byte array and will not work. Each and every field in the structure has to be reversed.

    Regards, Peri

    Tuesday, September 30, 2014 10:57 AM
  • The .Reverse method has an overload that takes a start and a length.

    http://msdn.microsoft.com/en-us/library/z78xtwts%28v=vs.110%29.aspx


    'Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it.'  JohnWein

    Multics

    My Serial Port Answer

    Tuesday, September 30, 2014 11:58 AM
  • Are you dealing with 2 byte or 4 bytes that are backwards?  The code below will revese 2 bytes. 

    Dim byteArray As Byte() = Nothing Dim temp As Byte For i = 0 To (byteArray.Length - 1) Step 2 temp = byteArray(i) byteArray(i) = byteArray(i + 1) byteArray(i) = temp Next i

    You can use similar code for 4 bytes

            Dim byteArray As Byte() = Nothing
            Dim temp1 As Byte
            Dim temp2 As Byte
            For i = 0 To (byteArray.Length - 1) Step 4
                temp1 = byteArray(i)
                temp2 = byteArray(i + 1)
                byteArray(i) = byteArray(i + 2)
                byteArray(i + 1) = byteArray(i + 3)
                byteArray(i + 2) = temp1
                byteArray(i + 3) = temp2
            Next i


    jdweng

    Tuesday, September 30, 2014 12:05 PM
  • I think your structure is too big.  You might consider converting it to a class with properties, and adding the code that you're looking for to that class.  I foresee two methods that each return a byte array, ToBigEndian and ToLittleEndian.

    Maybe you should explain how you convert your posted structure to a "byte array".

    Rudy   =8^D


    Mark the best replies as answers. "Fooling computers since 1971."

    http://thesharpercoder.com/

    Tuesday, September 30, 2014 12:21 PM
  • If it is a single field like double or string or integer the it will work as you said. But I am working with a structure.

    Regards, Peri

    Tuesday, September 30, 2014 2:07 PM
  • I have around 40 different structures. Converting all of these would be a huge job.

    In my question itself the code to convert the structure to byte array is given. In any case pasting it here again.

    Public Shared Function GetByteArrayForGivenMessageStructure(ByVal message As Object, ByRef byteArray As Byte(), ByVal CopyStartIndex As Integer) As Boolean
            Try
                Dim messageSize As Integer
    
                Dim pointerToData As IntPtr
    
                messageSize = Marshal.SizeOf(message)
    
                pointerToData = Marshal.AllocHGlobal(messageSize)
    
                Marshal.StructureToPtr(message, pointerToData, True)
    
                Marshal.Copy(pointerToData, byteArray, CopyStartIndex, messageSize)
    
                Marshal.FreeHGlobal(pointerToData)
    
                Return True
            Catch ex As Exception
                Throw ex
            End Try
        End Function


    Regards, Peri


    Tuesday, September 30, 2014 2:08 PM
  • You are returning a byte array by ref so won't my code work if it is put at the end of the function?

    jdweng

    Tuesday, September 30, 2014 2:29 PM
  • If it is a single field like double or string or integer the it will work as you said. But I am working with a structure.

    Regards, Peri

    That doesn't really matter... you know how many bytes it takes to represent each field of the structure; this is determined by the data type for most of your fields, and by the specified size constant for the string.  You also know that each field's data is present in the declared order because you specified Sequential layout.

    So, use either proposed method of reversing a byte array and convert each sub-chunk of the overall byte array according to each field size.  Given this example layout:

    'Total size is 71 bytes
    <StructLayout(LayoutKind.Sequential, Pack:=1)> Friend Structure ACMRequestMessage
        '4 byte header
        Friend MessageHeader As HeaderMessageStructure.MessageHeader
        '4 byte integer
        Friend BusinessDate As Integer
        '10 byte string
        <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=CustomConstants.VariableLengths.NoOfDigitsForTradeNumber)> _
        Friend ACMReferenceID As String
        '10 byte string
        <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=CustomConstants.VariableLengths.NoOfDigitsForBaseCurrency)> _
        Friend BaseCurrency As String
        '10 byte string
        <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=CustomConstants.VariableLengths.NoOfDigitsForCounterCurrency)> _
        Friend CounterCurrency As String
        '10 byte string
        <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=CustomConstants.VariableLengths.NoOfDigitsForMemberID)> _
        Friend MemberID As String
        '1 byte char
        Friend USDSellorBuy As Char
        '10 byte string
        <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=CustomConstants.VariableLengths.NoOfDigitsForSettlementType)> _
        Friend SettlementType As String
        '4 byte integer
        Friend SettlementDate As Integer
        '8 byte double
        Friend TradeAmount As Double
    End Structure
    
    Public Class HeaderMessageStructure
        Public Structure MessageHeader
            Public ID As Integer
        End Structure
    End Class
    
    Public Class CustomConstants
        Public Class VariableLengths
            Public Const NoOfDigitsForTradeNumber As Integer = 10
            Public Const NoOfDigitsForBaseCurrency As Integer = 10
            Public Const NoOfDigitsForCounterCurrency As Integer = 10
            Public Const NoOfDigitsForMemberID As Integer = 10
            Public Const NoOfDigitsForSettlementType As Integer = 10
        End Class
    End Class

    You should be able to use a routine something like this:

    Dim messageSize As Integer
    Dim pointerToData As IntPtr
    
    messageSize = Marshal.SizeOf(Message)
    Dim byteArray(messageSize - 1) As Byte
    
    pointerToData = Marshal.AllocHGlobal(messageSize)
    Marshal.StructureToPtr(Message, pointerToData, True)
    Marshal.Copy(pointerToData, byteArray, 0, messageSize)
    Marshal.FreeHGlobal(pointerToData)
    
    Dim intSize As Integer = Marshal.SizeOf(New Integer)
    Dim charSize As Integer = Marshal.SizeOf(New Char)
    Dim doubleSize As Integer = Marshal.SizeOf(New Double)
    Dim index As Integer = 0
    For Each length As Integer In {intSize, intSize, CustomConstants.VariableLengths.NoOfDigitsForTradeNumber,
                                   CustomConstants.VariableLengths.NoOfDigitsForBaseCurrency,
                                   CustomConstants.VariableLengths.NoOfDigitsForCounterCurrency,
                                   CustomConstants.VariableLengths.NoOfDigitsForMemberID, charSize,
                                   CustomConstants.VariableLengths.NoOfDigitsForSettlementType, intSize, doubleSize}
        Array.Reverse(byteArray, index, length)
        index = length
    Next
    


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    • Proposed as answer by dbasnett Wednesday, October 1, 2014 10:53 AM
    • Marked as answer by Carl CaiModerator Tuesday, October 7, 2014 6:02 AM
    Tuesday, September 30, 2014 5:11 PM
    Moderator
  • <quote> we need to convert into Big Endian before sending it and also convert the Big Endian to little Endian after we receive the data. </quote>

    Why do you need to convert it to big endian whilst in transit? Is anything in transit going to need to read this data? or understand it?

    Please forgive me if this shows my complete ignorance of this subject.


    Leon Stanley - ♪Don't pay the ferryman - till he gets you over to the other side♪ . um . I apply this to corporations - not to God.


    • Edited by LeonCS Wednesday, October 1, 2014 9:24 AM
    Wednesday, October 1, 2014 9:15 AM