簡體   English   中英

編解碼器 - 讀取固定長度的字符串

[英]Scodec - Reading in a fixed-length String

我正在編寫一個文件解析器,它正在讀取包含固定長度、0 填充字符串的現有文件格式。

因此,例如,我需要解析的文件中有兩個用於二進制結構的 case 類。 第一個包含一個 4 個字符的字符串,可以是兩個值之一,后者包含一個 8 個字符的字符串(其中長度小於 8 個字符的值用 NUL 填充)

case class WadHeader( magic : String, items : Int, dirOffset : Int)
case class LumpIndex( offset : Int, size : Int, lumpName : String)

我試圖編寫一個簡單的編解碼器來解析第一個:

  implicit val headerCodec : Codec[WadHeader] = {
    ("magic" | bytes(4)) ::
      ("items" | uint32) ::
      ("dirOffset" | uint32)
  }.as[WadHeader]

但是,我發現它無法成功將其轉換為 WadHeader(大概是因為魔術值與案例類定義不完全匹配。我希望能夠攝取固定大小的字符串字節並將其解碼為 String 對象。

不幸的是,搜索文檔只會出現“貪婪”字符串或大小前綴字符串選項。

好的 - 所以我想出了一個可以正常工作的解決方案。 可能有一種更簡單/更清潔的方法來做到這一點,但這很有效。

首先,當我提前知道長度時,我定義了一個新的 fixedString 編解碼器用於讀取字符串:

  def fixedString(size: Int): Codec[String] = new Codec[String] {
    private val codec = fixedSizeBytes(size, ascii)
    def sizeBound: SizeBound = SizeBound.exact(size * 8L)
    def encode(b: String): Attempt[BitVector] = codec.encode(b)
    def decode(b: BitVector): Attempt[DecodeResult[String]] = {
      codec.decode(b) match {
        case Successful(DecodeResult(value, remainder)) =>
          val decoded = value.toSeq.takeWhile(_>0).mkString

          Attempt.successful(DecodeResult(decoded, remainder))
        case fail : scodec.Attempt.Failure => fail
      }
    }
    override def toString = s"fixedString($size)"
  }

這適用於字符串。 第二個只是我的一個愚蠢的錯誤(uint32 解碼為 Long,而不是 Int),這需要我相應地更新我的案例類定義:

case class WadHeader( magic : String, items : Long, dirOffset : Long)

object WadHeader {
  implicit val codec : Codec[WadHeader] = {
    ("magic" | fixedString(4)) ::
      ("items" | uint32) ::
      ("dirOffset" | uint32)
  }.as[WadHeader]
}

編輯:5/7 - 發現我可以包裝fixedSizeCodec(size, ascii)而不是bytes ,它完成了我想要的大部分工作,並相應地更新了解決方案。 根據要求, fixedSizeCodec(size, cstring)也可能是一個非常好的解決方案 - 但是對於我的用例,對於使用完整字段長度的字符串失敗,因為沒有空間用於終止 nul。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM