switch to packaged lzma package

This commit is contained in:
aviau
2018-06-22 11:58:10 -04:00
parent 9000446663
commit 7dfc12d138
19 changed files with 4 additions and 4 deletions
+27
View File
@@ -0,0 +1,27 @@
// Copyright (c) 2010, Andrei Vieru. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of the author nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Binary file not shown.
+3982
View File
File diff suppressed because it is too large Load Diff
+355
View File
@@ -0,0 +1,355 @@
// Copyright (c) 2010, Andrei Vieru. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package lzma
import "io"
const (
kHash2Size = 1 << 10
kHash3Size = 1 << 16
kBT2HashSize = 1 << 16
kStartMaxLen = 1
kHash3Offset = kHash2Size
kEmptyHashValue = 0
kMaxValForNormalize = (1 << 30) - 1
)
type lzBinTree struct {
iw *lzInWindow
son []uint32
hash []uint32
cyclicBufPos uint32
cyclicBufSize uint32
matchMaxLen uint32
cutValue uint32
hashMask uint32
hashSizeSum uint32
kvNumHashDirectBytes uint32
kvMinMatchCheck uint32
kvFixHashSize uint32
hashArray bool
}
func newLzBinTree(r io.Reader, historySize, keepAddBufBefore, matchMaxLen, keepAddBufAfter, numHashBytes uint32) *lzBinTree {
bt := &lzBinTree{
son: make([]uint32, (historySize+1)*2), // history size is the dictSize from the encoder
cyclicBufPos: 0,
cyclicBufSize: historySize + 1,
matchMaxLen: matchMaxLen,
cutValue: 16 + (matchMaxLen >> 1),
}
winSizeReserv := (historySize+keepAddBufBefore+matchMaxLen+keepAddBufAfter)/2 + 256
bt.iw = newLzInWindow(r, historySize+keepAddBufBefore, matchMaxLen+keepAddBufAfter, winSizeReserv)
if numHashBytes > 2 {
bt.hashArray = true
bt.kvNumHashDirectBytes = 0
bt.kvMinMatchCheck = 4
bt.kvFixHashSize = kHash2Size + kHash3Size
} else {
bt.hashArray = false
bt.kvNumHashDirectBytes = 2
bt.kvMinMatchCheck = 3
bt.kvFixHashSize = 0
}
hs := uint32(kBT2HashSize)
if bt.hashArray == true {
hs = historySize - 1
hs |= hs >> 1
hs |= hs >> 2
hs |= hs >> 4
hs |= hs >> 8
hs >>= 1
hs |= 0xFFFF
if hs > 1<<24 {
hs >>= 1
}
bt.hashMask = hs
hs++
hs += bt.kvFixHashSize
}
bt.hashSizeSum = hs
bt.hash = make([]uint32, bt.hashSizeSum)
for i := uint32(0); i < bt.hashSizeSum; i++ {
bt.hash[i] = kEmptyHashValue
}
bt.iw.reduceOffsets(0xFFFFFFFF)
return bt
}
func normalizeLinks(items []uint32, numItems, subValue uint32) {
for i := uint32(0); i < numItems; i++ {
value := items[i]
if value <= subValue {
value = kEmptyHashValue
} else {
value -= subValue
}
items[i] = value
}
}
func (bt *lzBinTree) normalize() {
subValue := bt.iw.pos - bt.cyclicBufSize
normalizeLinks(bt.son, bt.cyclicBufSize*2, subValue)
normalizeLinks(bt.hash, bt.hashSizeSum, subValue)
bt.iw.reduceOffsets(subValue)
}
func (bt *lzBinTree) movePos() {
bt.cyclicBufPos++
if bt.cyclicBufPos >= bt.cyclicBufSize {
bt.cyclicBufPos = 0
}
bt.iw.movePos()
if bt.iw.pos == kMaxValForNormalize {
bt.normalize()
}
}
func (bt *lzBinTree) getMatches(distances []uint32) uint32 {
var lenLimit uint32
if bt.iw.pos+bt.matchMaxLen <= bt.iw.streamPos {
lenLimit = bt.matchMaxLen
} else {
lenLimit = bt.iw.streamPos - bt.iw.pos
if lenLimit < bt.kvMinMatchCheck {
bt.movePos()
return 0
}
}
offset := uint32(0)
matchMinPos := uint32(0)
if bt.iw.pos > bt.cyclicBufSize {
matchMinPos = bt.iw.pos - bt.cyclicBufSize
}
cur := bt.iw.bufOffset + bt.iw.pos
maxLen := uint32(kStartMaxLen)
var hashValue uint32
hash2Value := uint32(0)
hash3Value := uint32(0)
if bt.hashArray == true {
tmp := crcTable[bt.iw.buf[cur]] ^ uint32(bt.iw.buf[cur+1])
hash2Value = tmp & (kHash2Size - 1)
tmp ^= uint32(bt.iw.buf[cur+2]) << 8
hash3Value = tmp & (kHash3Size - 1)
hashValue = (tmp ^ crcTable[bt.iw.buf[cur+3]]<<5) & bt.hashMask
} else {
hashValue = uint32(bt.iw.buf[cur]) ^ uint32(bt.iw.buf[cur+1])<<8
}
curMatch := bt.hash[bt.kvFixHashSize+hashValue]
if bt.hashArray == true {
curMatch2 := bt.hash[hash2Value]
curMatch3 := bt.hash[kHash3Offset+hash3Value]
bt.hash[hash2Value] = bt.iw.pos
bt.hash[kHash3Offset+hash3Value] = bt.iw.pos
if curMatch2 > matchMinPos {
if bt.iw.buf[bt.iw.bufOffset+curMatch2] == bt.iw.buf[cur] {
maxLen = 2
distances[offset] = maxLen
offset++
distances[offset] = bt.iw.pos - curMatch2 - 1
offset++
}
}
if curMatch3 > matchMinPos {
if bt.iw.buf[bt.iw.bufOffset+curMatch3] == bt.iw.buf[cur] {
if curMatch3 == curMatch2 {
offset -= 2
}
maxLen = 3
distances[offset] = maxLen
offset++
distances[offset] = bt.iw.pos - curMatch3 - 1
offset++
curMatch2 = curMatch3
}
}
if offset != 0 && curMatch2 == curMatch {
offset -= 2
maxLen = kStartMaxLen
}
}
bt.hash[bt.kvFixHashSize+hashValue] = bt.iw.pos
if bt.kvNumHashDirectBytes != 0 {
if curMatch > matchMinPos {
if bt.iw.buf[bt.iw.bufOffset+curMatch+bt.kvNumHashDirectBytes] != bt.iw.buf[cur+bt.kvNumHashDirectBytes] {
maxLen = bt.kvNumHashDirectBytes
distances[offset] = maxLen
offset++
distances[offset] = bt.iw.pos - curMatch - 1
offset++
}
}
}
ptr0 := bt.cyclicBufPos<<1 + 1
ptr1 := bt.cyclicBufPos << 1
len0 := bt.kvNumHashDirectBytes
len1 := bt.kvNumHashDirectBytes
count := bt.cutValue
for {
if curMatch <= matchMinPos || count == 0 {
bt.son[ptr1] = kEmptyHashValue
bt.son[ptr0] = kEmptyHashValue
break
}
count--
delta := bt.iw.pos - curMatch
var cyclicPos uint32
if delta <= bt.cyclicBufPos {
cyclicPos = (bt.cyclicBufPos - delta) << 1
} else {
cyclicPos = (bt.cyclicBufPos - delta + bt.cyclicBufSize) << 1
}
pby1 := bt.iw.bufOffset + curMatch
length := minUInt32(len0, len1)
if bt.iw.buf[pby1+length] == bt.iw.buf[cur+length] {
for length++; length != lenLimit; length++ {
if bt.iw.buf[pby1+length] != bt.iw.buf[cur+length] {
break
}
}
if maxLen < length {
maxLen = length
distances[offset] = maxLen
offset++
distances[offset] = delta - 1
offset++
if length == lenLimit {
bt.son[ptr1] = bt.son[cyclicPos]
bt.son[ptr0] = bt.son[cyclicPos+1]
break
}
}
}
if bt.iw.buf[pby1+length] < bt.iw.buf[cur+length] {
bt.son[ptr1] = curMatch
ptr1 = cyclicPos + 1
curMatch = bt.son[ptr1]
len1 = length
} else {
bt.son[ptr0] = curMatch
ptr0 = cyclicPos
curMatch = bt.son[ptr0]
len0 = length
}
}
bt.movePos()
return offset
}
func (bt *lzBinTree) skip(num uint32) {
for i := uint32(0); i < num; i++ {
var lenLimit uint32
if bt.iw.pos+bt.matchMaxLen <= bt.iw.streamPos {
lenLimit = bt.matchMaxLen
} else {
lenLimit = bt.iw.streamPos - bt.iw.pos
if lenLimit < bt.kvMinMatchCheck {
bt.movePos()
continue
}
}
matchMinPos := uint32(0)
if bt.iw.pos > bt.cyclicBufSize {
matchMinPos = bt.iw.pos - bt.cyclicBufSize
}
cur := bt.iw.bufOffset + bt.iw.pos
var hashValue uint32
if bt.hashArray == true {
tmp := crcTable[bt.iw.buf[cur]] ^ uint32(bt.iw.buf[cur+1])
hash2Value := tmp & (kHash2Size - 1)
bt.hash[hash2Value] = bt.iw.pos
tmp ^= uint32(bt.iw.buf[cur+2]) << 8
hash3Value := tmp & (kHash3Size - 1)
bt.hash[kHash3Offset+hash3Value] = bt.iw.pos
hashValue = (tmp ^ crcTable[bt.iw.buf[cur+3]]<<5) & bt.hashMask
} else {
hashValue = uint32(bt.iw.buf[cur]) ^ uint32(bt.iw.buf[cur+1])<<8
}
curMatch := bt.hash[bt.kvFixHashSize+hashValue]
bt.hash[bt.kvFixHashSize+hashValue] = bt.iw.pos
ptr0 := bt.cyclicBufPos<<1 + 1
ptr1 := bt.cyclicBufPos << 1
len0 := bt.kvNumHashDirectBytes
len1 := bt.kvNumHashDirectBytes
count := bt.cutValue
for {
if curMatch <= matchMinPos || count == 0 {
bt.son[ptr1] = kEmptyHashValue
bt.son[ptr0] = kEmptyHashValue
break
}
count--
delta := bt.iw.pos - curMatch
var cyclicPos uint32
if delta <= bt.cyclicBufPos {
cyclicPos = (bt.cyclicBufPos - delta) << 1
} else {
cyclicPos = (bt.cyclicBufPos - delta + bt.cyclicBufSize) << 1
}
pby1 := bt.iw.bufOffset + curMatch
length := minUInt32(len0, len1)
if bt.iw.buf[pby1+length] == bt.iw.buf[cur+length] {
for length++; length != lenLimit; length++ {
if bt.iw.buf[pby1+length] != bt.iw.buf[cur+length] {
break
}
}
if length == lenLimit {
bt.son[ptr1] = bt.son[cyclicPos]
bt.son[ptr0] = bt.son[cyclicPos+1]
break
}
}
if bt.iw.buf[pby1+length] < bt.iw.buf[cur+length] {
bt.son[ptr1] = curMatch
ptr1 = cyclicPos + 1
curMatch = bt.son[ptr1]
len1 = length
} else {
bt.son[ptr0] = curMatch
ptr0 = cyclicPos
curMatch = bt.son[ptr0]
len0 = length
}
}
bt.movePos()
}
}
var crcTable []uint32 = make([]uint32, 256)
// should be called in the encoder's contructor
func initCrcTable() {
for i := uint32(0); i < 256; i++ {
r := i
for j := 0; j < 8; j++ {
if r&1 != 0 {
r = r>>1 ^ 0xEDB88320
} else {
r >>= 1
}
}
crcTable[i] = r
}
}
+193
View File
@@ -0,0 +1,193 @@
// Copyright (c) 2010, Andrei Vieru. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package lzma
import "io"
type lzOutWindow struct {
w io.Writer
buf []byte
winSize uint32
pos uint32
streamPos uint32
//unpacked uint32 // counter of unpacked bytes
}
func newLzOutWindow(w io.Writer, windowSize uint32) *lzOutWindow {
return &lzOutWindow{
w: w,
buf: make([]byte, windowSize),
winSize: windowSize,
pos: 0,
streamPos: 0,
//unpacked: 0,
}
}
func (ow *lzOutWindow) flush() {
size := ow.pos - ow.streamPos
if size == 0 {
return
}
n, err := ow.w.Write(ow.buf[ow.streamPos : ow.streamPos+size])
if err != nil {
throw(err)
}
if uint32(n) != size {
throw(nWriteError)
}
//unpacked += size
if ow.pos >= ow.winSize {
ow.pos = 0
}
ow.streamPos = ow.pos
}
func (ow *lzOutWindow) copyBlock(distance, length uint32) {
pos := ow.pos - distance - 1
if pos >= ow.winSize {
pos += ow.winSize
}
for ; length != 0; length-- {
if pos >= ow.winSize {
pos = 0
}
ow.buf[ow.pos] = ow.buf[pos]
ow.pos++
pos++
if ow.pos >= ow.winSize {
ow.flush()
}
}
}
func (ow *lzOutWindow) putByte(b byte) {
ow.buf[ow.pos] = b
ow.pos++
if ow.pos >= ow.winSize {
ow.flush()
}
}
func (ow *lzOutWindow) getByte(distance uint32) byte {
pos := ow.pos - distance - 1
if pos >= ow.winSize {
pos += ow.winSize
}
return ow.buf[pos]
}
type lzInWindow struct {
r io.Reader
buf []byte
posLimit uint32
lastSafePos uint32
bufOffset uint32
blockSize uint32
pos uint32
keepSizeBefore uint32
keepSizeAfter uint32
streamPos uint32
streamEnd bool
}
func newLzInWindow(r io.Reader, keepSizeBefore, keepSizeAfter, keepSizeReserv uint32) *lzInWindow {
blockSize := keepSizeBefore + keepSizeAfter + keepSizeReserv
iw := &lzInWindow{
r: r,
buf: make([]byte, blockSize),
lastSafePos: blockSize - keepSizeAfter,
bufOffset: 0,
blockSize: blockSize,
pos: 0,
keepSizeBefore: keepSizeBefore,
keepSizeAfter: keepSizeAfter,
streamPos: 0,
streamEnd: false,
}
iw.readBlock()
return iw
}
func (iw *lzInWindow) moveBlock() {
offset := iw.bufOffset + iw.pos - iw.keepSizeBefore
if offset > 0 {
offset--
}
numBytes := iw.bufOffset + iw.streamPos - offset
for i := uint32(0); i < numBytes; i++ {
iw.buf[i] = iw.buf[offset+i]
}
iw.bufOffset -= offset
}
func (iw *lzInWindow) readBlock() {
if iw.streamEnd {
return
}
for {
if iw.blockSize-iw.bufOffset-iw.streamPos == 0 {
return
}
n, err := iw.r.Read(iw.buf[iw.bufOffset+iw.streamPos : iw.blockSize])
if err != nil && err != io.EOF {
throw(err)
}
if n == 0 && err == io.EOF {
iw.posLimit = iw.streamPos
ptr := iw.bufOffset + iw.posLimit
if ptr > iw.lastSafePos {
iw.posLimit = iw.lastSafePos - iw.bufOffset
}
iw.streamEnd = true
return
}
iw.streamPos += uint32(n)
if iw.streamPos >= iw.pos+iw.keepSizeAfter {
iw.posLimit = iw.streamPos - iw.keepSizeAfter
}
}
}
func (iw *lzInWindow) movePos() {
iw.pos++
if iw.pos > iw.posLimit {
ptr := iw.bufOffset + iw.pos
if ptr > iw.lastSafePos {
iw.moveBlock()
}
iw.readBlock()
}
}
func (iw *lzInWindow) getIndexByte(index int32) byte {
return iw.buf[int32(iw.bufOffset+iw.pos)+index]
}
func (iw *lzInWindow) getMatchLen(index int32, distance, limit uint32) (res uint32) {
uIndex := uint32(index)
if iw.streamEnd == true {
if iw.pos+uIndex+limit > iw.streamPos {
limit = iw.streamPos - (iw.pos + uIndex)
}
}
distance++
pby := iw.bufOffset + iw.pos + uIndex
for res = uint32(0); res < limit && iw.buf[pby+res] == iw.buf[pby+res-distance]; res++ {
// empty body
}
return
}
func (iw *lzInWindow) getNumAvailableBytes() uint32 {
return iw.streamPos - iw.pos
}
func (iw *lzInWindow) reduceOffsets(subValue uint32) {
iw.bufOffset += subValue
iw.posLimit -= subValue
iw.pos -= subValue
iw.streamPos -= subValue
}
+311
View File
@@ -0,0 +1,311 @@
// Copyright (c) 2010, Andrei Vieru. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package lzma
import (
"io/ioutil"
"log"
)
type lzmaTest struct {
descr string
level int
size bool
raw string
lzma []byte
err error
}
var lzmaTests = []lzmaTest{
// fmt -w 80 -s file
// cat file | sed s/\\\\/\\\\\\\\/g | sed s/\"/\\\\\"/g | sed s/^/\"/ | sed s/$/\\\\n\"\ +/
// hexdump -Cv file.lzma | awk '{for (i=2; i<18; i++) {printf("0x%s, ", $i); if (i==9) printf("\n");} printf("\n")}'
lzmaTest{
"empty test",
3,
true,
"",
[]byte{
0x5d, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
},
nil,
},
lzmaTest{
"empty (with size == -1) test",
3,
false,
"",
[]byte{
0x5d, 0x00, 0x00, 0x10, 0x00, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x83, 0xff,
0xfb, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00,
},
nil,
},
lzmaTest{
"hello world test",
3,
true,
"hello world\n",
[]byte{
0x5d, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x19,
0x49, 0xee, 0x8d, 0xe9, 0x17, 0x89, 0x3a, 0x33,
0x5f, 0xfc, 0xac, 0xf7, 0x20, 0x00,
},
nil,
},
lzmaTest{
"hello world (with size == -1) test",
3,
false,
"hello world\n",
[]byte{
0x5d, 0x00, 0x00, 0x10, 0x00, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x34, 0x19,
0x49, 0xee, 0x8d, 0xe9, 0x17, 0x89, 0x3a, 0x33,
0x5f, 0xfc, 0xb2, 0x09, 0x82, 0x2f, 0xff, 0xfd,
0xe2, 0x80, 0x00,
},
nil,
},
lzmaTest{
"text test",
3,
true,
"Two named types are identical if their type names originate in the same type\n" +
"declaration (§Declarations and scope). A named and an unnamed type are never\n" +
"identical. Two unnamed types are identical if the corresponding type literals\n" +
"have the same literal structure and corresponding components have identical\n" +
"types. In detail:\n" +
"\n" +
" * Two array types are identical if they have identical element types and\n" +
"the same array length.\n" +
" * Two slice types are identical if they have identical element types.\n" +
" * Two struct types are identical if they have the same sequence of fields,\n" +
"and if corresponding fields have the same names and identical types. Two\n" +
"anonymous fields are considered to have the same name.\n" +
" * Two pointer types are identical if they have identical base types.\n" +
" * Two function types are identical if they have the same number of\n" +
"parameters and result values and if corresponding parameter and result types\n" +
"are identical. All \"...\" parameters without a specified type are defined to\n" +
"have identical type. All \"...\" parameters with specified identical type T are\n" +
"defined to have identical type. Parameter and result names are not required to\n" +
"match.\n" +
" * Two interface types are identical if they have the same set of methods\n" +
"with the same names and identical function types. The order of the methods is\n" +
"irrelevant.\n" +
" * Two map types are identical if they have identical key and value types.\n" +
" * Two channel types are identical if they have identical value types and\n" +
"the same direction.\n",
[]byte{
0x5d, 0x00, 0x00, 0x10, 0x00, 0xe8, 0x05, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x1d,
0xc9, 0xe2, 0x03, 0x0c, 0x4e, 0x75, 0xc8, 0xee,
0x65, 0x97, 0xae, 0x0a, 0x7b, 0x0a, 0x66, 0xfa,
0x4a, 0x94, 0xe6, 0x32, 0x2f, 0x9b, 0x44, 0x8c,
0xaf, 0xf6, 0xf4, 0x67, 0xe2, 0x8a, 0x8b, 0x2f,
0x26, 0x41, 0xf6, 0x64, 0xe2, 0xf6, 0x00, 0xbb,
0x1f, 0x4a, 0xb1, 0xca, 0xa6, 0xf0, 0x54, 0x9e,
0xa5, 0x2d, 0xe7, 0x6e, 0x6a, 0x49, 0x84, 0xac,
0xf5, 0x52, 0xcf, 0x57, 0xcd, 0xa7, 0x84, 0xe9,
0x27, 0xdc, 0x3d, 0xf3, 0xf4, 0x1a, 0x8d, 0x98,
0xba, 0xcc, 0x47, 0xca, 0x1b, 0x38, 0xa6, 0x8c,
0x96, 0x24, 0x14, 0x8d, 0x1c, 0x81, 0x6b, 0xc0,
0x1c, 0x69, 0xa1, 0x79, 0xa2, 0x20, 0x10, 0x6c,
0x0c, 0x56, 0x40, 0x1f, 0x3f, 0x32, 0x4a, 0x4f,
0x1f, 0x2a, 0x29, 0xf0, 0x23, 0x99, 0xbe, 0xc7,
0x49, 0x7e, 0xc7, 0x60, 0xa3, 0x54, 0x9c, 0x06,
0x06, 0xb4, 0xc4, 0x4d, 0x07, 0xd5, 0xef, 0xa0,
0xcd, 0xac, 0x8f, 0x54, 0xf9, 0x15, 0x15, 0xa0,
0xb5, 0xf1, 0x7d, 0xde, 0xeb, 0xe0, 0x41, 0x9a,
0x3e, 0x5a, 0x66, 0xd2, 0xfc, 0x08, 0x00, 0xe8,
0xf2, 0xc9, 0x04, 0x94, 0x7e, 0x0b, 0x06, 0x56,
0x9d, 0xe7, 0x1f, 0x48, 0x21, 0x4d, 0x18, 0x21,
0xa3, 0x5f, 0x69, 0x7a, 0xed, 0x4d, 0x2d, 0xb4,
0x3e, 0x34, 0xcf, 0x9e, 0xae, 0x11, 0x2d, 0x15,
0xbc, 0x2c, 0xd7, 0xef, 0x1c, 0xd5, 0xd8, 0xd3,
0xc2, 0x4f, 0xcb, 0x2c, 0xb1, 0xa3, 0x85, 0x0a,
0xad, 0x44, 0x68, 0x42, 0xab, 0x40, 0x58, 0xa2,
0x9b, 0xdf, 0xbd, 0xa2, 0x10, 0xc7, 0x2e, 0x5a,
0x1d, 0x07, 0xe4, 0xb5, 0xa6, 0xa8, 0xb3, 0x12,
0x44, 0x64, 0x18, 0xaf, 0xa7, 0x72, 0x05, 0x29,
0x48, 0xc6, 0x78, 0xef, 0x7f, 0x54, 0xe9, 0xb3,
0xae, 0x10, 0x51, 0x11, 0x91, 0xf6, 0x96, 0x40,
0x6a, 0xf1, 0xc8, 0x3d, 0x46, 0x86, 0x2e, 0xd3,
0xa1, 0xdc, 0x38, 0x97, 0x11, 0x49, 0x4b, 0x03,
0x91, 0xa5, 0xed, 0x53, 0x3f, 0xd5, 0x87, 0x04,
0x25, 0xf0, 0xe2, 0x19, 0x55, 0x99, 0x6b, 0xad,
0xa2, 0x9c, 0x7a, 0xcd, 0xc9, 0x34, 0x18, 0x8f,
0x4c, 0xaa, 0xed, 0xd3, 0x49, 0x98, 0xd9, 0x67,
0xbe, 0x41, 0x85, 0xbf, 0x09, 0x22, 0x16, 0xa0,
0x81, 0x71, 0x38, 0xdb, 0xb2, 0xd6, 0xfe, 0x2b,
0xf4, 0x03, 0xf8, 0xd1, 0x00, 0x16, 0x5e, 0x77,
0x69, 0xd4, 0x28, 0x8f, 0x94, 0x4d, 0x58, 0x4f,
0xae, 0x6b, 0xb1, 0x09, 0x85, 0x71, 0xd7, 0x3a,
0x4b, 0xea, 0xd2, 0x70, 0xbb, 0xa2, 0x20, 0x85,
0x2d, 0xbd, 0x57, 0x3f, 0x81, 0x3e, 0xe4, 0xa2,
0x43, 0x3e, 0xee, 0x04, 0xbe, 0x42, 0x51, 0xaa,
0xad, 0xda, 0x53, 0x87, 0xeb, 0xc0, 0x9a, 0xde,
0xa2, 0x7e, 0x19, 0x4f, 0xa7, 0xdf, 0x23, 0x96,
0xdd, 0xe3, 0x18, 0x0f, 0xc0, 0x48, 0xfd, 0x9f,
0x13, 0xc3, 0x3c, 0x3a, 0x7b, 0x7c, 0xa8, 0x89,
0x6a, 0xd6, 0x68, 0xdd, 0x3b, 0xc6, 0xc6, 0x44,
0x79, 0xc5, 0x59, 0x1c, 0x23, 0xa9, 0x8b, 0x00,
0x62, 0xeb, 0x3a, 0x51, 0x14, 0x5e, 0x63, 0x79,
0x97, 0x60, 0x62, 0x13, 0x49, 0x41, 0x06, 0xf4,
0x5f, 0xe7, 0x9b, 0xd6, 0x51, 0x31, 0x6e, 0x7d,
0x5e, 0xe8, 0x72, 0xce, 0x5e, 0xd0, 0xa7, 0x9d,
0xa3, 0xa9, 0x92, 0xa8, 0x2f, 0x78, 0x00, 0x92,
0x4f, 0xf0, 0x21, 0xb6, 0x74, 0xfb, 0x3c, 0xe2,
0x60, 0xdf, 0x82, 0x09, 0x07, 0xb3, 0x68, 0x5b,
0xe2, 0x49, 0xeb, 0x81, 0x98, 0x23, 0x19, 0xdc,
0x2c, 0xa1, 0xad, 0x95, 0xc0, 0x9a, 0x48, 0xcd,
0xa8, 0xe4, 0xdf, 0xbb, 0xca, 0xd4, 0x47, 0x46,
0xe2, 0xdb, 0x5c, 0xe2, 0xdb, 0xb2, 0x32, 0x44,
0x87, 0x0a, 0x49, 0x99, 0xc6, 0x32, 0x75, 0xc6,
0xe7, 0x1b, 0xf1, 0x71, 0x74, 0x32, 0x4a, 0x17,
0x2f, 0xe8, 0x00,
},
nil,
},
lzmaTest{
"text test with size == -1",
3,
false,
"Two named types are identical if their type names originate in the same type\n" +
"declaration (§Declarations and scope). A named and an unnamed type are never\n" +
"identical. Two unnamed types are identical if the corresponding type literals\n" +
"have the same literal structure and corresponding components have identical\n" +
"types. In detail:\n" +
"\n" +
" * Two array types are identical if they have identical element types and\n" +
"the same array length.\n" +
" * Two slice types are identical if they have identical element types.\n" +
" * Two struct types are identical if they have the same sequence of fields,\n" +
"and if corresponding fields have the same names and identical types. Two\n" +
"anonymous fields are considered to have the same name.\n" +
" * Two pointer types are identical if they have identical base types.\n" +
" * Two function types are identical if they have the same number of\n" +
"parameters and result values and if corresponding parameter and result types\n" +
"are identical. All \"...\" parameters without a specified type are defined to\n" +
"have identical type. All \"...\" parameters with specified identical type T are\n" +
"defined to have identical type. Parameter and result names are not required to\n" +
"match.\n" +
" * Two interface types are identical if they have the same set of methods\n" +
"with the same names and identical function types. The order of the methods is\n" +
"irrelevant.\n" +
" * Two map types are identical if they have identical key and value types.\n" +
" * Two channel types are identical if they have identical value types and\n" +
"the same direction.\n",
[]byte{
0x5d, 0x00, 0x00, 0x10, 0x00, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x2a, 0x1d,
0xc9, 0xe2, 0x03, 0x0c, 0x4e, 0x75, 0xc8, 0xee,
0x65, 0x97, 0xae, 0x0a, 0x7b, 0x0a, 0x66, 0xfa,
0x4a, 0x94, 0xe6, 0x32, 0x2f, 0x9b, 0x44, 0x8c,
0xaf, 0xf6, 0xf4, 0x67, 0xe2, 0x8a, 0x8b, 0x2f,
0x26, 0x41, 0xf6, 0x64, 0xe2, 0xf6, 0x00, 0xbb,
0x1f, 0x4a, 0xb1, 0xca, 0xa6, 0xf0, 0x54, 0x9e,
0xa5, 0x2d, 0xe7, 0x6e, 0x6a, 0x49, 0x84, 0xac,
0xf5, 0x52, 0xcf, 0x57, 0xcd, 0xa7, 0x84, 0xe9,
0x27, 0xdc, 0x3d, 0xf3, 0xf4, 0x1a, 0x8d, 0x98,
0xba, 0xcc, 0x47, 0xca, 0x1b, 0x38, 0xa6, 0x8c,
0x96, 0x24, 0x14, 0x8d, 0x1c, 0x81, 0x6b, 0xc0,
0x1c, 0x69, 0xa1, 0x79, 0xa2, 0x20, 0x10, 0x6c,
0x0c, 0x56, 0x40, 0x1f, 0x3f, 0x32, 0x4a, 0x4f,
0x1f, 0x2a, 0x29, 0xf0, 0x23, 0x99, 0xbe, 0xc7,
0x49, 0x7e, 0xc7, 0x60, 0xa3, 0x54, 0x9c, 0x06,
0x06, 0xb4, 0xc4, 0x4d, 0x07, 0xd5, 0xef, 0xa0,
0xcd, 0xac, 0x8f, 0x54, 0xf9, 0x15, 0x15, 0xa0,
0xb5, 0xf1, 0x7d, 0xde, 0xeb, 0xe0, 0x41, 0x9a,
0x3e, 0x5a, 0x66, 0xd2, 0xfc, 0x08, 0x00, 0xe8,
0xf2, 0xc9, 0x04, 0x94, 0x7e, 0x0b, 0x06, 0x56,
0x9d, 0xe7, 0x1f, 0x48, 0x21, 0x4d, 0x18, 0x21,
0xa3, 0x5f, 0x69, 0x7a, 0xed, 0x4d, 0x2d, 0xb4,
0x3e, 0x34, 0xcf, 0x9e, 0xae, 0x11, 0x2d, 0x15,
0xbc, 0x2c, 0xd7, 0xef, 0x1c, 0xd5, 0xd8, 0xd3,
0xc2, 0x4f, 0xcb, 0x2c, 0xb1, 0xa3, 0x85, 0x0a,
0xad, 0x44, 0x68, 0x42, 0xab, 0x40, 0x58, 0xa2,
0x9b, 0xdf, 0xbd, 0xa2, 0x10, 0xc7, 0x2e, 0x5a,
0x1d, 0x07, 0xe4, 0xb5, 0xa6, 0xa8, 0xb3, 0x12,
0x44, 0x64, 0x18, 0xaf, 0xa7, 0x72, 0x05, 0x29,
0x48, 0xc6, 0x78, 0xef, 0x7f, 0x54, 0xe9, 0xb3,
0xae, 0x10, 0x51, 0x11, 0x91, 0xf6, 0x96, 0x40,
0x6a, 0xf1, 0xc8, 0x3d, 0x46, 0x86, 0x2e, 0xd3,
0xa1, 0xdc, 0x38, 0x97, 0x11, 0x49, 0x4b, 0x03,
0x91, 0xa5, 0xed, 0x53, 0x3f, 0xd5, 0x87, 0x04,
0x25, 0xf0, 0xe2, 0x19, 0x55, 0x99, 0x6b, 0xad,
0xa2, 0x9c, 0x7a, 0xcd, 0xc9, 0x34, 0x18, 0x8f,
0x4c, 0xaa, 0xed, 0xd3, 0x49, 0x98, 0xd9, 0x67,
0xbe, 0x41, 0x85, 0xbf, 0x09, 0x22, 0x16, 0xa0,
0x81, 0x71, 0x38, 0xdb, 0xb2, 0xd6, 0xfe, 0x2b,
0xf4, 0x03, 0xf8, 0xd1, 0x00, 0x16, 0x5e, 0x77,
0x69, 0xd4, 0x28, 0x8f, 0x94, 0x4d, 0x58, 0x4f,
0xae, 0x6b, 0xb1, 0x09, 0x85, 0x71, 0xd7, 0x3a,
0x4b, 0xea, 0xd2, 0x70, 0xbb, 0xa2, 0x20, 0x85,
0x2d, 0xbd, 0x57, 0x3f, 0x81, 0x3e, 0xe4, 0xa2,
0x43, 0x3e, 0xee, 0x04, 0xbe, 0x42, 0x51, 0xaa,
0xad, 0xda, 0x53, 0x87, 0xeb, 0xc0, 0x9a, 0xde,
0xa2, 0x7e, 0x19, 0x4f, 0xa7, 0xdf, 0x23, 0x96,
0xdd, 0xe3, 0x18, 0x0f, 0xc0, 0x48, 0xfd, 0x9f,
0x13, 0xc3, 0x3c, 0x3a, 0x7b, 0x7c, 0xa8, 0x89,
0x6a, 0xd6, 0x68, 0xdd, 0x3b, 0xc6, 0xc6, 0x44,
0x79, 0xc5, 0x59, 0x1c, 0x23, 0xa9, 0x8b, 0x00,
0x62, 0xeb, 0x3a, 0x51, 0x14, 0x5e, 0x63, 0x79,
0x97, 0x60, 0x62, 0x13, 0x49, 0x41, 0x06, 0xf4,
0x5f, 0xe7, 0x9b, 0xd6, 0x51, 0x31, 0x6e, 0x7d,
0x5e, 0xe8, 0x72, 0xce, 0x5e, 0xd0, 0xa7, 0x9d,
0xa3, 0xa9, 0x92, 0xa8, 0x2f, 0x78, 0x00, 0x92,
0x4f, 0xf0, 0x21, 0xb6, 0x74, 0xfb, 0x3c, 0xe2,
0x60, 0xdf, 0x82, 0x09, 0x07, 0xb3, 0x68, 0x5b,
0xe2, 0x49, 0xeb, 0x81, 0x98, 0x23, 0x19, 0xdc,
0x2c, 0xa1, 0xad, 0x95, 0xc0, 0x9a, 0x48, 0xcd,
0xa8, 0xe4, 0xdf, 0xbb, 0xca, 0xd4, 0x47, 0x46,
0xe2, 0xdb, 0x5c, 0xe2, 0xdb, 0xb2, 0x32, 0x44,
0x87, 0x0a, 0x49, 0x99, 0xc6, 0x32, 0x75, 0xc6,
0xe7, 0x1b, 0xf1, 0x71, 0x74, 0x32, 0x4a, 0x8d,
0xf2, 0x0a, 0x64, 0xff, 0xe4, 0x0d, 0xf4, 0xa2,
},
nil,
},
lzmaTest{
"hello world test with corrupt lc, lp, pb in header",
3,
true,
"hello world\n",
[]byte{
0xfe, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x19,
0x49, 0xee, 0x8d, 0xe9, 0x17, 0x89, 0x3a, 0x33,
0x5f, 0xfc, 0xac, 0xf7, 0x20, 0x00,
},
headerError,
},
}
type lzmaBenchmark struct {
descr string
level int
raw []byte
lzma []byte
}
func readFile(filename string) []byte {
file, err := ioutil.ReadFile(filename)
if err != nil {
log.Fatalf("%v", err)
}
return file
}
var bench = lzmaBenchmark{
descr: "text bench with size == -1",
level: 3,
raw: readFile("data/data.txt"),
lzma: readFile("data/data.eos.l3.lzma"),
}
+369
View File
@@ -0,0 +1,369 @@
// Copyright (c) 2010, Andrei Vieru. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// The lzma package implements reading and writing of LZMA format compressed data.
// Reference implementation is LZMA SDK version 4.65 originaly developed by Igor
// Pavlov, available online at:
//
// http://www.7-zip.org/sdk.html
//
//
//
// Usage examples. Write compressed data to a buffer:
//
// var b bytes.Buffer
// w := lzma.NewWriter(&b)
// w.Write([]byte("hello, world\n"))
// w.Close()
//
// read that data back:
//
// r := lzma.NewReader(&b)
// io.Copy(os.Stdout, r)
// r.Close()
//
//
//
// If the data is bigger than you'd like to hold into memory, use pipes. Write
// compressed data to an io.PipeWriter:
//
// pr, pw := io.Pipe()
// go func() {
// defer pw.Close()
// w := lzma.NewWriter(pw)
// defer w.Close()
// // the bytes.Buffer would be an io.Reader used to read uncompressed data from
// io.Copy(w, bytes.NewBuffer([]byte("hello, world\n")))
// }()
//
// and read it back:
//
// defer pr.Close()
// r := lzma.NewReader(pr)
// defer r.Close()
// // the os.Stdout would be an io.Writer used to write uncompressed data to
// io.Copy(os.Stdout, r)
//
//
//
package lzma
import (
"errors"
"io"
)
const (
inBufSize = 1 << 16
outBufSize = 1 << 16
lzmaPropSize = 5
lzmaHeaderSize = lzmaPropSize + 8
lzmaMaxReqInputSize = 20
kNumRepDistances = 4
kNumStates = 12
kNumPosSlotBits = 6
kDicLogSizeMin = 0
kNumLenToPosStatesBits = 2
kNumLenToPosStates = 1 << kNumLenToPosStatesBits
kMatchMinLen = 2
kNumAlignBits = 4
kAlignTableSize = 1 << kNumAlignBits
kAlignMask = kAlignTableSize - 1
kStartPosModelIndex = 4
kEndPosModelIndex = 14
kNumPosModels = kEndPosModelIndex - kStartPosModelIndex
kNumFullDistances = 1 << (kEndPosModelIndex / 2)
kNumLitPosStatesBitsEncodingMax = 4
kNumLitContextBitsMax = 8
kNumPosStatesBitsMax = 4
kNumPosStatesMax = 1 << kNumPosStatesBitsMax
kNumLowLenBits = 3
kNumMidLenBits = 3
kNumHighLenBits = 8
kNumLowLenSymbols = 1 << kNumLowLenBits
kNumMidLenSymbols = 1 << kNumMidLenBits
kNumLenSymbols = kNumLowLenSymbols + kNumMidLenSymbols + (1 << kNumHighLenBits)
kMatchMaxLen = kMatchMinLen + kNumLenSymbols - 1
)
// A streamError reports the presence of corrupt input stream.
var streamError = errors.New("error in lzma encoded data stream")
// A headerError reports an error in the header of the lzma encoder file.
var headerError = errors.New("error in lzma header")
// A nReadError reports what its message reads
var nReadError = errors.New("number of bytes returned by Reader.Read() didn't meet expectances")
// A nWriteError reports what its message reads
var nWriteError = errors.New("number of bytes returned by Writer.Write() didn't meet expectances")
// TODO: implement this err
// A dataIntegrityError reports an error encountered while cheching data integrity.
// -- from lzma.txt:
// You can use multiple checks to test data integrity after full decompression:
// 1) Check Result and "status" variable.
// 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
// 3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
// You must use correct finish mode in that case.
//
//type dataIntegrityError struct {
// msg string
// // hz
//}
func stateUpdateChar(index uint32) uint32 {
if index < 4 {
return 0
}
if index < 10 {
return index - 3
}
return index - 6
}
func stateUpdateMatch(index uint32) uint32 {
if index < 7 {
return 7
}
return 10
}
func stateUpdateRep(index uint32) uint32 {
if index < 7 {
return 8
}
return 11
}
func stateUpdateShortRep(index uint32) uint32 {
if index < 7 {
return 9
}
return 11
}
func stateIsCharState(index uint32) bool {
if index < 7 {
return true
}
return false
}
func getLenToPosState(length uint32) uint32 {
length -= kMatchMinLen
if length < kNumLenToPosStates {
return length
}
return kNumLenToPosStates - 1
}
// LZMA compressed file format
// ---------------------------
// Offset Size Description
// 0 1 Special LZMA properties (lc,lp, pb in encoded form)
// 1 4 Dictionary size (little endian)
// 5 8 Uncompressed size (little endian). Size -1 stands for unknown size
// lzma properties
type props struct {
litContextBits, // lc
litPosStateBits, // lp
posStateBits uint8 // pb
dictSize uint32
}
func (p *props) decodeProps(buf []byte) {
d := buf[0]
if d > (9 * 5 * 5) {
throw(headerError)
}
p.litContextBits = d % 9
d /= 9
p.posStateBits = d / 5
p.litPosStateBits = d % 5
if p.litContextBits > kNumLitContextBitsMax || p.litPosStateBits > 4 || p.posStateBits > kNumPosStatesBitsMax {
throw(headerError)
}
for i := 0; i < 4; i++ {
p.dictSize += uint32(buf[i+1]) << uint32(i*8)
}
}
type decoder struct {
// i/o
rd *rangeDecoder // r
outWin *lzOutWindow // w
// lzma header
prop *props
unpackSize int64
// hz
matchDecoders []uint16
repDecoders []uint16
repG0Decoders []uint16
repG1Decoders []uint16
repG2Decoders []uint16
rep0LongDecoders []uint16
posSlotCoders []*rangeBitTreeCoder
posDecoders []uint16
posAlignCoder *rangeBitTreeCoder
lenCoder *lenCoder
repLenCoder *lenCoder
litCoder *litCoder
dictSizeCheck uint32
posStateMask uint32
}
func (z *decoder) doDecode() {
var state uint32 = 0
var rep0 uint32 = 0
var rep1 uint32 = 0
var rep2 uint32 = 0
var rep3 uint32 = 0
var nowPos uint64 = 0
var prevByte byte = 0
for z.unpackSize < 0 || int64(nowPos) < z.unpackSize {
posState := uint32(nowPos) & z.posStateMask
if z.rd.decodeBit(z.matchDecoders, state<<kNumPosStatesBitsMax+posState) == 0 {
lsc := z.litCoder.getSubCoder(uint32(nowPos), prevByte)
if !stateIsCharState(state) {
prevByte = lsc.decodeWithMatchByte(z.rd, z.outWin.getByte(rep0))
} else {
prevByte = lsc.decodeNormal(z.rd)
}
z.outWin.putByte(prevByte)
state = stateUpdateChar(state)
nowPos++
} else {
var length uint32
if z.rd.decodeBit(z.repDecoders, state) == 1 {
length = 0
if z.rd.decodeBit(z.repG0Decoders, state) == 0 {
if z.rd.decodeBit(z.rep0LongDecoders, state<<kNumPosStatesBitsMax+posState) == 0 {
state = stateUpdateShortRep(state)
length = 1
}
} else {
var distance uint32
if z.rd.decodeBit(z.repG1Decoders, state) == 0 {
distance = rep1
} else {
if z.rd.decodeBit(z.repG2Decoders, state) == 0 {
distance = rep2
} else {
distance, rep3 = rep3, rep2
}
rep2 = rep1
}
rep1, rep0 = rep0, distance
}
if length == 0 {
length = z.repLenCoder.decode(z.rd, posState) + kMatchMinLen
state = stateUpdateRep(state)
}
} else {
rep3, rep2, rep1 = rep2, rep1, rep0
length = z.lenCoder.decode(z.rd, posState) + kMatchMinLen
state = stateUpdateMatch(state)
posSlot := z.posSlotCoders[getLenToPosState(length)].decode(z.rd)
if posSlot >= kStartPosModelIndex {
numDirectBits := posSlot>>1 - 1
rep0 = (2 | posSlot&1) << numDirectBits
if posSlot < kEndPosModelIndex {
rep0 += reverseDecodeIndex(z.rd, z.posDecoders, rep0-posSlot-1, numDirectBits)
} else {
rep0 += z.rd.decodeDirectBits(numDirectBits-kNumAlignBits) << kNumAlignBits
rep0 += z.posAlignCoder.reverseDecode(z.rd)
if int32(rep0) < 0 {
if rep0 == 0xFFFFFFFF {
break
}
throw(streamError)
}
}
} else {
rep0 = posSlot
}
}
if uint64(rep0) >= nowPos || rep0 >= z.dictSizeCheck {
throw(streamError)
}
z.outWin.copyBlock(rep0, length)
nowPos += uint64(length)
prevByte = z.outWin.getByte(0)
}
}
z.outWin.flush()
//if z.unpackSize != -1 {
// if z.outWin.unpacked != z.unpackSize {
// throw(&dataIntegrityError{})
// }
//}
}
func (z *decoder) decoder(r io.Reader, w io.Writer) (err error) {
defer handlePanics(&err)
// read 13 bytes (lzma header)
header := make([]byte, lzmaHeaderSize)
n, err := r.Read(header)
if err != nil {
return
}
if n != lzmaHeaderSize {
return nReadError
}
z.prop = &props{}
z.prop.decodeProps(header)
z.unpackSize = 0
for i := 0; i < 8; i++ {
b := header[lzmaPropSize+i]
z.unpackSize = z.unpackSize | int64(b)<<uint64(8*i)
}
// do not move before r.Read(header)
z.rd = newRangeDecoder(r)
z.dictSizeCheck = maxUInt32(z.prop.dictSize, 1)
z.outWin = newLzOutWindow(w, maxUInt32(z.dictSizeCheck, 1<<12))
z.litCoder = newLitCoder(uint32(z.prop.litPosStateBits), uint32(z.prop.litContextBits))
z.lenCoder = newLenCoder(uint32(1 << z.prop.posStateBits))
z.repLenCoder = newLenCoder(uint32(1 << z.prop.posStateBits))
z.posStateMask = uint32(1<<z.prop.posStateBits - 1)
z.matchDecoders = initBitModels(kNumStates << kNumPosStatesBitsMax)
z.repDecoders = initBitModels(kNumStates)
z.repG0Decoders = initBitModels(kNumStates)
z.repG1Decoders = initBitModels(kNumStates)
z.repG2Decoders = initBitModels(kNumStates)
z.rep0LongDecoders = initBitModels(kNumStates << kNumPosStatesBitsMax)
z.posDecoders = initBitModels(kNumFullDistances - kEndPosModelIndex)
z.posSlotCoders = make([]*rangeBitTreeCoder, kNumLenToPosStates)
for i := 0; i < kNumLenToPosStates; i++ {
z.posSlotCoders[i] = newRangeBitTreeCoder(kNumPosSlotBits)
}
z.posAlignCoder = newRangeBitTreeCoder(kNumAlignBits)
z.doDecode()
return
}
// NewReader returns a new ReadCloser that can be used to read the uncompressed
// version of r. It is the caller's responsibility to call Close on the ReadCloser
// when finished reading.
//
func NewReader(r io.Reader) io.ReadCloser {
var z decoder
pr, pw := io.Pipe()
go func() {
err := z.decoder(r, pw)
pw.CloseWithError(err)
}()
return pr
}
+55
View File
@@ -0,0 +1,55 @@
// Copyright (c) 2010, Andrei Vieru. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package lzma
import (
"bytes"
"io"
"log"
"testing"
)
func TestDecoder(t *testing.T) {
b := new(bytes.Buffer)
for _, tt := range lzmaTests {
in := bytes.NewBuffer(tt.lzma)
r := NewReader(in)
defer r.Close()
b.Reset()
n, err := io.Copy(b, r)
if err != tt.err {
t.Errorf("%s: io.Copy: %v, want %v", tt.descr, err, tt.err)
}
if err == nil { // if err != nil, there is little chance that data is decoded correctly, if at all
s := b.String()
if s != tt.raw {
t.Errorf("%s: got %d-byte %q, want %d-byte %q", tt.descr, n, s, len(tt.raw), tt.raw)
}
}
}
}
func BenchmarkDecoder(b *testing.B) {
b.StopTimer()
buf := new(bytes.Buffer)
for i := 0; i < b.N; i++ {
buf.Reset()
in := bytes.NewBuffer(bench.lzma)
b.StartTimer()
// timer starts before this contructor because variable "in" already
// contains data, so the decoding start rigth away
r := NewReader(in)
n, err := io.Copy(buf, r)
b.StopTimer()
if err != nil {
log.Fatalf("%v", err)
}
b.SetBytes(n)
r.Close()
}
if bytes.Equal(buf.Bytes(), bench.raw) == false { // check only after last iteration
log.Fatalf("%s: got %d-byte %q, want %d-byte %q", bench.descr, len(buf.Bytes()), buf.String(), len(bench.raw), bench.raw)
}
}
+1150
View File
File diff suppressed because it is too large Load Diff
+157
View File
@@ -0,0 +1,157 @@
// Copyright (c) 2010, Andrei Vieru. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package lzma
import (
"bytes"
"io"
"io/ioutil"
"log"
"testing"
)
func pipe(t *testing.T, efunc func(io.WriteCloser), dfunc func(io.ReadCloser), size int64) {
level := 3
pr, pw := io.Pipe()
go func() {
defer pw.Close()
ze := NewWriterSizeLevel(pw, size, level)
defer ze.Close()
efunc(ze)
}()
defer pr.Close()
zd := NewReader(pr)
defer zd.Close()
dfunc(zd)
}
func testEmpty(t *testing.T, sizeIsKnown bool) {
size := int64(-1)
if sizeIsKnown == true {
size = 0
}
pipe(t,
func(w io.WriteCloser) {},
func(r io.ReadCloser) {
b, err := ioutil.ReadAll(r)
if err != nil {
t.Fatalf("%v", err)
}
if len(b) != 0 {
t.Fatalf("did not read an empty slice")
}
},
size)
}
func TestEmpty1(t *testing.T) {
testEmpty(t, true)
}
func TestEmpty2(t *testing.T) {
testEmpty(t, false)
}
func testBoth(t *testing.T, sizeIsKnown bool) {
size := int64(-1)
payload := []byte("lzmalzmalzma")
if sizeIsKnown == true {
size = int64(len(payload))
}
pipe(t,
func(w io.WriteCloser) {
n, err := w.Write(payload)
if err != nil {
t.Fatalf("%v", err)
}
if n != len(payload) {
t.Fatalf("wrote %d bytes, want %d bytes", n, len(payload))
}
},
func(r io.ReadCloser) {
b, err := ioutil.ReadAll(r)
if err != nil {
t.Fatalf("%v", err)
}
if string(b) != string(payload) {
t.Fatalf("payload is %s, want %s", string(b), string(payload))
}
},
size)
}
func TestBoth1(t *testing.T) {
testBoth(t, true)
}
func TestBoth2(t *testing.T) {
testBoth(t, false)
}
func TestEncoder(t *testing.T) {
b := new(bytes.Buffer)
for _, tt := range lzmaTests {
if tt.err == nil {
pr, pw := io.Pipe()
defer pr.Close()
in := bytes.NewBuffer([]byte(tt.raw))
size := int64(-1)
if tt.size == true {
size = int64(len([]byte(tt.raw)))
}
go func() {
defer pw.Close()
w := NewWriterSizeLevel(pw, size, tt.level)
defer w.Close()
_, err := io.Copy(w, in)
if err != nil {
t.Errorf("%v", err)
}
}()
b.Reset()
_, err := io.Copy(b, pr)
if err != nil {
t.Errorf("%v", err)
}
res := b.Bytes()
if bytes.Equal(res, tt.lzma) == false {
t.Errorf("%s: got %d-byte %q, want %d-byte %q", tt.descr, len(res), string(res), len(tt.lzma), string(tt.lzma))
}
}
}
}
func BenchmarkEncoder(b *testing.B) {
b.StopTimer()
buf := new(bytes.Buffer)
start := make(chan bool)
for i := 0; i < b.N; i++ {
in := bytes.NewBuffer(bench.raw)
pr, pw := io.Pipe()
defer pr.Close()
go func() {
defer pw.Close()
w := NewWriterLevel(pw, bench.level)
defer w.Close()
start <- true
n, err := io.Copy(w, in)
if err != nil {
log.Fatalf("%v", err)
}
b.SetBytes(n)
}()
buf.Reset()
<-start // wait for encoder to start encoding before starting the timer
b.StartTimer()
_, err := io.Copy(buf, pr)
b.StopTimer()
if err != nil {
log.Fatalf("%v", err)
}
}
if bytes.Equal(buf.Bytes(), bench.lzma) == false { // check only once, not at every iteration
log.Fatalf("%s: got %d-byte %q, want %d-byte %q", bench.descr, len(buf.Bytes()), buf.String(), len(bench.lzma), string(bench.lzma))
}
}
+27
View File
@@ -0,0 +1,27 @@
// Copyright (c) 2010, Andrei Vieru. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of the author nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+261
View File
@@ -0,0 +1,261 @@
// Copyright (c) 2010, Andrei Vieru. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
//"compress/lzma"
"github.com/kjk/lzma"
"flag"
"fmt"
"io"
"log"
"os"
"path"
"runtime"
"strings"
)
var (
stdout = flag.Bool("c", false, "write on standard output, keep original files unchanged")
decompress = flag.Bool("d", false, "decompress; see also -c and -k")
force = flag.Bool("f", false, "force overwrite of output file")
help = flag.Bool("h", false, "print this help message")
keep = flag.Bool("k", false, "keep original files unchaned")
suffix = flag.String("s", "lzma", "use provided suffix on compressed files")
level = flag.Int("l", 5, "compression level [1 ... 9]")
cores = flag.Int("cores", 1, "number of cores to use for parallelization")
stdin bool
)
func usage() {
fmt.Fprintf(os.Stderr, "Usage: %s [OPTION]... [FILE]\n", os.Args[0])
fmt.Fprintf(os.Stderr, "Compress or uncompress FILE (by default, compress FILE in-place).\n\n")
flag.PrintDefaults()
fmt.Fprintf(os.Stderr, "\nWith no FILE, or when FILE is -, read standard input.\n")
}
func exit(msg string) {
usage()
fmt.Fprintln(os.Stderr)
log.Fatalf("%s: check args: %s\n\n", os.Args[0], msg)
}
func setByUser(name string) (isSet bool) {
flag.Visit(func(f *flag.Flag) {
if f.Name == name {
isSet = true
}
})
return
}
func main() {
flag.Parse()
if *help == true {
usage()
log.Fatal(0)
}
//if *stdout == true && *suffix != "lzma" {
if *stdout == true && setByUser("s") == true {
exit("stdout set, suffix not used")
}
if *stdout == true && *force == true {
exit("stdout set, force not used")
}
if *stdout == true && *keep == true {
exit("stdout set, keep is redundant")
}
if flag.NArg() > 1 {
exit("too many file, provide at most one file at a time or check order of flags")
}
//if *decompress == true && *level != 5 {
if *decompress == true && setByUser("l") == true {
exit("compression level is used for compression only")
}
if *level < 1 || *level > 9 {
exit("compression level out of range")
}
if *cores < 1 || *cores > 32 {
exit("invalid number of cores")
}
runtime.GOMAXPROCS(*cores)
var inFilePath string
var outFilePath string
if flag.NArg() == 0 || flag.NArg() == 1 && flag.Args()[0] == "-" { // parse args: read from stdin
if *stdout != true {
exit("reading from stdin, can write only to stdout")
}
//if *suffix != "lzma" {
if setByUser("s") == true {
exit("reading from stdin, suffix not needed")
}
stdin = true
} else if flag.NArg() == 1 { // parse args: read from file
inFilePath = flag.Args()[0]
f, err := os.Lstat(inFilePath)
if err != nil {
log.Fatal(err.Error())
}
if f == nil {
exit(fmt.Sprintf("file %s not found", inFilePath))
}
if !!f.IsDir() {
exit(fmt.Sprintf("%s is not a regular file", inFilePath))
}
if *stdout == false { // parse args: write to file
if *suffix == "" {
exit("suffix can't be an empty string")
}
if *decompress == true {
outFileDir, outFileName := path.Split(inFilePath)
if strings.HasSuffix(outFileName, "."+*suffix) {
if len(outFileName) > len("."+*suffix) {
nstr := strings.SplitN(outFileName, ".", len(outFileName))
estr := strings.Join(nstr[0:len(nstr)-1], ".")
outFilePath = outFileDir + estr
} else {
log.Fatalf("error: can't strip suffix .%s from file %s", *suffix, inFilePath)
}
} else {
exit(fmt.Sprintf("file %s doesn't have suffix .%s", inFilePath, *suffix))
}
} else {
outFilePath = inFilePath + "." + *suffix
}
f, err = os.Lstat(outFilePath)
if err != nil && f != nil { // should be: ||| if err != nil && err != "file not found" ||| but i can't find the error's id
log.Fatal(err.Error())
}
if f != nil && !f.IsDir() {
if *force == true {
err = os.Remove(outFilePath)
if err != nil {
log.Fatal(err.Error())
}
} else {
exit(fmt.Sprintf("outFile %s exists. use force to overwrite", outFilePath))
}
} else if f != nil {
exit(fmt.Sprintf("outFile %s exists and is not a regular file", outFilePath))
}
}
}
pr, pw := io.Pipe()
//defer pr.Close()
//defer pw.Close()
if *decompress {
// read from inFile into pw
go func() {
defer pw.Close()
var inFile *os.File
var err error
if stdin == true {
inFile = os.Stdin
} else {
inFile, err = os.Open(inFilePath)
}
defer inFile.Close()
if err != nil {
log.Fatal(err.Error())
}
_, err = io.Copy(pw, inFile)
if err != nil {
log.Fatal(err.Error())
}
}()
// write into outFile from z
defer pr.Close()
z := lzma.NewReader(pr)
defer z.Close()
var outFile *os.File
var err error
if *stdout == true {
outFile = os.Stdout
} else {
outFile, err = os.Create(outFilePath)
}
defer outFile.Close()
if err != nil {
log.Fatal(err.Error())
}
_, err = io.Copy(outFile, z)
if err != nil {
log.Fatal(err.Error())
}
} else {
// read from inFile into z
go func() {
defer pw.Close()
var z io.WriteCloser
var inFile *os.File
var err error
if stdin == true {
inFile = os.Stdin
defer inFile.Close()
z = lzma.NewWriterLevel(pw, *level)
defer z.Close()
} else {
inFile, err = os.Open(inFilePath)
defer inFile.Close()
if err != nil {
log.Fatal(err.Error())
}
f, err := os.Lstat(inFilePath)
if err != nil {
log.Fatal(err.Error())
}
z = lzma.NewWriterSizeLevel(pw, int64(f.Size()), *level)
defer z.Close()
}
_, err = io.Copy(z, inFile)
if err != nil {
log.Fatal(err.Error())
}
}()
// write into outFile from pr
defer pr.Close()
var outFile *os.File
var err error
if *stdout == true {
outFile = os.Stdout
} else {
outFile, err = os.Create(outFilePath)
}
defer outFile.Close()
if err != nil {
log.Fatal(err.Error())
}
_, err = io.Copy(outFile, pr)
if err != nil {
log.Fatal(err.Error())
}
}
if *stdout == false && *keep == false {
err := os.Remove(inFilePath)
if err != nil {
log.Fatal(err.Error())
}
}
}
+126
View File
@@ -0,0 +1,126 @@
// Copyright (c) 2010, Andrei Vieru. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package lzma
type lenCoder struct {
choice []uint16
lowCoder []*rangeBitTreeCoder
midCoder []*rangeBitTreeCoder
highCoder *rangeBitTreeCoder
}
func newLenCoder(numPosStates /*1 << pb*/ uint32) *lenCoder {
lc := &lenCoder{
choice: initBitModels(2),
lowCoder: make([]*rangeBitTreeCoder, kNumPosStatesMax),
midCoder: make([]*rangeBitTreeCoder, kNumPosStatesMax),
highCoder: newRangeBitTreeCoder(kNumHighLenBits),
}
for i := uint32(0); i < numPosStates; i++ {
lc.lowCoder[i] = newRangeBitTreeCoder(kNumLowLenBits)
lc.midCoder[i] = newRangeBitTreeCoder(kNumMidLenBits)
}
return lc
}
func (lc *lenCoder) decode(rd *rangeDecoder, posState uint32) (res uint32) {
i := rd.decodeBit(lc.choice, 0)
if i == 0 {
res = lc.lowCoder[posState].decode(rd)
return
}
res = kNumLowLenSymbols
j := rd.decodeBit(lc.choice, 1)
if j == 0 {
k := lc.midCoder[posState].decode(rd)
res += k
return
} else {
l := lc.highCoder.decode(rd)
res = res + kNumMidLenSymbols + l
return
}
return
}
func (lc *lenCoder) encode(re *rangeEncoder, symbol, posState uint32) {
if symbol < kNumLowLenSymbols {
re.encode(lc.choice, 0, 0)
lc.lowCoder[posState].encode(re, symbol)
} else {
symbol -= kNumLowLenSymbols
re.encode(lc.choice, 0, 1)
if symbol < kNumMidLenSymbols {
re.encode(lc.choice, 1, 0)
lc.midCoder[posState].encode(re, symbol)
} else {
re.encode(lc.choice, 1, 1)
lc.highCoder.encode(re, symbol-kNumMidLenSymbols)
}
}
}
// write prices into prices []uint32
func (lc *lenCoder) setPrices(prices []uint32, posState, numSymbols, st uint32) {
a0 := getPrice0(lc.choice[0])
a1 := getPrice1(lc.choice[0])
b0 := a1 + getPrice0(lc.choice[1])
b1 := a1 + getPrice1(lc.choice[1])
var i uint32
for i = 0; i < kNumLowLenSymbols; i++ {
if i >= numSymbols {
return
}
prices[st+i] = a0 + lc.lowCoder[posState].getPrice(i)
}
for ; i < kNumLowLenSymbols+kNumMidLenSymbols; i++ {
if i >= numSymbols {
return
}
prices[st+i] = b0 + lc.midCoder[posState].getPrice(i-kNumLowLenSymbols)
}
for ; i < numSymbols; i++ {
prices[st+i] = b1 + lc.highCoder.getPrice(i-kNumLowLenSymbols-kNumMidLenSymbols)
}
}
type lenPriceTableCoder struct {
lc *lenCoder
prices []uint32
counters []uint32
tableSize uint32
}
func newLenPriceTableCoder(tableSize, numPosStates uint32) *lenPriceTableCoder {
pc := &lenPriceTableCoder{
lc: newLenCoder(numPosStates),
prices: make([]uint32, kNumLenSymbols<<kNumPosStatesBitsMax),
counters: make([]uint32, kNumPosStatesMax),
tableSize: tableSize,
}
for posState := uint32(0); posState < numPosStates; posState++ {
pc.updateTable(posState)
}
return pc
}
func (pc *lenPriceTableCoder) updateTable(posState uint32) {
pc.lc.setPrices(pc.prices, posState, pc.tableSize, posState*kNumLenSymbols)
pc.counters[posState] = pc.tableSize
}
func (pc *lenPriceTableCoder) getPrice(symbol, posState uint32) uint32 {
return pc.prices[posState*kNumLenSymbols+symbol]
}
func (pc *lenPriceTableCoder) encode(re *rangeEncoder, symbol, posState uint32) {
pc.lc.encode(re, symbol, posState)
pc.counters[posState]--
if pc.counters[posState] == 0 {
pc.updateTable(posState)
}
}
+128
View File
@@ -0,0 +1,128 @@
// Copyright (c) 2010, Andrei Vieru. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package lzma
type litSubCoder struct {
coders []uint16
}
func newLitSubCoder() *litSubCoder {
return &litSubCoder{
coders: initBitModels(0x300),
}
}
func (lsc *litSubCoder) decodeNormal(rd *rangeDecoder) byte {
symbol := uint32(1)
for symbol < 0x100 {
i := rd.decodeBit(lsc.coders, symbol)
symbol = symbol<<1 | i
}
return byte(symbol)
}
func (lsc *litSubCoder) decodeWithMatchByte(rd *rangeDecoder, matchByte byte) byte {
uMatchByte := uint32(matchByte)
symbol := uint32(1)
for symbol < 0x100 {
matchBit := (uMatchByte >> 7) & 1
uMatchByte <<= 1
bit := rd.decodeBit(lsc.coders, ((1+matchBit)<<8)+symbol)
symbol = (symbol << 1) | bit
if matchBit != bit {
for symbol < 0x100 {
i := rd.decodeBit(lsc.coders, symbol)
symbol = (symbol << 1) | i
}
break
}
}
return byte(symbol)
}
func (lsc *litSubCoder) encode(re *rangeEncoder, symbol byte) {
uSymbol := uint32(symbol)
context := uint32(1)
for i := uint32(7); int32(i) >= 0; i-- {
bit := (uSymbol >> i) & 1
re.encode(lsc.coders, context, bit)
context = context<<1 | bit
}
}
func (lsc *litSubCoder) encodeMatched(re *rangeEncoder, matchByte, symbol byte) {
uMatchByte := uint32(matchByte)
uSymbol := uint32(symbol)
context := uint32(1)
same := true
for i := uint32(7); int32(i) >= 0; i-- {
bit := (uSymbol >> i) & 1
state := context
if same == true {
matchBit := (uMatchByte >> i) & 1
state += (1 + matchBit) << 8
same = false
if matchBit == bit {
same = true
}
}
re.encode(lsc.coders, state, bit)
context = context<<1 | bit
}
}
func (lsc *litSubCoder) getPrice(matchMode bool, matchByte, symbol byte) uint32 {
uMatchByte := uint32(matchByte)
uSymbol := uint32(symbol)
price := uint32(0)
context := uint32(1)
i := uint32(7)
if matchMode == true {
for ; int32(i) >= 0; i-- {
matchBit := (uMatchByte >> i) & 1
bit := (uSymbol >> i) & 1
price += getPrice(lsc.coders[(1+matchBit)<<8+context], bit)
context = context<<1 | bit
if matchBit != bit {
i--
break
}
}
}
for ; int32(i) >= 0; i-- {
bit := (uSymbol >> i) & 1
price += getPrice(lsc.coders[context], bit)
context = context<<1 | bit
}
return price
}
type litCoder struct {
coders []*litSubCoder
numPrevBits uint32 // literal context bits // lc
// numPosBits uint32 // literal position state bits // lp
posMask uint32
}
func newLitCoder(numPosBits, numPrevBits uint32) *litCoder {
numStates := uint32(1) << (numPrevBits + numPosBits)
lc := &litCoder{
coders: make([]*litSubCoder, numStates),
numPrevBits: numPrevBits,
// numPosBits: numPosBits,
posMask: (1 << numPosBits) - 1,
}
for i := uint32(0); i < numStates; i++ {
lc.coders[i] = newLitSubCoder()
}
return lc
}
func (lc *litCoder) getSubCoder(pos uint32, prevByte byte) *litSubCoder {
return lc.coders[((pos&lc.posMask)<<lc.numPrevBits)+uint32(prevByte>>(8-lc.numPrevBits))]
}
+117
View File
@@ -0,0 +1,117 @@
// Copyright (c) 2010, Andrei Vieru. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package lzma
type rangeBitTreeCoder struct {
models []uint16 // length(models) is at most 1<<8
numBitLevels uint32 // min 2; max 8
}
func newRangeBitTreeCoder(numBitLevels uint32) *rangeBitTreeCoder {
return &rangeBitTreeCoder{
numBitLevels: numBitLevels,
models: initBitModels(1 << numBitLevels),
}
}
func (rc *rangeBitTreeCoder) decode(rd *rangeDecoder) (res uint32) {
res = 1
for bitIndex := rc.numBitLevels; bitIndex != 0; bitIndex-- {
bit := rd.decodeBit(rc.models, res)
res = res<<1 + bit
}
res -= 1 << rc.numBitLevels
return
}
func (rc *rangeBitTreeCoder) reverseDecode(rd *rangeDecoder) (res uint32) {
index := uint32(1)
res = 0
for bitIndex := uint32(0); bitIndex < rc.numBitLevels; bitIndex++ {
bit := rd.decodeBit(rc.models, index)
index <<= 1
index += bit
res |= bit << bitIndex
}
return
}
func reverseDecodeIndex(rd *rangeDecoder, models []uint16, startIndex, numBitModels uint32) (res uint32) {
index := uint32(1)
res = 0
for bitIndex := uint32(0); bitIndex < numBitModels; bitIndex++ {
bit := rd.decodeBit(models, startIndex+index)
index <<= 1
index += bit
res |= bit << bitIndex
}
return
}
func (rc *rangeBitTreeCoder) encode(re *rangeEncoder, symbol uint32) {
m := uint32(1)
for bitIndex := rc.numBitLevels; bitIndex != 0; {
bitIndex--
bit := (symbol >> bitIndex) & 1
re.encode(rc.models, m, bit)
m = m<<1 | bit
}
}
func (rc *rangeBitTreeCoder) reverseEncode(re *rangeEncoder, symbol uint32) {
m := uint32(1)
for i := uint32(0); i < rc.numBitLevels; i++ {
bit := symbol & 1
re.encode(rc.models, m, bit)
m = m<<1 | bit
symbol >>= 1
}
}
func (rc *rangeBitTreeCoder) getPrice(symbol uint32) (res uint32) {
res = 0
m := uint32(1)
for bitIndex := rc.numBitLevels; bitIndex != 0; {
bitIndex--
bit := (symbol >> bitIndex) & 1
res += getPrice(rc.models[m], bit)
m = m<<1 + bit
}
return
}
func (rc *rangeBitTreeCoder) reverseGetPrice(symbol uint32) (res uint32) {
res = 0
m := uint32(1)
for i := rc.numBitLevels; i != 0; i-- {
bit := symbol & 1
symbol >>= 1
res += getPrice(rc.models[m], bit)
m = m<<1 | bit
}
return
}
func reverseGetPriceIndex(models []uint16, startIndex, numBitLevels, symbol uint32) (res uint32) {
res = 0
m := uint32(1)
for i := numBitLevels; i != 0; i-- {
bit := symbol & 1
symbol >>= 1
res += getPrice(models[startIndex+m], bit)
m = m<<1 | bit
}
return
}
func reverseEncodeIndex(re *rangeEncoder, models []uint16, startIndex, numBitLevels, symbol uint32) {
m := uint32(1)
for i := uint32(0); i < numBitLevels; i++ {
bit := symbol & 1
re.encode(models, startIndex+m, bit)
m = m<<1 | bit
symbol >>= 1
}
}
+249
View File
@@ -0,0 +1,249 @@
// Copyright (c) 2010, Andrei Vieru. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package lzma
import (
"bufio"
"io"
)
const (
kTopValue = 1 << 24
kNumBitModelTotalBits = 11
kBitModelTotal = 1 << kNumBitModelTotalBits
kNumMoveBits = 5
)
// The actual read interface needed by NewDecoder. If the passed in io.Reader
// does not also have ReadByte, the NewDecoder will introduce its own buffering.
//
type Reader interface {
io.Reader
ReadByte() (c byte, err error)
}
type rangeDecoder struct {
r Reader
rrange uint32
code uint32
}
func makeReader(r io.Reader) Reader {
if rr, ok := r.(Reader); ok {
return rr
}
return bufio.NewReader(r)
}
func newRangeDecoder(r io.Reader) *rangeDecoder {
rd := &rangeDecoder{
r: makeReader(r),
rrange: 0xFFFFFFFF,
code: 0,
}
buf := make([]byte, 5)
n, err := rd.r.Read(buf)
if err != nil {
throw(err)
}
if n != len(buf) {
throw(nReadError)
}
for i := 0; i < len(buf); i++ {
rd.code = rd.code<<8 | uint32(buf[i])
}
return rd
}
func (rd *rangeDecoder) decodeDirectBits(numTotalBits uint32) (res uint32) {
for i := numTotalBits; i != 0; i-- {
rd.rrange >>= 1
t := (rd.code - rd.rrange) >> 31
rd.code -= rd.rrange & (t - 1)
res = res<<1 | (1 - t)
if rd.rrange < kTopValue {
c, err := rd.r.ReadByte()
if err != nil {
throw(err)
}
rd.code = rd.code<<8 | uint32(c)
rd.rrange <<= 8
}
}
return
}
func (rd *rangeDecoder) decodeBit(probs []uint16, index uint32) (res uint32) {
prob := probs[index]
newBound := (rd.rrange >> kNumBitModelTotalBits) * uint32(prob)
if rd.code < newBound {
rd.rrange = newBound
probs[index] = prob + (kBitModelTotal-prob)>>kNumMoveBits
if rd.rrange < kTopValue {
b, err := rd.r.ReadByte()
if err != nil {
throw(err)
}
rd.code = rd.code<<8 | uint32(b)
rd.rrange <<= 8
}
res = 0
} else {
rd.rrange -= newBound
rd.code -= newBound
probs[index] = prob - prob>>kNumMoveBits
if rd.rrange < kTopValue {
b, err := rd.r.ReadByte()
if err != nil {
throw(err)
}
rd.code = rd.code<<8 | uint32(b)
rd.rrange <<= 8
}
res = 1
}
return
}
func initBitModels(length uint32) (probs []uint16) {
probs = make([]uint16, length)
val := uint16(kBitModelTotal) >> 1
for i := uint32(0); i < length; i++ {
probs[i] = val // 1 << 10
}
return
}
const (
kNumMoveReducingBits = 2
kNumBitPriceShiftBits = 6
)
// The actual write interface needed by NewEncoder. If the passed in io.Writer
// does not also have WriteByte and Flush, the NewEncoder will wrap it into an
// bufio.Writer.
//
type Writer interface {
io.Writer
Flush() error
WriteByte(c byte) error
}
type rangeEncoder struct {
w Writer
low uint64
pos uint64
cacheSize uint32
cache uint32
rrange uint32
}
func makeWriter(w io.Writer) Writer {
if ww, ok := w.(Writer); ok {
return ww
}
return bufio.NewWriter(w)
}
func newRangeEncoder(w io.Writer) *rangeEncoder {
return &rangeEncoder{
w: makeWriter(w),
low: 0,
pos: 0,
cacheSize: 1,
cache: 0,
rrange: 0xFFFFFFFF,
}
}
func (re *rangeEncoder) flush() {
for i := 0; i < 5; i++ {
re.shiftLow()
}
err := re.w.Flush()
if err != nil {
throw(err)
}
}
func (re *rangeEncoder) shiftLow() {
lowHi := uint32(re.low >> 32)
if lowHi != 0 || re.low < uint64(0x00000000FF000000) {
re.pos += uint64(re.cacheSize)
temp := re.cache
dwtemp := uint32(1) // execute the loop at least once (do-while)
for ; dwtemp != 0; dwtemp = re.cacheSize {
err := re.w.WriteByte(byte(temp + lowHi))
if err != nil {
throw(err)
}
temp = 0x000000FF
re.cacheSize--
}
re.cache = uint32(re.low) >> 24
}
re.cacheSize++
re.low = uint64(uint32(re.low) << 8)
}
func (re *rangeEncoder) encodeDirectBits(v, numTotalBits uint32) {
for i := numTotalBits - 1; int32(i) >= 0; i-- {
re.rrange >>= 1
if (v>>i)&1 == 1 {
re.low += uint64(re.rrange)
}
if re.rrange < kTopValue {
re.rrange <<= 8
re.shiftLow()
}
}
}
func (re *rangeEncoder) processedSize() uint64 {
return uint64(re.cacheSize) + re.pos + 4
}
func (re *rangeEncoder) encode(probs []uint16, index, symbol uint32) {
prob := probs[index]
newBound := (re.rrange >> kNumBitModelTotalBits) * uint32(prob)
if symbol == 0 {
re.rrange = newBound
probs[index] = prob + (kBitModelTotal-prob)>>kNumMoveBits
} else {
re.low += uint64(newBound) & uint64(0xFFFFFFFFFFFFFFFF)
re.rrange -= newBound
probs[index] = prob - prob>>kNumMoveBits
}
if re.rrange < kTopValue {
re.rrange <<= 8
re.shiftLow()
}
}
var probPrices []uint32 = make([]uint32, kBitModelTotal>>kNumMoveReducingBits) // len(probPrices) = 512
// should be called in the encoder's contructor.
func initProbPrices() {
kNumBits := uint32(kNumBitModelTotalBits - kNumMoveReducingBits)
for i := kNumBits - 1; int32(i) >= 0; i-- {
start := uint32(1) << (kNumBits - i - 1)
end := uint32(1) << (kNumBits - i)
for j := start; j < end; j++ {
probPrices[j] = i<<kNumBitPriceShiftBits + ((end-j)<<kNumBitPriceShiftBits)>>(kNumBits-i-1)
}
}
}
func getPrice(prob uint16, symbol uint32) uint32 {
return probPrices[(((uint32(prob)-symbol)^(-symbol))&(uint32(kBitModelTotal)-1))>>kNumMoveReducingBits]
}
func getPrice0(prob uint16) uint32 {
return probPrices[prob>>kNumMoveReducingBits]
}
func getPrice1(prob uint16) uint32 {
return probPrices[(kBitModelTotal-prob)>>kNumMoveReducingBits]
}
+33
View File
@@ -0,0 +1,33 @@
// Copyright (c) 2010, Andrei Vieru. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package lzma
func minInt32(left int32, right int32) int32 {
if left < right {
return left
}
return right
}
func minUInt32(left uint32, right uint32) uint32 {
if left < right {
return left
}
return right
}
func maxInt32(left int32, right int32) int32 {
if left > right {
return left
}
return right
}
func maxUInt32(left uint32, right uint32) uint32 {
if left > right {
return left
}
return right
}