首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >scodec解码/编码分割长度字段

scodec解码/编码分割长度字段
EN

Stack Overflow用户
提问于 2014-11-13 23:18:20
回答 1查看 630关注 0票数 2

我使用scodec:https://github.com/scodec/scodec来解码/编码二进制协议。

我正在与规范的一部分进行斗争,其中一个“长度”字段被一个“萤火虫”分割成两个部分。莫尔菲表示长度字段是否需要更多的空间。

代码语言:javascript
复制
Example:
Byte 1:  identifier bits 8-7, moreFlag bit 6, length bits 5-0    // first length field filled with 0's if moreFlag is false
Byte 2:  moreFlag bit 8, length bits 7-0  
Byte 3:  otherJunk bits 8-0

我的问题是,我想将这两个长度字段编码/解码成一个case类字段:

代码语言:javascript
复制
case class Header(totalLength: Int, otherJunk: Int)

我尝试过几种不同的方法,但到目前为止还没有结果:

代码语言:javascript
复制
implicit val headerCodec: Codec[Header] = (
  ("identifier" | uint2) :~>:
  ("moreFlag" | bool).compact >>:~ { meta => 
    if (meta.last) {
      // more flag enabled, combine lengths somehow
      ("first length part" | uint(5)) :: ("moreFlag2DontCare" | uint(1) :~>: ("second length part - how to combine?" | uint(7)) :: ("otherJunk" | uint8) 
    }
    else {
      ("first length part always 0s" | constant(bin"00000")) :: ("moreFlag2DontCare" | uint(1) :~>: ("fullLength" | uint(7)) :: ("otherJunk" | uint8)
    }
  }
).as[Header]

我在这里走得对吗?谢谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-11-14 00:54:01

实现这一点的一种方法是使用预定义的组合器来定义二进制格式的结构--而不是组合逻辑。然后将组合逻辑放入传递给xmap的函数中。

代码语言:javascript
复制
import scodec._
import bits._
import codecs._
import shapeless._

case class Header(totalLength: Int, otherJunk: Int)

object Header {
  implicit val codec: Codec[Header] = {
    type Struct = Int :: Boolean :: BitVector :: Boolean :: BitVector :: Int :: HNil
    val struct: Codec[Struct] = ("identifier" | uint2) :: ("moreFlag" | bool) :: ("upper length bits" | codecs.bits(5)) :: ("moreFlag2" | bool) :: ("lower length bits" | codecs.bits(7)) :: ("other junk" | uint8)
    def to(header: Header): Struct = {
      val lengthBits = uint(12).encodeValid(header.totalLength)
      val more = !(lengthBits startsWith bin"00000")
      0 :: more :: lengthBits.take(5) :: false :: lengthBits.drop(5) :: header.otherJunk :: HNil
    }
    def from(struct: Struct): Header = struct match {
      case id :: moreFlag :: upperLengthBits :: moreFlag2 :: lowerLengthBits :: otherJunk :: HNil =>
        val length =
          if (moreFlag) uint(12).decodeValidValue(upperLengthBits ++ lowerLengthBits)
          else uint(7).decodeValidValue(lowerLengthBits)
        Header(length, otherJunk)
    }
    struct.xmap[Header](from, to)
  }
}

请注意,上下长度位被编码为bits(5)bits(7),然后在from函数中手动组合并解码。尽管使用了不安全的decodeValidValue,但是解码是安全的,因为uint(12)编解码器是在12位输入上的--它不可能返回一个左。

但是,to函数使用encodeValid,这显然是不安全的--例如,Int.MaxValue将导致异常。我们可以用稍微复杂一些的版本来修复这个问题,其中to函数返回一个Err \/ Struct,我们调用widen而不是xmap

代码语言:javascript
复制
object Header {
  implicit val codec: Codec[Header] = {
    type Struct = Int :: Boolean :: BitVector :: Boolean :: BitVector :: Int :: HNil
    val struct: Codec[Struct] = ("identifier" | uint2) :: ("moreFlag" | bool) :: ("upper length bits" | codecs.bits(5)) :: ("moreFlag2" | bool) :: ("lower length bits" | codecs.bits(7)) :: ("other junk" | uint8)
    def to(header: Header): Err \/ Struct = {
      uint(12).encode(header.totalLength) map { lengthBits =>
        val more = !(lengthBits startsWith bin"00000")
        0 :: more :: lengthBits.take(5) :: false :: lengthBits.drop(5) :: header.otherJunk :: HNil
      }
    }
    def from(struct: Struct): Header = struct match {
      case id :: moreFlag :: upperLengthBits :: moreFlag2 :: lowerLengthBits :: otherJunk :: HNil =>
        val length =
          if (moreFlag) uint(12).decodeValidValue(upperLengthBits ++ lowerLengthBits)
          else uint(7).decodeValidValue(lowerLengthBits)
        Header(length, otherJunk)
    }
    struct.widen[Header](from, to)
  }
}
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26920286

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档