Public Class DataTable

    ''' <summary>
    ''' Copie de mémoire
    ''' </summary>
    ''' <param name="Destination">Mot</param>
    ''' <param name="Source">Tableau d'octet</param>
    ''' <param name="Length">Longueur de copie</param>
    ''' <remarks></remarks>
    Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByRef Destination As Single, ByRef Source As Byte, ByVal Length As Long)
    ''' <summary>
    ''' Copie de mémoire
    ''' </summary>
    ''' <param name="Destination">Tableau d'octet</param>
    ''' <param name="Source">Mot</param>
    ''' <param name="Length">Longueur de copie</param>
    ''' <remarks></remarks>
    Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByRef Destination As Byte, ByRef Source As Single, ByVal Length As Long)

    'Public Shared Function Merge(ByVal pBuffer1 As DataTable, ByVal pBuffer2 As DataTable) As DataTable

    'End Function

    ''' <summary>
    ''' Offset de la table
    ''' </summary>
    ''' <remarks></remarks>
    Private mOffset As UShort
    ''' <summary>
    ''' Données
    ''' </summary>
    ''' <remarks></remarks>
    Private mtDatas As UShort()

    ''' <summary>
    ''' Constructeur de la classe
    ''' </summary>
    ''' <param name="pOffset">Offset de la table</param>
    ''' <param name="pLength">Longueur de la table</param>
    ''' <remarks></remarks>
    Public Sub New(ByVal pOffset As UShort, ByVal pLength As UShort)
        If (CInt(pOffset) + pLength) > UShort.MaxValue Then
            Throw New ArgumentException("pOffset+pLength>65535")
        End If
        If pLength = 0 Then
            Throw New ArgumentException("pLength=0")
        End If
        mOffset = pOffset
        ReDim mtDatas(pLength - 1)
    End Sub

    ''' <summary>
    ''' Retourne l'offset de la table
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property Offset() As UShort
        Get
            Return mOffset
        End Get
    End Property
    ''' <summary>
    ''' Retourne la longueur de la table
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property Length() As UShort
        Get
            Return CUShort(mtDatas.Length)
        End Get
    End Property

    ''' <summary>
    ''' Retourne un tableau de mot
    ''' </summary>
    ''' <param name="pOffset">Offset de départ (relatif)</param>
    ''' <param name="pLength">Nombre de mots à lire</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function GetArrayShort(ByVal pOffset As UShort, ByVal pLength As UShort) As UShort()
        Dim ltData As UShort()
        ReDim ltData(pLength - 1)

        For i As UShort = pOffset To CUShort(pOffset + pLength - 1)
            ltData(i - pOffset) = mtDatas(i - mOffset)
        Next

        Return ltData
    End Function

#Region "Gestion des données"

#Region "Propriétés"

#Region "Motorola"
    ''' <summary>
    ''' Retourne ou définit un entier non signé sur 32 bits (format Motorola)
    ''' </summary>
    ''' <param name="pOffset">Décalage du mot par rapport à l'offset de base</param>
    ''' <value></value>


    Public Property [UInt32](ByVal pOffset As Integer) As UInteger
        Get
            If mtDatas.Length < pOffset + 2 Then
                Return 0
            Else
                Return (CUInt(mtDatas(pOffset)) << 16) + CUInt(mtDatas(pOffset + 1))
            End If
        End Get
        Set(ByVal value As UInteger)
            If mtDatas.Length < pOffset + 2 Then
#If DEBUG Then
                Stop
#End If
                Return
            End If
            mtDatas(pOffset) = CUShort(value >> 16)
            mtDatas(pOffset + 1) = CUShort(value And &HFFFF)
        End Set
    End Property
    ''' <summary>
    ''' Retourne ou définit une entier signé sur 32 bits (format Motorola)
    ''' </summary>
    ''' <param name="pOffset">Décalage du mot par rapport à l'offset de base</param>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property [Int32](ByVal pOffset As Integer) As Integer
        Get
            Dim lUInt As UInteger = UInt32(pOffset)
            If lUInt > Integer.MaxValue Then
                Return CInt(CLng(lUInt) - UInteger.MaxValue - 1)
            Else
                Return CInt(lUInt)
            End If
        End Get
        Set(ByVal value As Integer)
            If value < 0 Then
                UInt32(pOffset) = CUInt(CLng(value) + UInteger.MaxValue + 1)
            Else
                UInt32(pOffset) = CUInt(value)
            End If
        End Set
    End Property
    ''' <summary>
    ''' Retourne ou définit un entier non signé sur 16 bits (format Motorola)
    ''' </summary>
    ''' <param name="pOffset">Décalage du mot par rapport à l'offset de base</param>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property [UInt16](ByVal pOffset As Integer) As UShort
        Get
            If mtDatas.Length <= pOffset Then
                Return 0
            Else
                Return mtDatas(pOffset)
            End If
        End Get
        Set(ByVal value As UShort)
            If mtDatas.Length <= pOffset Then
#If DEBUG Then
                Stop
