2013-01-08 51 views
3

我有一個字節流,它是一個串聯的節,其中每個節由一個頭和一個放縮的字節流組成。如何超越字節流中包含的放氣字節序列?

我需要分割這個字節流部分,但頭只包含有關未壓縮形式的數據的信息,沒有關於壓縮數據長度的提示,所以我可以在流中正確前進並解析下一部分。

到目前爲止,我發現超越癟縮字節序列的唯一方法是根據this specification解析它。根據我所瞭解的規範,deflate流由塊組成,可以是壓縮塊或文字塊。

文字塊包含一個大小標題,可用於輕鬆超越它。

壓縮塊由'前綴代碼'組成,它是可變長度的位序列,對縮放算法有特殊的含義。由於我只想找出縮小的流長度,所以我想我需要查找的唯一代碼是'0000000',根據規範指示塊結束。

所以我想出了這個CoffeeScript的函數來解析放氣流(我工作的node.js)

# The job of this function is to return the position 
# after the deflate stream contained in 'buffer'. The 
# deflated stream begins at 'pos'. 
advanceDeflateStream = (buffer, pos) -> 
    byteOffset = 0 
    finalBlock = false 
    while 1 
    if byteOffset == 6 
     firstTypeBit = 0b00000001 & buffer[pos] 
     pos++ 
     secondTypeBit = 0b10000000 & buffer[pos] 
     type = firstTypeBit | (secondTypeBit << 1) 
    else 
     if byteOffset == 7 
     pos++ 
     type = buffer[pos] & (0b01100000 >>> byteOffset) 
    if type == 0 
     # Literal block 
     # ignore the remaining bits and advance position 
     byteOffset = 0 
     pos++ 
     len = buffer.readUInt16LE(pos) 
     pos += 2 
     lenComplement = buffer.readUInt16LE(pos) 
     if (len^~lenComplement) 
     throw new Error('Literal block lengh check fail') 
     pos += (2 + len) # Advance past literal block 
    else if type in [1, 2] 
     # huffman block 
     # we are only interested in finding the 'block end' marker 
     # which is signaled by the bit string 0000000 (256) 
     eob = false 
     matchedZeros = 0 
     while !eob 
     byte = buffer[pos] 
     for i in [byteOffset..7] 
      # loop the remaining bits looking for 7 consecutive zeros 
      if (byte^(0b10000000 >>> byteOffset)) >>> (7 - byteOffset) 
      matchedZeros++ 
      else 
      # reset counter 
      matchedZeros = 0 
      if matchedZeros == 7 
      eob = true 
      break 
      byteOffset++ 
     if !eob 
      byteOffset = 0 
      pos++ 
    else 
     throw new Error('Invalid deflate block') 
    finalBlock = buffer[pos] & (0b10000000 >>> byteOffset) 
    if finalBlock 
     break 
    return pos 

要檢查,如果這個工程,我寫了一個簡單的摩卡測試用例:

zlib = require 'zlib' 

test 'sample deflate stream', (done) -> 
    data = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' # length 30 
    zlib.deflate data, (err, deflated) -> 
    # deflated.length == 11 
    advanceDeflateStream(deflated, 0).shoudl.eql(11) 
    done() 

問題是,此測試失敗,我不知道如何調試它。我接受任何答案,指出我在解析算法中遺漏了什麼,或者是否包含任何語言的上述函數的正確版本。

回答

2

找到放氣流或放氣塊結束的唯一方法是解碼包含在其中的所有霍夫曼碼。沒有可以搜索的位模式,它不能在流的前面出現。

+0

我認爲前綴代碼背後的想法是,沒有代碼可能是另一個代碼的前綴,如果是的話,塊結束標記怎麼會出現在塊結束?代碼解析算法是否在前方? –

+0

是的,沒有代碼是另一個代碼的前綴。但是,這並不妨礙代碼出現在兩個其他代碼的位的結合中。前綴屬性僅適用於您知道每個代碼開始的位。爲了知道代碼在哪一位開始,你需要先解碼所有的代碼。 –

+0

明白了,謝謝。 –