duanlei8119 2016-12-12 15:22
浏览 30
已采纳

如何反序列化非标准尺寸的字段?

I have to deserialize some binary messages coming from another application. I would love to use restruct.io but some fields in the message structure use a "non-standard" number of bits ( 5 bits, 3 bits, ... 10 bits ... ).

Is there any way to handle this type of structs? I have been searching for some time without any success so any help will be very welcomed.

thanks in advance

I wil try to give an example to clarify my question. Given the code:

package main

import (
    "encoding/binary"
    "fmt"

    restruct "gopkg.in/restruct.v1"
)

type MessageType uint8

const (
    MessageTypeOne MessageType = iota + 1
    MessageTypeTwo
    MessageTypeThree
)

// Message is the data to deserialize from the binary stream
type Message struct {
    Length     uint32      `struct:"uint32"` // message size in bytes (including length)
    Type       MessageType `struct:"uint8"`
    Version    uint8       `struct:"uint8:4"` // Just need 4 bits
    Subversion uint8       `struct:"uint8:2"` // just need 2 bits
    Optional   uint8       `struct:"uint8:1"` // just one bit --> '1' means next field is NOT present
    NodeName   string      ``
    ANumber    uint16      `struct:"uint16:10"` // just need 10 bits
}

// (length(4)+type(1)+(version(4bits)+Subversion(2bits)+Optional(1bit))) = 6 bytes
// need 32bit alignment
func main() {
    var inStream = []byte{0x08, // just 8 bytes needed
        0x01,       // messge type = MessageTypeOne
        0x4a,       // Version=0100 Subversion=10 Optional=1 ANumber = 0 (MSB bit)
        0x00, 0x60, // ANumber(000 0000 011) Padding = 0 0000 for 32 bits alignment
    }
    var msg Message

    err := restruct.Unpack(inStream, binary.BigEndian, &msg)
    if err != nil {
        panic(err)
    }
    fmt.Println(msg)
    // Expected:
    // msg.Length = 8
    // msg.Type = 1
    // msg.Version = 4
    // msg.Subversion = 2
    // msg.Optional = 1
    // msg.NodeName = ""
    // msg.ANumber = 3
}

I will receive inStream from a TCP connection and will want to deserialize the binary data and get a Message struct with the expected values ...

Hope this will clarify my question.

Thanks again ;)

  • 写回答

2条回答 默认 最新

  • dsgrgaz321973284 2017-01-18 13:54
    关注

    I have been working on some patch for restruct.io to be able to work with bitfields .... Still not fully tested but seems to work ...

    Will try to send a pull request once tested ...

    func (e *encoder) writeBits(f field, inBuf []byte) {
    
        var inputLength uint8 = uint8(len(inBuf))
    
        if f.BitSize == 0 {
            // Having problems with complex64 type ... so we asume we want to read all
            //f.BitSize = uint8(f.Type.Bits())
            f.BitSize = 8 * inputLength
        }
    
        // destPos: Destination position ( in the result ) of the first bit in the first byte
        var destPos uint8 = 8 - e.bitCounter
    
        // originPos: Original position of the first bit in the first byte
        var originPos uint8 = f.BitSize % 8
        if originPos == 0 {
            originPos = 8
        }
    
        // numBytes: number of complete bytes to hold the result
        var numBytes uint8 = f.BitSize / 8
    
        // numBits: number of remaining bits in the first non-complete byte of the result
        var numBits uint8 = f.BitSize % 8
    
        // number of positions we have to shift the bytes to get the result
        var shift uint8
        if originPos > destPos {
            shift = originPos - destPos
        } else {
            shift = destPos - originPos
        }
        shift = shift % 8
    
        var inputInitialIdx uint8 = inputLength - numBytes
        if numBits > 0 {
            inputInitialIdx = inputInitialIdx - 1
        }
    
        if originPos < destPos {
            // shift left
            carry := func(idx uint8) uint8 {
                if (idx + 1) < inputLength {
                    return (inBuf[idx+1] >> (8 - shift))
                }
                return 0x00
    
            }
            mask := func(idx uint8) uint8 {
                if idx == 0 {
                    return (0x01 << destPos) - 1
                }
                return 0xFF
            }
            var idx uint8 = 0
            for inIdx := inputInitialIdx; inIdx < inputLength; inIdx++ {
                e.buf[idx] |= ((inBuf[inIdx] << shift) | carry(inIdx)) & mask(idx)
                idx++
            }
    
        } else {
            // originPos >= destPos => shift right
            var idx uint8 = 0
            // carry : is a little bit tricky in this case because of the first case
            // when idx == 0 and there is no carry at all
            carry := func(idx uint8) uint8 {
                if idx == 0 {
                    return 0x00
                }
                return (inBuf[idx-1] << (8 - shift))
            }
            mask := func(idx uint8) uint8 {
                if idx == 0 {
                    return (0x01 << destPos) - 1
                }
                return 0xFF
            }
            inIdx := inputInitialIdx
            for ; inIdx < inputLength; inIdx++ {
                //note: Should the mask be done BEFORE the OR with carry?
                e.buf[idx] |= ((inBuf[inIdx] >> shift) | carry(inIdx)) & mask(idx)
    
                idx++
            }
            if ((e.bitCounter + f.BitSize) % 8) > 0 {
                e.buf[idx] |= carry(inIdx)
            }
        }
    
        //now we should update buffer and bitCounter
        e.bitCounter = (e.bitCounter + f.BitSize) % 8
    
        // move the head to the next non-complete byte used
        headerUpdate := func() uint8 {
            if (e.bitCounter == 0) && ((f.BitSize % 8) != 0) {
                return (numBytes + 1)
            }
            return numBytes
        }
    
        e.buf = e.buf[headerUpdate():]
    
        return
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 孟德尔随机化结果不一致
  • ¥15 深度学习残差模块模型
  • ¥50 怎么判断同步时序逻辑电路和异步时序逻辑电路
  • ¥15 差动电流二次谐波的含量Matlab计算
  • ¥15 Can/caned 总线错误问题,错误显示控制器要发1,结果总线检测到0
  • ¥15 C#如何调用串口数据
  • ¥15 MATLAB与单片机串口通信
  • ¥15 L76k模块的GPS的使用
  • ¥15 请帮我看一看数电项目如何设计
  • ¥23 (标签-bug|关键词-密码错误加密)