#End If
                Return
            End If
            mtDatas(pOffset) = value
        End Set
    End Property
    ''' <summary>
    ''' Retourne ou définit un entier signé sur 16 bits (format Motorola)
    ''' </summary>
    ''' <param name="pOffset">Décalage du mot par rapport à l'offset de base</param>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property [Int16](ByVal pOffset As Integer) As Short
        Get
            Dim lInt As Integer = CInt(UInt16(pOffset))
            If lInt > Short.MaxValue Then
                Return CShort(lInt - UShort.MaxValue - 1)
            Else
                Return CShort(lInt)
            End If
        End Get
        Set(ByVal value As Short)
            If value < 0 Then
                UInt16(pOffset) = CUShort(CInt(value) + UShort.MaxValue + 1)
            Else
                UInt16(pOffset) = CUShort(value)
            End If
        End Set
    End Property
    ''' <summary>
    ''' Retourne ou définit un octet non signé
    ''' </summary>
    ''' <param name="pOffset">Décalage du mot par rapport à l'offset de base</param>
    ''' <param name="pLSB">Indique s'il s'agit de l'octet de poids faible du mot</param>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property UInt8(ByVal pOffset As Integer, ByVal pLSB As Boolean) As Byte
        Get
            Dim lUShort As UShort = UInt16(pOffset)
            If pLSB Then
                Return CByte(lUShort And &HFF)
            Else
                Return CByte((lUShort And &HFF00) >> 8)
            End If
        End Get
        Set(ByVal value As Byte)
            Dim lUShort As UShort = UInt16(pOffset)
            If pLSB Then
                lUShort = CUShort((lUShort And &HFF00) Or value)
            Else
                lUShort = CUShort((lUShort And &HFF) Or (CUShort(value) << 8))
            End If
            UInt16(pOffset) = lUShort
        End Set
    End Property
    ''' <summary>
    ''' Retour ou définit un octet signé
    ''' </summary>
    ''' <param name="pOffset">Décalage du mot par rapport à l'offset de base</param>
    ''' <param name="pLSB">Indique s'il s'agit de l'octet de poids faible du mot</param>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property Int8(ByVal pOffset As Integer, ByVal pLSB As Boolean) As SByte
        Get
            Dim lInt As Integer = CInt(UInt8(pOffset, pLSB))
            If lInt > SByte.MaxValue Then
                Return CSByte(lInt - Byte.MaxValue - 1)
            Else
                Return CSByte(lInt)
            End If
        End Get
        Set(ByVal value As SByte)
            If value < 0 Then
                Dim lInt As Integer = value
                UInt8(pOffset, pLSB) = CByte(lInt + Byte.MaxValue + 1)
            Else
                UInt8(pOffset, pLSB) = CByte(value)
            End If
        End Set
    End Property
    ''' <summary>
    ''' Retourne ou définit une chaine de caractère (premier à gauche)
    ''' </summary>
    ''' <param name="pOffset">Décalage du mot par rapport à l'offset de base</param>
    ''' <param name="pLength">Longueur à lire/écrire (optionnel en écriture)</param>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property [String](ByVal pOffset As Integer, ByVal pLength As Integer) As String
        Get
            Dim lUShort As UShort
            Dim lStr As String = ""

            Do While pLength > 0
                lUShort = UInt16(pOffset)
                pOffset += 1

                pLength -= 1
                lStr += Chr(lUShort >> 8)

                If pLength > 0 Then
                    pLength -= 1
                    lStr += Chr(lUShort And &HFF)
                End If
            Loop

            Return lStr
        End Get
        Set(ByVal value As String)
            If pLength <= 0 Then
                pLength = value.Length
            ElseIf pLength > value.Length Then
                Do While pLength > value.Length
                    value += " "
                Loop
            End If

            value = value.Substring(0, pLength)

            Do While value.Length > 1
                UInt16(pOffset) = CUShort(((Asc(value.Substring(0, 1))) << 8) Or (Asc(value.Substring(1, 1))))
                value = value.Substring(2)
                pOffset += 1
            Loop

            If value.Length > 0 Then
                UInt8(pOffset, False) = CByte(value)
            End If
        End Set
    End Property
    ''' <summary>
    ''' Définit une chaine de caractère (premier à gauche)
    ''' </summary>
    ''' <param name="pOffset">Décalage du mot par rapport à l'offset de base</param>
    ''' <value></value>
    ''' <remarks></remarks>
    Public WriteOnly Property [String](ByVal pOffset As Integer) As String
        Set(ByVal value As String)
            Me.String(pOffset, value.Length) = value
        End Set
    End Property
    ''' <summary>
    ''' Retourne ou définit un bit d'un mot (format Motorola)
    ''' </summary>
    ''' <param name="pOffset">Décalage du mot par rapport à l'offset de base</param>
    ''' <param name="pNumBit">Numéro du bit (0 LSB, valeur entre 0 et 15 bornes comprises)</param>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property [Boolean](ByVal pOffset As Integer, ByVal pNumBit As Integer) As Boolean
        Get
            If pNumBit < 0 Or pNumBit > 15 Then
                Throw New ArgumentException("pNumBit doit être compris entre 0 et 15 (borne incluses)", "pNumBit")
            End If

            Dim lUShort As UShort = UInt16(pOffset)
            Return (lUShort And (1 << pNumBit)) <> 0
        End Get
        Set(ByVal value As Boolean)
            If pNumBit < 0 Or pNumBit > 15 Then
                Throw New ArgumentException("pNumBit doit être compris entre 0 et 7 (borne incluses)", "pNumBit")
            End If

            Dim lUShort As UShort = UInt16(pOffset)
            If value Then
                lUShort = CUShort(lUShort Or (1 << pNumBit))
            Else
                lUShort = CUShort(lUShort And Not (1 << pNumBit))
            End If
            UInt16(pOffset) = lUShort
        End Set
    End Property
