セクションの連結であるバイトストリームがあります。各セクションは、ヘッダーと収縮したバイトストリームで構成されています。
このバイトストリームセクションを分割する必要がありますが、ヘッダーには非圧縮形式のデータに関する情報のみが含まれ、圧縮データの長さに関するヒントは含まれていないため、ストリームを適切に進めて次のセクションを解析できます。
これまでのところ、デフレートされたバイトシーケンスを超えて進むことがわかった唯一の方法は、この仕様に従って解析することです。仕様を読んで理解したところによると、デフレートストリームはブロックで構成されており、圧縮ブロックまたはリテラルブロックにすることができます。
リテラルブロックには、それを簡単に通過するために使用できるサイズヘッダーが含まれています。
圧縮されたブロックは、「プレフィックスコード」で構成されます。これは、deflateアルゴリズムにとって特別な意味を持つ可変長のビットシーケンスです。収縮したストリームの長さを調べることだけに興味があるので、探す必要があるコードは「0000000」だけだと思います。これは、仕様によれば、ブロックの終わりを示します。
そこで、deflateストリームを解析するためにこの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
これが機能するかどうかを確認するために、簡単なmochaテストケースを作成しました。
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()
問題は、このテストが失敗し、デバッグ方法がわからないことです。私は、構文解析アルゴリズムで見逃したことを指摘する、または上記の関数の正しいバージョンを任意の言語で含む回答を受け入れます。