package lzo const ( cSWD_N = m4_MAX_OFFSET // ring buffer size cSWD_THRESHOLD = 1 // lower limit for match length cSWD_F = 2048 // upper limit for match length cSWD_BEST_OFF = m3_MAX_LEN + 1 // max(m2,m3,m4)+1 cSWD_HSIZE = 16384 cSWD_MAX_CHAIN = 2048 ) type swd struct { // Public builtin SwdN uint SwdF uint SwdThreshold uint // Public configuration MaxChain uint NiceLength uint UseBestOff bool LazyInsert uint // Output MLen uint MOff uint Look uint BChar int BestOff [cSWD_BEST_OFF]uint // Semi-public ctx *compressor mpos uint bestPos [cSWD_BEST_OFF]uint // Private ip uint // input pointer (lookahead) bp uint // buffer pointer rp uint // remove pointer bsize uint bwrap []byte nodecount uint firstrp uint b [cSWD_N + cSWD_F + cSWD_F]byte head3 [cSWD_HSIZE]uint16 succ3 [cSWD_N + cSWD_F]uint16 best3 [cSWD_N + cSWD_F]uint16 llen3 [cSWD_HSIZE]uint16 head2 [65536]uint16 } func head2(data []byte) uint { return uint(data[1])<<8 | uint(data[0]) } func head3(data []byte) uint { key := uint(data[0]) key = (key << 5) ^ uint(data[1]) key = (key << 5) ^ uint(data[2]) key = (key * 0x9f5f) >> 5 return key & (cSWD_HSIZE - 1) } func (s *swd) gethead3(key uint) uint16 { if s.llen3[key] == 0 { return 0xFFFF } return s.head3[key] } func (s *swd) removeNode(node uint) { if s.nodecount == 0 { key := head3(s.b[node:]) if s.llen3[key] == 0 { panic("assert: swd.removeNode: invalid llen3") } s.llen3[key]-- key = head2(s.b[node:]) if s.head2[key] == 0xFFFF { panic("assert: swd.removeNode: invalid head2") } if uint(s.head2[key]) == node { s.head2[key] = 0xFFFF } return } s.nodecount-- } func (s *swd) init() { s.SwdN = cSWD_N s.SwdF = cSWD_F s.SwdThreshold = cSWD_THRESHOLD s.MaxChain = cSWD_MAX_CHAIN s.NiceLength = s.SwdF s.bsize = s.SwdN + s.SwdF s.bwrap = s.b[s.bsize:] s.nodecount = s.SwdN for i := 0; i < len(s.head2); i++ { s.head2[i] = 0xFFFF } s.ip = 0 s.bp = s.ip s.firstrp = s.ip if s.ip+s.SwdF > s.bsize { panic("assert: swd.init: invalid ip") } s.Look = uint(len(s.ctx.in)) - s.ip if s.Look > 0 { if s.Look > s.SwdF { s.Look = s.SwdF } copy(s.b[s.ip:], s.ctx.in[:s.Look]) s.ctx.ip += int(s.Look) s.ip += s.Look } if s.ip == s.bsize { s.ip = 0 } s.rp = s.firstrp if s.rp >= s.nodecount { s.rp -= s.nodecount } else { s.rp += s.bsize - s.nodecount } if s.Look < 3 { s.b[s.bp+s.Look] = 0 s.b[s.bp+s.Look+1] = 0 s.b[s.bp+s.Look+2] = 0 } } func (s *swd) getbyte() { c := -1 if s.ctx.ip < len(s.ctx.in) { c = int(s.ctx.in[s.ctx.ip]) s.ctx.ip++ s.b[s.ip] = byte(c) if s.ip < s.SwdF { s.bwrap[s.ip] = byte(c) } } else { if s.Look > 0 { s.Look-- } s.b[s.ip] = 0 if s.ip < s.SwdF { s.bwrap[s.ip] = 0 } } s.ip++ if s.ip == s.bsize { s.ip = 0 } s.bp++ if s.bp == s.bsize { s.bp = 0 } s.rp++ if s.rp == s.bsize { s.rp = 0 } } func (s *swd) accept(n uint) { if n > s.Look { panic("swd: accept: invalid n") } for i := uint(0); i < n; i++ { s.removeNode(s.rp) key := head3(s.b[s.bp:]) s.succ3[s.bp] = s.gethead3(key) s.head3[key] = uint16(s.bp) s.best3[s.bp] = uint16(s.SwdF + 1) s.llen3[key]++ if uint(s.llen3[key]) > s.SwdN { panic("swd: accept: invalid llen3") } key = head2(s.b[s.bp:]) s.head2[key] = uint16(s.bp) s.getbyte() } } func (s *swd) search(node uint, cnt uint) { if s.MLen <= 0 { panic("assert: search: invalid mlen") } mlen := s.MLen bp := s.bp bx := s.bp + s.Look scanend1 := s.b[s.bp+mlen-1] for ; cnt > 0; cnt-- { p1 := bp p2 := node px := bx if mlen >= s.Look { panic("assert: search: invalid mlen in loop") } if s.b[p2+mlen-1] == scanend1 && s.b[p2+mlen] == s.b[p1+mlen] && s.b[p2] == s.b[p1] && s.b[p2+1] == s.b[p1+1] { if s.b[bp] != s.b[node] || s.b[bp+1] != s.b[node+1] || s.b[bp+2] != s.b[node+2] { panic("assert: seach: invalid initial match") } p1 = p1 + 2 p2 = p2 + 2 for p1 < px { p1++ p2++ if s.b[p1] != s.b[p2] { break } } i := p1 - bp for j := uint(0); j < i; j++ { if s.b[s.bp+j] != s.b[node+j] { panic("assert: search: invalid final match") } } if i < cSWD_BEST_OFF { if s.bestPos[i] == 0 { s.bestPos[i] = node + 1 } } if i > mlen { mlen = i s.MLen = mlen s.mpos = node if mlen == s.Look { return } if mlen >= s.NiceLength { return } if mlen > uint(s.best3[node]) { return } scanend1 = s.b[s.bp+mlen-1] } } node = uint(s.succ3[node]) } } func (s *swd) search2() bool { if s.Look < 2 { panic("assert: search2: invalid look") } if s.MLen <= 0 { panic("assert: search2: invalid mlen") } key := s.head2[head2(s.b[s.bp:])] if key == 0xFFFF { return false } if s.b[s.bp] != s.b[key] || s.b[s.bp+1] != s.b[key+1] { panic("assert: search2: invalid key found") } if s.bestPos[2] == 0 { s.bestPos[2] = uint(key + 1) } if s.MLen < 2 { s.MLen = 2 s.mpos = uint(key) } return true } func (s *swd) findbest() { if s.MLen == 0 { panic("swd: findbest: invalid mlen") } key := head3(s.b[s.bp:]) node := s.gethead3(key) s.succ3[s.bp] = node cnt := uint(s.llen3[key]) s.llen3[key]++ if cnt > s.SwdN+s.SwdF { panic("swd: findbest: invalid llen3") } if cnt > s.MaxChain && s.MaxChain > 0 { cnt = s.MaxChain } s.head3[key] = uint16(s.bp) s.BChar = int(s.b[s.bp]) len := s.MLen if s.MLen >= s.Look { if s.Look == 0 { s.BChar = -1 } s.MOff = 0 s.best3[s.bp] = uint16(s.SwdF + 1) } else { if s.search2() && s.Look >= 3 { s.search(uint(node), cnt) } if s.MLen > len { s.MOff = s.pos2off(s.mpos) } if s.UseBestOff { for i := 2; i < cSWD_BEST_OFF; i++ { if s.bestPos[i] > 0 { s.BestOff[i] = s.pos2off(s.bestPos[i] - 1) } else { s.BestOff[i] = 0 } } } } s.removeNode(s.rp) key = head2(s.b[s.bp:]) s.head2[key] = uint16(s.bp) } func (s *swd) pos2off(pos uint) uint { if s.bp > pos { return s.bp - pos } return s.bsize - (pos - s.bp) }