#End Region

#Region "Intel"
    ''' <summary>
    ''' Retourne ou définit un entier non signé sur 32 bits (format Intel)
    ''' </summary>
    ''' <param name="pOffset">Décalage du mot par rapport à l'offset de base</param>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property IntelUInt32(ByVal pOffset As Integer) As UInteger
        Get
            If mtDatas.Length < pOffset + 2 Then
                Return 0
            Else
                Return CUInt(mtDatas(pOffset)) + (CUInt(mtDatas(pOffset + 1)) << 16)
            End If
        End Get
        Set(ByVal value As UInteger)
            If mtDatas.Length < pOffset + 2 Then
#If DEBUG Then
                Stop
#End If
                Return
            End If
            mtDatas(pOffset + 1) = CUShort(value >> 16)
            mtDatas(pOffset) = CUShort(value And &HFFFF)
        End Set
    End Property
    ''' <summary>
    ''' Retourne ou définit une entier signé sur 32 bits (format Intel)
    ''' </summary>
    ''' <param name="pOffset">Décalage du mot par rapport à l'offset de base</param>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property IntelInt32(ByVal pOffset As Integer) As Integer
        Get
            Dim lUInt As UInteger = IntelUInt32(pOffset)
            If lUInt > Integer.MaxValue Then
                Return CInt(CLng(lUInt) - UInteger.MaxValue - 1)
            Else
                Return CInt(lUInt)
            End If
        End Get
        Set(ByVal value As Integer)
            If value < 0 Then
                IntelUInt32(pOffset) = CUInt(CLng(value) + UInteger.MaxValue + 1)
            Else
                IntelUInt32(pOffset) = CUInt(value)
            End If
        End Set
    End Property
    ''' <summary>
    ''' Retourne ou définit une entier flottant simple précision
    ''' </summary>
    ''' <param name="pOffset">Décalage du mot par rapport à l'offset de base</param>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property Float(ByVal pOffset As Integer) As Single
        Get
            Dim lSng As Single = 0
            Dim ltByte As Byte() = New Byte() {UInt8(pOffset + 1, True), UInt8(pOffset + 1, False), UInt8(pOffset, True), UInt8(pOffset, False)}
            CopyMemory(lSng, ltByte(0), 4)
            Return lSng
        End Get
        Set(ByVal value As Single)
            Dim ltByte(3) As Byte
            CopyMemory(ltByte(0), value, 4)
            UInt8(pOffset, False) = ltByte(3)
            UInt8(pOffset, True) = ltByte(2)
            UInt8(pOffset + 1, False) = ltByte(1)
            UInt8(pOffset + 1, True) = ltByte(0)
        End Set
    End Property
#End Region

#End Region

#Region "Procédures"
    ''' <summary>
    ''' Met à zéro les mots
    ''' </summary>
    ''' <param name="pStart">Offset relatif de départ</param>
    ''' <param name="pLength">Longueur des données à définir</param>
    ''' <remarks></remarks>
    Public Sub SetZeros(ByVal pStart As Integer, ByVal pLength As Integer)
        SetValues(pStart, pLength, 0)
    End Sub
    ''' <summary>
    ''' Met à zéro depuis pStart à la fin des données actuellement présente
    ''' </summary>
    ''' <param name="pStart">Offset relatif de départ</param>
    ''' <remarks></remarks>
    Public Sub SetZeros(ByVal pStart As Integer)
        SetValues(pStart, 0)
    End Sub
    ''' <summary>
    ''' Met à pValue les mots
    ''' </summary>
    ''' <param name="pStart">Offset relatif de départ</param>
    ''' <param name="pLength">Longueur des données à définir</param>
    ''' <param name="pValue">Valeur à utiliser</param>
    ''' <remarks></remarks>
    Public Sub SetValues(ByVal pStart As Integer, ByVal pLength As Integer, ByVal pValue As UShort)
        For i As Integer = pStart To pStart + pLength - 1
            If i > (mtDatas.Length - 1) Then Exit Sub
            mtDatas(i) = pValue
        Next
    End Sub
    ''' <summary>
    ''' Met à pValue depuis pStart à la fin des données actuellement présente
    ''' </summary>
    ''' <param name="pStart">Offset relatif de départ</param>
    ''' <param name="pValue">Valeur à utiliser</param>
    ''' <remarks></remarks>
    Public Sub SetValues(ByVal pStart As Integer, ByVal pValue As UShort)
        SetValues(pStart, mtDatas.Length - pStart, pValue)
    End Sub
#End Region

#End Region

End Class
