2016-02-19 4 views
5

私はいくつかのバイナリファイルの解析をスムーズにしようとしていますが、私は動作するものの、可変フィールドがある状況があります。即時に任意のビット数を読み取るためのアプローチ

は、私はすべて私がデータのほとんどはので、私は先に行ってきたoptionalsの唯一の特定のセットを使用しています

1-bit field 
1-bit field 
1-bit field 
11-bits field 
1-bit field 
(optional) 4-bit field 
(optional) 4-bit field 
1-bit field 
2-bit field 
(optional) 4-bit field 
5-bit field 
6-bit field 
(optional) 6-bit field 
(optional) 24-bit field 
(junk data - up until byte buffer 0 - 7 bits as needed) 

つかむ

デフォルトのケースで働く私の解析および処理するためのクラスを書き始めましたそのデータ。私の一般的なアプローチは、ポインタ構造を作成し、そこからバイト配列を構築することである。

let rawData: NSMutableData = NSMutableData(data: input_nsdata) 
var ptr: UnsafeMutablePointer<UInt8> = UnsafeMutablePointer<UInt8(rawData.mutableBytes) 
bytes = UnsafeMutableBufferPointer<UInt8>(start: ptr, count: rawData.length - offset) 

だから私は[UInt8]の配列で作業を終わると、私はと同様に、私の構文解析を行うことができます。

let b1 = (bytes[3] & 0x01) << 5 
let b2 = (bytes[4] & 0xF8) >> 3 
    return Int(b1 | b2) 

私が問題に遭遇するところでは、オプションのフィールドがあります。なぜなら、私のデータはバイト境界上にあるわけではなく、すべてが複雑になるからです。理想的な世界では、私はおそらくポインタで直接作業し、必要に応じてバイト単位で進めますが、3ビットでポインタを前進させる方法はありません - 私の質問に私をもたらします

私の状況を処理する最善の方法は何ですか?

私は、ビット配列のパック構造を素早く作成する方法がわからないことを除いて、オプションのフィールドを反映するさまざまな構造を思いついたと考えました。

私の最善のアプローチは何ですか?明確化のために、最初の1-bitフィールドは、オプションフィールドのいずれが設定されるかを決定します。

+1

、私は単に[CFBitVector](https://developer.appleを使用します。 com/library/mac/documentation/CoreFoundation/Reference/CFBitVectorRef /)を参照してください。 –

+0

@SamR .: CFBitVectorは大規模なビットセットを管理するのに便利ですが、何かを見落とさない限り、おそらくバイト境界を越えて複数のビットに格納されている数値を取得するのに役立ちません。 1つのフィールドのすべてのビットを別々に取得し、これらから数を構築することは、あまり効果的ではないでしょう。 –

答えて

2

フィールドがバイト境界にない場合、 は現在のバイトと現在のビット位置の両方を1バイト以内に記録する必要があります。

データ配列の任意の数 を読み取って、すべての簿記を実行することができる解決策があります。 の唯一の制限は、nextBits()の結果がUInt (プラットフォームによって32ビットまたは64ビット)に収まる必要があることです。

struct BitReader { 

    private let data : [UInt8] 
    private var byteOffset : Int 
    private var bitOffset : Int 

    init(data : [UInt8]) { 
     self.data = data 
     self.byteOffset = 0 
     self.bitOffset = 0 
    } 

    func remainingBits() -> Int { 
     return 8 * (data.count - byteOffset) - bitOffset 
    } 

    mutating func nextBits(numBits : Int) -> UInt { 
     precondition(numBits <= remainingBits(), "attempt to read more bits than available") 

     var bits = numBits  // remaining bits to read 
     var result : UInt = 0 // result accumulator 

     // Read remaining bits from current byte: 
     if bitOffset > 0 { 
      if bitOffset + bits < 8 { 
       result = (UInt(data[byteOffset]) & UInt(0xFF >> bitOffset)) >> UInt(8 - bitOffset - bits) 
       bitOffset += bits 
       return result 
      } else { 
       result = UInt(data[byteOffset]) & UInt(0xFF >> bitOffset) 
       bits = bits - (8 - bitOffset) 
       bitOffset = 0 
       byteOffset = byteOffset + 1 
      } 
     } 

     // Read entire bytes: 
     while bits >= 8 { 
      result = (result << UInt(8)) + UInt(data[byteOffset]) 
      byteOffset = byteOffset + 1 
      bits = bits - 8 
     } 

     // Read remaining bits: 
     if bits > 0 { 
      result = (result << UInt(bits)) + (UInt(data[byteOffset]) >> UInt(8 - bits)) 
      bitOffset = bits 
     } 

     return result 
    } 
} 

使用例:

let data : [UInt8] = ... your data ... 
var bitReader = BitReader(data: data) 

let b1 = bitReader.nextBits(1) 
let b2 = bitReader.nextBits(1) 
let b3 = bitReader.nextBits(1) 
let b4 = bitReader.nextBits(11) 
let b5 = bitReader.nextBits(1) 
if b1 > 0 { 
    let b6 = bitReader.nextBits(4) 
    let b7 = bitReader.nextBits(4) 
} 
// ... and so on ... 

そしてここでは、ビット 簡単かつ恐らくより有効である別の可能implemention、です。それはUIntにバイトを集め、 は結果を1ステップで抽出します。 ここでは、numBits + 7は、UInt(32または64)のビット数以下である必要があります。 以下である必要があります。あなたは、特に独自の実装を設計するために探していた場合を除き(もちろんUInt それはプラットフォームに依存しないようするためにUInt64によって置き換えることができます。)

struct BitReader { 
    private let data : [UInt8] 
    private var byteOffset = 0 
    private var currentValue : UInt = 0 // Bits which still have to be consumed 
    private var currentBits = 0   // Number of valid bits in `currentValue` 

    init(data : [UInt8]) { 
     self.data = data 
    } 

    func remainingBits() -> Int { 
     return 8 * (data.count - byteOffset) + currentBits 
    } 

    mutating func nextBits(numBits : Int) -> UInt { 
     precondition(numBits <= remainingBits(), "attempt to read more bits than available") 

     // Collect bytes until we have enough bits: 
     while currentBits < numBits { 
      currentValue = (currentValue << 8) + UInt(data[byteOffset]) 
      currentBits = currentBits + 8 
      byteOffset = byteOffset + 1 
     } 

     // Extract result: 
     let remaining = currentBits - numBits 
     let result = currentValue >> UInt(remaining) 

     // Update remaining bits: 
     currentValue = currentValue & UInt(1 << remaining - 1) 
     currentBits = remaining 
     return result 
    } 

} 
関連する問題