dep ensure

This commit is contained in:
Benjamin Elder
2018-10-24 17:24:58 -07:00
parent 41845522f6
commit 163515c5a0
6525 changed files with 84 additions and 3291220 deletions

View File

@@ -1,25 +0,0 @@
# .gitignore
TODO.html
README.html
lzma/writer.txt
lzma/reader.txt
cmd/gxz/gxz
cmd/xb/xb
# test executables
*.test
# profile files
*.out
# vim swap file
.*.swp
# executables on windows
*.exe
# default compression test file
enwik8*

View File

@@ -1,71 +0,0 @@
# Package xz
This Go language package supports the reading and writing of xz
compressed streams. It includes also a gxz command for compressing and
decompressing data. The package is completely written in Go and doesn't
have any dependency on any C code.
The package is currently under development. There might be bugs and APIs
are not considered stable. At this time the package cannot compete with
the xz tool regarding compression speed and size. The algorithms there
have been developed over a long time and are highly optimized. However
there are a number of improvements planned and I'm very optimistic about
parallel compression and decompression. Stay tuned!
# Using the API
The following example program shows how to use the API.
package main
import (
"bytes"
"io"
"log"
"os"
"github.com/ulikunitz/xz"
)
func main() {
const text = "The quick brown fox jumps over the lazy dog.\n"
var buf bytes.Buffer
// compress text
w, err := xz.NewWriter(&buf)
if err != nil {
log.Fatalf("xz.NewWriter error %s", err)
}
if _, err := io.WriteString(w, text); err != nil {
log.Fatalf("WriteString error %s", err)
}
if err := w.Close(); err != nil {
log.Fatalf("w.Close error %s", err)
}
// decompress buffer and write output to stdout
r, err := xz.NewReader(&buf)
if err != nil {
log.Fatalf("NewReader error %s", err)
}
if _, err = io.Copy(os.Stdout, r); err != nil {
log.Fatalf("io.Copy error %s", err)
}
}
# Using the gxz compression tool
The package includes a gxz command line utility for compression and
decompression.
Use following command for installation:
$ go get github.com/ulikunitz/xz/cmd/gxz
To test it call the following command.
$ gxz bigfile
After some time a much smaller file bigfile.xz will replace bigfile.
To decompress it use the following command.
$ gxz -d bigfile.xz

View File

@@ -1,315 +0,0 @@
# TODO list
## Release v0.6
1. Review encoder and check for lzma improvements under xz.
2. Fix binary tree matcher.
3. Compare compression ratio with xz tool using comparable parameters
and optimize parameters
4. Do some optimizations
- rename operation action and make it a simple type of size 8
- make maxMatches, wordSize parameters
- stop searching after a certain length is found (parameter sweetLen)
## Release v0.7
1. Optimize code
2. Do statistical analysis to get linear presets.
3. Test sync.Pool compatability for xz and lzma Writer and Reader
3. Fuzz optimized code.
## Release v0.8
1. Support parallel go routines for writing and reading xz files.
2. Support a ReaderAt interface for xz files with small block sizes.
3. Improve compatibility between gxz and xz
4. Provide manual page for gxz
## Release v0.9
1. Improve documentation
2. Fuzz again
## Release v1.0
1. Full functioning gxz
2. Add godoc URL to README.md (godoc.org)
3. Resolve all issues.
4. Define release candidates.
5. Public announcement.
## Package lzma
### Release v0.6
- Rewrite Encoder into a simple greedy one-op-at-a-time encoder
including
+ simple scan at the dictionary head for the same byte
+ use the killer byte (requiring matches to get longer, the first
test should be the byte that would make the match longer)
## Optimizations
- There may be a lot of false sharing in lzma.State; check whether this
can be improved by reorganizing the internal structure of it.
- Check whether batching encoding and decoding improves speed.
### DAG optimizations
- Use full buffer to create minimal bit-length above range encoder.
- Might be too slow (see v0.4)
### Different match finders
- hashes with 2, 3 characters additional to 4 characters
- binary trees with 2-7 characters (uint64 as key, use uint32 as
pointers into a an array)
- rb-trees with 2-7 characters (uint64 as key, use uint32 as pointers
into an array with bit-steeling for the colors)
## Release Procedure
- execute goch -l for all packages; probably with lower param like 0.5.
- check orthography with gospell
- Write release notes in doc/relnotes.
- Update README.md
- xb copyright . in xz directory to ensure all new files have Copyright
header
- VERSION=<version> go generate github.com/ulikunitz/xz/... to update
version files
- Execute test for Linux/amd64, Linux/x86 and Windows/amd64.
- Update TODO.md - write short log entry
- git checkout master && git merge dev
- git tag -a <version>
- git push
## Log
### 2017-06-05
Release v0.5.4 fixes issues #15 of another problem with the padding size
check for the xz block header. I removed the check completely.
### 2017-02-15
Release v0.5.3 fixes issue #12 regarding the decompression of an empty
XZ stream. Many thanks to Tomasz Kłak, who reported the issue.
### 2016-12-02
Release v0.5.2 became necessary to allow the decoding of xz files with
4-byte padding in the block header. Many thanks to Greg, who reported
the issue.
### 2016-07-23
Release v0.5.1 became necessary to fix problems with 32-bit platforms.
Many thanks to Bruno Brigas, who reported the issue.
### 2016-07-04
Release v0.5 provides improvements to the compressor and provides support for
the decompression of xz files with multiple xz streams.
### 2016-01-31
Another compression rate increase by checking the byte at length of the
best match first, before checking the whole prefix. This makes the
compressor even faster. We have now a large time budget to beat the
compression ratio of the xz tool. For enwik8 we have now over 40 seconds
to reduce the compressed file size for another 7 MiB.
### 2016-01-30
I simplified the encoder. Speed and compression rate increased
dramatically. A high compression rate affects also the decompression
speed. The approach with the buffer and optimizing for operation
compression rate has not been successful. Going for the maximum length
appears to be the best approach.
### 2016-01-28
The release v0.4 is ready. It provides a working xz implementation,
which is rather slow, but works and is interoperable with the xz tool.
It is an important milestone.
### 2016-01-10
I have the first working implementation of an xz reader and writer. I'm
happy about reaching this milestone.
### 2015-12-02
I'm now ready to implement xz because, I have a working LZMA2
implementation. I decided today that v0.4 will use the slow encoder
using the operations buffer to be able to go back, if I intend to do so.
### 2015-10-21
I have restarted the work on the library. While trying to implement
LZMA2, I discovered that I need to resimplify the encoder and decoder
functions. The option approach is too complicated. Using a limited byte
writer and not caring for written bytes at all and not to try to handle
uncompressed data simplifies the LZMA encoder and decoder much.
Processing uncompressed data and handling limits is a feature of the
LZMA2 format not of LZMA.
I learned an interesting method from the LZO format. If the last copy is
too far away they are moving the head one 2 bytes and not 1 byte to
reduce processing times.
### 2015-08-26
I have now reimplemented the lzma package. The code is reasonably fast,
but can still be optimized. The next step is to implement LZMA2 and then
xz.
### 2015-07-05
Created release v0.3. The version is the foundation for a full xz
implementation that is the target of v0.4.
### 2015-06-11
The gflag package has been developed because I couldn't use flag and
pflag for a fully compatible support of gzip's and lzma's options. It
seems to work now quite nicely.
### 2015-06-05
The overflow issue was interesting to research, however Henry S. Warren
Jr. Hacker's Delight book was very helpful as usual and had the issue
explained perfectly. Fefe's information on his website was based on the
C FAQ and quite bad, because it didn't address the issue of -MININT ==
MININT.
### 2015-06-04
It has been a productive day. I improved the interface of lzma.Reader
and lzma.Writer and fixed the error handling.
### 2015-06-01
By computing the bit length of the LZMA operations I was able to
improve the greedy algorithm implementation. By using an 8 MByte buffer
the compression rate was not as good as for xz but already better then
gzip default.
Compression is currently slow, but this is something we will be able to
improve over time.
### 2015-05-26
Checked the license of ogier/pflag. The binary lzmago binary should
include the license terms for the pflag library.
I added the endorsement clause as used by Google for the Go sources the
LICENSE file.
### 2015-05-22
The package lzb contains now the basic implementation for creating or
reading LZMA byte streams. It allows the support for the implementation
of the DAG-shortest-path algorithm for the compression function.
### 2015-04-23
Completed yesterday the lzbase classes. I'm a little bit concerned that
using the components may require too much code, but on the other hand
there is a lot of flexibility.
### 2015-04-22
Implemented Reader and Writer during the Bayern game against Porto. The
second half gave me enough time.
### 2015-04-21
While showering today morning I discovered that the design for OpEncoder
and OpDecoder doesn't work, because encoding/decoding might depend on
the current status of the dictionary. This is not exactly the right way
to start the day.
Therefore we need to keep the Reader and Writer design. This time around
we simplify it by ignoring size limits. These can be added by wrappers
around the Reader and Writer interfaces. The Parameters type isn't
needed anymore.
However I will implement a ReaderState and WriterState type to use
static typing to ensure the right State object is combined with the
right lzbase.Reader and lzbase.Writer.
As a start I have implemented ReaderState and WriterState to ensure
that the state for reading is only used by readers and WriterState only
used by Writers.
### 2015-04-20
Today I implemented the OpDecoder and tested OpEncoder and OpDecoder.
### 2015-04-08
Came up with a new simplified design for lzbase. I implemented already
the type State that replaces OpCodec.
### 2015-04-06
The new lzma package is now fully usable and lzmago is using it now. The
old lzma package has been completely removed.
### 2015-04-05
Implemented lzma.Reader and tested it.
### 2015-04-04
Implemented baseReader by adapting code form lzma.Reader.
### 2015-04-03
The opCodec has been copied yesterday to lzma2. opCodec has a high
number of dependencies on other files in lzma2. Therefore I had to copy
almost all files from lzma.
### 2015-03-31
Removed only a TODO item.
However in Francesco Campoy's presentation "Go for Javaneros
(Javaïstes?)" is the the idea that using an embedded field E, all the
methods of E will be defined on T. If E is an interface T satisfies E.
https://talks.golang.org/2014/go4java.slide#51
I have never used this, but it seems to be a cool idea.
### 2015-03-30
Finished the type writerDict and wrote a simple test.
### 2015-03-25
I started to implement the writerDict.
### 2015-03-24
After thinking long about the LZMA2 code and several false starts, I
have now a plan to create a self-sufficient lzma2 package that supports
the classic LZMA format as well as LZMA2. The core idea is to support a
baseReader and baseWriter type that support the basic LZMA stream
without any headers. Both types must support the reuse of dictionaries
and the opCodec.
### 2015-01-10
1. Implemented simple lzmago tool
2. Tested tool against large 4.4G file
- compression worked correctly; tested decompression with lzma
- decompression hits a full buffer condition
3. Fixed a bug in the compressor and wrote a test for it
4. Executed full cycle for 4.4 GB file; performance can be improved ;-)
### 2015-01-11
- Release v0.2 because of the working LZMA encoder and decoder

View File

@@ -1,33 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xz
import (
"bytes"
"testing"
)
func TestUvarint(t *testing.T) {
tests := []uint64{0, 0x80, 0x100, 0xffffffff, 0x100000000, 1<<64 - 1}
p := make([]byte, 10)
for _, u := range tests {
p = p[:10]
n := putUvarint(p, u)
if n < 1 {
t.Fatalf("putUvarint returned %d", n)
}
r := bytes.NewReader(p[:n])
x, m, err := readUvarint(r)
if err != nil {
t.Fatalf("readUvarint returned %s", err)
}
if m != n {
t.Fatalf("readUvarint read %d bytes; want %d", m, n)
}
if x != u {
t.Fatalf("readUvarint returned 0x%x; want 0x%x", x, u)
}
}
}

View File

@@ -1,514 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. 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 (
"bufio"
"errors"
"fmt"
"io"
"os"
"os/signal"
"path/filepath"
"strings"
"syscall"
"github.com/ulikunitz/xz"
"github.com/ulikunitz/xz/internal/xlog"
"github.com/ulikunitz/xz/lzma"
)
// signalHandler establishes the signal handler for SIGTERM(1) and
// handles it in its own go routine. The returned quit channel must be
// closed to terminate the signal handler go routine.
func signalHandler(w *writer) chan<- struct{} {
quit := make(chan struct{})
sigch := make(chan os.Signal, 1)
signal.Notify(sigch, os.Interrupt, syscall.SIGPIPE)
go func() {
select {
case <-quit:
signal.Stop(sigch)
return
case <-sigch:
w.removeTmpFile()
os.Exit(7)
}
}()
return quit
}
// format defines the newCompressor and newDecompressor functions for a
// compression format.
type format struct {
newCompressor func(w io.Writer, opts *options) (c io.WriteCloser,
err error)
newDecompressor func(r io.Reader, opts *options) (d io.Reader,
err error)
validHeader func(br *bufio.Reader) bool
}
// dictCapExps maps preset values to exponent for dictionary capacity
// sizes.
var lzmaDictCapExps = []uint{18, 20, 21, 22, 22, 23, 23, 24, 25, 26}
// formats contains the formats supported by gxz.
var formats = map[string]*format{
"lzma": &format{
newCompressor: func(w io.Writer, opts *options,
) (c io.WriteCloser, err error) {
lc := lzma.WriterConfig{
Properties: &lzma.Properties{LC: 3, LP: 0,
PB: 2},
DictCap: 1 << lzmaDictCapExps[opts.preset],
}
return lc.NewWriter(w)
},
newDecompressor: func(r io.Reader, opts *options,
) (d io.Reader, err error) {
lc := lzma.ReaderConfig{
DictCap: 1 << lzmaDictCapExps[opts.preset],
}
return lc.NewReader(r)
},
validHeader: func(br *bufio.Reader) bool {
h, err := br.Peek(lzma.HeaderLen)
if err != nil {
return false
}
return lzma.ValidHeader(h)
},
},
"xz": &format{
newCompressor: func(w io.Writer, opts *options,
) (c io.WriteCloser, err error) {
cfg := xz.WriterConfig{
DictCap: 1 << lzmaDictCapExps[opts.preset],
}
return cfg.NewWriter(w)
},
newDecompressor: func(r io.Reader, opts *options,
) (d io.Reader, err error) {
cfg := xz.ReaderConfig{
DictCap: 1 << lzmaDictCapExps[opts.preset],
}
return cfg.NewReader(r)
},
validHeader: func(br *bufio.Reader) bool {
h, err := br.Peek(xz.HeaderLen)
if err != nil {
return false
}
return xz.ValidHeader(h)
},
},
}
var errBase = errors.New("name has no base part")
// targetName finds the correct target name taking the options into
// account.
func targetName(path string, opts *options) (target string, err error) {
if path == "-" {
panic("path name - not supported")
}
if len(path) == 0 {
return "", errors.New("empty file name not supported")
}
ext := "." + opts.format
tarExt := ".txz"
if opts.format == "lzma" {
tarExt = ".tlz"
}
if !opts.decompress {
if strings.HasSuffix(path, ext) {
return "", fmt.Errorf(
"%s: file has already %s suffix", path, ext)
}
if strings.HasSuffix(path, tarExt) {
return "", fmt.Errorf(
"%s: file has already %s suffix", path, tarExt)
}
return path + ext, nil
}
if strings.HasSuffix(path, ext) {
target = path[:len(path)-len(ext)]
if filepath.Base(target) == "" {
return "", &userPathError{path, errBase}
}
return target, nil
}
if strings.HasSuffix(path, tarExt) {
target = path[:len(path)-len(tarExt)]
if filepath.Base(target) == "" {
return "", &userPathError{path, errBase}
}
return target + ".tar", nil
}
return path, nil
}
// tmpName converts the path string into a temporary name by appending
// .decompress or .compress to the file path.
func tmpName(path string, decompress bool) string {
var ext string
if decompress {
ext = ".decompress"
} else {
ext = ".compress"
}
return path + ext
}
// writer is used as file writer for decompression and file compressor
// for compression.
type writer struct {
f *os.File
name string
bw *bufio.Writer
io.Writer
cmp io.WriteCloser
success bool
}
// writerFormat select the writer format.
func writerFormat(opts *options) (f *format, err error) {
var ok bool
if f, ok = formats[opts.format]; !ok {
return nil, fmt.Errorf("compression format %q not supported",
opts.format)
}
return f, nil
}
// newCompressor creates a compressor for the given writer.
func newCompressor(w io.Writer, opts *options) (cmp io.WriteCloser, err error) {
if opts.decompress {
panic("no compressor needed")
}
f, err := writerFormat(opts)
if err != nil {
return nil, err
}
if cmp, err = f.newCompressor(w, opts); err != nil {
return nil, err
}
return cmp, nil
}
// newWriter creates a new file writer. Note that options must contain
// the actual compression format supported and not just auto.
func newWriter(path string, perm os.FileMode, opts *options,
) (w *writer, err error) {
w = &writer{name: path}
if opts.stdout {
w.f = os.Stdout
w.name = "-"
} else {
name, err := targetName(path, opts)
if err != nil {
return nil, err
}
if _, err = os.Stat(name); !os.IsNotExist(err) {
if !opts.force {
return nil, &userPathError{
Path: name,
Err: errors.New("file exists")}
}
}
tmp := tmpName(name, opts.decompress)
if w.f, err = os.OpenFile(tmp,
os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm); err != nil {
return nil, err
}
w.name = name
}
w.bw = bufio.NewWriter(w.f)
if opts.decompress {
w.Writer = w.bw
return w, nil
}
w.cmp, err = newCompressor(w.bw, opts)
if err != nil {
return nil, &userPathError{w.name, err}
}
w.Writer = w.cmp
return w, nil
}
// isStdout checks whether the parameter refers to stdout.
func isStdout(f *os.File) bool {
return f.Fd() == uintptr(syscall.Stdout)
}
var errInval = errors.New("invalid value")
// Close closes the writer. Note that the behavior depends whether
// success has been set for the writer.
func (w *writer) Close() error {
var err error
if w.f == nil {
return errInval
}
defer func() { w.f = nil }()
if !w.success {
if isStdout(w.f) {
return nil
}
if err = w.f.Close(); err != nil {
return err
}
if err = os.Remove(w.f.Name()); err != nil {
return err
}
return nil
}
if w.cmp != nil {
if err = w.cmp.Close(); err != nil {
return err
}
}
if err = w.bw.Flush(); err != nil {
return err
}
if isStdout(w.f) {
return nil
}
if err = w.f.Close(); err != nil {
return err
}
if err = os.Rename(w.f.Name(), w.name); err != nil {
return err
}
return nil
}
// removeTmpFile removes the temporary file for the writer. It is used
// by the signal handler goroutine.
func (w *writer) removeTmpFile() {
os.Remove(w.f.Name())
}
// SetSuccess sets the success variable to true.
func (w *writer) SetSuccess() { w.success = true }
// reader is used as a file reader.
type reader struct {
f *os.File
io.Reader
success bool
keep bool
}
// errNoRegular indicates that a file is not regular.
var errNoRegular = errors.New("no regular file")
// specialBits contain the special bits, which are not supported by gxz.
const specialBits = os.ModeSetuid | os.ModeSetgid | os.ModeSticky
// openFile opens the given path with the given options.
func openFile(path string, opts *options) (f *os.File, err error) {
if path == "-" {
return os.Stdin, nil
}
fi, err := os.Lstat(path)
if err != nil {
return nil, err
}
fm := fi.Mode()
if !fm.IsRegular() {
if !opts.force || fm&os.ModeSymlink == 0 {
return nil, &userPathError{Path: path,
Err: errNoRegular}
}
}
if f, err = os.Open(path); err != nil {
return nil, err
}
if fi, err = f.Stat(); err != nil {
return nil, err
}
fm = fi.Mode()
if !fm.IsRegular() {
return nil, &userPathError{Path: path, Err: errNoRegular}
}
if fm&specialBits != 0 && !opts.force {
return nil, &userPathError{Path: path,
Err: errors.New("setuid, setgid and/or sticky bit set")}
}
return f, nil
}
var errInvalidFormat = errors.New("file format not recognized")
// readerFormat tries to determine the type of a file. Currently it
// checks for the XZ header magic and if it is not present assumes that
// the file has been encoded by LZMA. The format field in options is
// updated.
func readerFormat(br *bufio.Reader, opts *options) (f *format, err error) {
var ok bool
if f, ok = formats[opts.format]; ok {
if !f.validHeader(br) {
return nil, errInvalidFormat
}
return f, nil
}
if opts.format != "auto" {
return nil, fmt.Errorf("compression format %s not supported",
opts.format)
}
for format, f := range formats {
if f.validHeader(br) {
opts.format = format
return f, nil
}
}
return nil, errInvalidFormat
}
// newDecompressor creates a new decompressor.
func newDecompressor(br *bufio.Reader, opts *options) (dec io.Reader,
err error) {
if !opts.decompress {
panic("no decompressor needed")
}
f, err := readerFormat(br, opts)
if err != nil {
return nil, err
}
if dec, err = f.newDecompressor(br, opts); err != nil {
return nil, err
}
return dec, nil
}
// newReader creates a new reader for files.
func newReader(path string, opts *options) (r *reader, err error) {
f, err := openFile(path, opts)
if err != nil {
return nil, err
}
br := bufio.NewReader(f)
if !opts.decompress {
r = &reader{f: f, Reader: br, keep: opts.keep || opts.stdout}
return r, nil
}
dec, err := newDecompressor(br, opts)
if err != nil {
return nil, &userPathError{path, err}
}
r = &reader{f: f, Reader: dec, keep: opts.keep || opts.stdout}
return r, nil
}
// isStdin checks whether the given file reference is stdin.
func isStdin(f *os.File) bool {
return f.Fd() == uintptr(syscall.Stdin)
}
// Close closes the reader. The behavior can be influences by the
// success attribute of reader.
func (r *reader) Close() error {
if r.f == nil {
return errInval
}
defer func() { r.f = nil }()
if isStdin(r.f) {
return nil
}
if err := r.f.Close(); err != nil {
return err
}
if r.keep || !r.success {
return nil
}
if err := os.Remove(r.f.Name()); err != nil {
return err
}
return nil
}
func (r *reader) SetSuccess() { r.success = true }
func (r *reader) Perm() os.FileMode {
const defaultPerm os.FileMode = 0666
fi, err := r.f.Stat()
if err != nil {
return defaultPerm
}
return fi.Mode() & defaultPerm
}
// userPathError represents a path error presentable to a user. In
// difference to os.PathError it removes the information of the
// operation returning the error.
type userPathError struct {
Path string
Err error
}
// Error provides the error string for the path error.
func (e *userPathError) Error() string {
return e.Path + ": " + e.Err.Error()
}
// userError converts path error to an error message that is
// acceptable for gxz users. PathError provides information about the
// command that has created an error. For instance Lstat informs that
// lstat detected that a file didn't exist this information is not
// relevant for users of the gxz program. This function converts a
// path error into a generic error removing the operation information.
func userError(err error) error {
pe, ok := err.(*os.PathError)
if !ok {
return err
}
return &userPathError{Path: pe.Path, Err: pe.Err}
}
func printErr(err error) {
if err != nil {
xlog.Warn(userError(err))
}
}
// processFile process the file with the given path applying the
// provided options.
func processFile(path string, opts *options) (err error) {
r, err := newReader(path, opts)
if err != nil {
printErr(err)
return
}
defer r.Close()
w, err := newWriter(path, r.Perm(), opts)
if err != nil {
printErr(err)
return
}
defer w.Close()
quitSignalHandler := signalHandler(w)
if _, err = io.Copy(w, r); err != nil {
close(quitSignalHandler)
printErr(err)
return err
}
close(quitSignalHandler)
w.SetSuccess()
if err = w.Close(); err != nil {
printErr(err)
return err
}
r.SetSuccess()
if err = r.Close(); err != nil {
printErr(err)
return err
}
return nil
}

View File

@@ -1,57 +0,0 @@
package main
const goLicense = `Copyright (c) 2009 The Go Authors. 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 Google Inc. 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
OWNER 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.
`
const xzLicense = `Copyright (c) 2014-2017 Ulrich Kunitz
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.
* My name, Ulrich Kunitz, may not 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.
`

View File

@@ -1,240 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Command gxz supports the compression and decompression of LZMA files.
//
// Use gxz -h to get information about supported flags.
package main
//go:generate xb cat -o licenses.go xzLicense:github.com/ulikunitz/xz/LICENSE goLicense:~/go/LICENSE
//go:generate xb version-file -o version.go
import (
"fmt"
"io"
"os"
"path/filepath"
"runtime/pprof"
"strings"
"text/template"
"github.com/ulikunitz/xz/internal/gflag"
"github.com/ulikunitz/xz/internal/term"
"github.com/ulikunitz/xz/internal/xlog"
)
const (
usageStr = `Usage: gxz [OPTION]... [FILE]...
Compress or uncompress FILEs in the .lzma format (by default, compress FILES
in place).
-c, --stdout write to standard output and don't delete input files
-d, --decompress force decompression
-f, --force force overwrite of output file and compress links
-F, --format <format>
Specify the file format to compress or decompress.
auto Default format for compression is xz. For decompression
the file content is used to identify the format.
xz The xz file format.
lzma, alone Compress to the .lzma file format.
-h, --help give this help
-k, --keep keep (don't delete) input files
-L, --license display software license
-q, --quiet suppress all warnings
-v, --verbose verbose mode
-V, --version display version string
-z, --compress force compression
-0 ... -9 compression preset; default is 6
--cpuprofile <file>
create a cpuprofile that can be used with go tool pprof
With no file, or when FILE is -, read standard input.
Report bugs using <https://github.com/ulikunitz/xz/issues>.
`
)
func usage(w io.Writer) {
fmt.Fprint(w, usageStr)
}
func licenses(w io.Writer) {
out := `
github.com/ulikunitz/xz -- xz for Go
====================================
{{.xz}}
Go Programming Language
=======================
The gxz program contains the packages gflag and xlog that are
extensions of packages from the Go standard library. The packages may
contain code from those packages.
{{.go}}
`
out = strings.TrimLeft(out, " \n")
tmpl, err := template.New("licenses").Parse(out)
if err != nil {
xlog.Panicf("error %s parsing licenses template", err)
}
lmap := map[string]string{
"xz": strings.TrimSpace(xzLicense),
"go": strings.TrimSpace(goLicense),
}
if err = tmpl.Execute(w, lmap); err != nil {
xlog.Fatalf("error %s writing licenses template", err)
}
}
type options struct {
help bool
stdout bool
decompress bool
force bool
format string
keep bool
license bool
version bool
quiet int
verbose int
preset int
cpuprofile string
}
func (o *options) Init() {
if o.preset != 0 {
xlog.Panicf("options are already initialized")
}
gflag.BoolVarP(&o.help, "help", "h", false, "")
gflag.BoolVarP(&o.stdout, "stdout", "c", false, "")
gflag.BoolVarP(&o.decompress, "decompress", "d", false, "")
gflag.BoolVarP(&o.force, "force", "f", false, "")
gflag.StringVarP(&o.format, "format", "F", "auto", "")
gflag.BoolVarP(&o.keep, "keep", "k", false, "")
gflag.BoolVarP(&o.license, "license", "L", false, "")
gflag.BoolVarP(&o.version, "version", "V", false, "")
gflag.CounterVarP(&o.quiet, "quiet", "q", 0, "")
gflag.CounterVarP(&o.verbose, "verbose", "v", 0, "")
gflag.PresetVar(&o.preset, 0, 9, 6, "")
gflag.StringVarP(&o.cpuprofile, "cpuprofile", "", "", "")
}
// normalizeFormat normalizes the format field of options. If the
// function completes without error the format field will be "xz",
// "lzma" or "auto". The latter only if the option decompress is true.
func normalizeFormat(o *options) error {
switch o.format {
case "xz", "lzma":
case "auto":
if !o.decompress {
o.format = "xz"
}
case "alone":
o.format = "lzma"
default:
return fmt.Errorf("format %q unsupported", o.format)
}
return nil
}
func main() {
// setup logger
cmdName := filepath.Base(os.Args[0])
xlog.SetPrefix(fmt.Sprintf("%s: ", cmdName))
xlog.SetFlags(0)
// initialize flags
gflag.CommandLine = gflag.NewFlagSet(cmdName, gflag.ExitOnError)
gflag.Usage = func() { usage(os.Stderr); os.Exit(1) }
opts := options{}
opts.Init()
switch cmdName {
case "lzma", "glzma":
opts.format = "lzma"
case "lzcat", "glzcat":
opts.format = "lzma"
fallthrough
case "xzcat", "gxzcat":
opts.stdout = true
opts.decompress = true
case "unlzma", "unglzma":
opts.format = "lzma"
fallthrough
case "unxz", "ungxz":
opts.decompress = true
}
gflag.Parse()
if opts.help {
usage(os.Stdout)
os.Exit(0)
}
if opts.license {
licenses(os.Stdout)
os.Exit(0)
}
if opts.version {
xlog.Printf("version %s\n", version)
os.Exit(0)
}
flags := xlog.Flags()
switch {
case opts.verbose <= 0:
flags |= xlog.Lnoprint | xlog.Lnodebug
case opts.verbose == 1:
flags |= xlog.Lnodebug
}
switch {
case opts.quiet >= 2:
flags |= xlog.Lnoprint | xlog.Lnowarn | xlog.Lnodebug
flags |= xlog.Lnopanic | xlog.Lnofatal
case opts.quiet == 1:
flags |= xlog.Lnoprint | xlog.Lnowarn | xlog.Lnodebug
}
xlog.SetFlags(flags)
if opts.cpuprofile != "" {
f, err := os.Create(opts.cpuprofile)
if err != nil {
xlog.Fatal(err)
}
if err = pprof.StartCPUProfile(f); err != nil {
xlog.Fatal(err)
}
}
if err := normalizeFormat(&opts); err != nil {
pprof.StopCPUProfile()
xlog.Fatal(err)
}
var args []string
if gflag.NArg() == 0 {
opts.stdout = true
args = []string{"-"}
} else {
args = gflag.Args()
}
if opts.stdout && !opts.decompress && !opts.force &&
term.IsTerminal(os.Stdout.Fd()) {
pprof.StopCPUProfile()
xlog.Fatal(`Compressed data will not be written to a terminal
Use -f to force compression. For help type gxz -h.`)
}
exit := 0
for _, arg := range args {
if err := processFile(arg, &opts); err != nil {
exit = 1
}
}
pprof.StopCPUProfile()
os.Exit(exit)
}

View File

@@ -1,3 +0,0 @@
package main
const version = "0.5.4"

View File

@@ -1,191 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. 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 (
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
"text/template"
)
const catUsageString = `xb cat [options] <id>:<path>...
This xb command puts the contents of the files given as relative paths to
the GOPATH variable as string constants into a go file.
-h prints this message and exits
-p package name (default main)
-o file name of output
`
func catUsage(w io.Writer) {
fmt.Fprint(w, catUsageString)
}
type gopath struct {
p []string
i int
}
func newGopath() *gopath {
p := strings.Split(os.Getenv("GOPATH"), ":")
return &gopath{p: p}
}
type cpair struct {
id string
path string
}
func (p cpair) Read() (s string, err error) {
var r io.ReadCloser
if p.path == "-" {
r = os.Stdin
} else {
if r, err = os.Open(p.path); err != nil {
return
}
}
defer func() {
err = r.Close()
}()
b, err := ioutil.ReadAll(r)
if err != nil {
return
}
s = string(b)
return
}
func verifyPath(path string) error {
fi, err := os.Stat(path)
if err != nil {
return err
}
if !fi.Mode().IsRegular() {
return fmt.Errorf("%s is not a regular file", path)
}
return nil
}
func (gp *gopath) find(arg string) (p cpair, err error) {
t := strings.SplitN(arg, ":", 2)
switch len(t) {
case 0:
err = fmt.Errorf("empty argument not supported")
return
case 1:
gp.i++
p = cpair{fmt.Sprintf("gocat%d", gp.i), t[0]}
case 2:
p = cpair{t[0], t[1]}
}
if p.path == "-" {
return
}
// substitute first ~ by $HOME
p.path = strings.Replace(p.path, "~", os.Getenv("HOME"), 1)
paths := make([]string, 0, len(gp.p)+1)
if filepath.IsAbs(p.path) {
paths = append(paths, filepath.Clean(p.path))
} else {
for _, q := range gp.p {
u := filepath.Join(q, "src", p.path)
paths = append(paths, filepath.Clean(u))
}
u := filepath.Join(".", p.path)
paths = append(paths, filepath.Clean(u))
}
for _, u := range paths {
if err = verifyPath(u); err != nil {
if os.IsNotExist(err) {
continue
}
return
}
p.path = u
return
}
err = fmt.Errorf("file %s not found", p.path)
return
}
// Gofile is used with the template gofileTmpl.
type Gofile struct {
Pkg string
Cmap map[string]string
}
var gofileTmpl = `package {{.Pkg}}
{{range $k, $v := .Cmap}}const {{$k}} = ` + "`{{$v}}`\n{{end}}"
func cat() {
var err error
cmdName := filepath.Base(os.Args[0])
log.SetPrefix(fmt.Sprintf("%s: ", cmdName))
log.SetFlags(0)
flag.CommandLine = flag.NewFlagSet(cmdName, flag.ExitOnError)
flag.Usage = func() { catUsage(os.Stderr); os.Exit(1) }
help := flag.Bool("h", false, "")
pkg := flag.String("p", "main", "")
out := flag.String("o", "", "")
flag.Parse()
if *help {
catUsage(os.Stdout)
os.Exit(0)
}
if *pkg == "" {
log.Fatal("option -p must not be empty")
}
w := os.Stdout
if *out != "" {
if w, err = os.Create(*out); err != nil {
log.Fatal(err)
}
}
gp := newGopath()
gofile := Gofile{
Pkg: *pkg,
Cmap: make(map[string]string, len(flag.Args())),
}
for _, arg := range flag.Args() {
p, err := gp.find(arg)
if err != nil {
log.Print(err)
continue
}
s, err := p.Read()
if err != nil {
log.Print(err)
continue
}
gofile.Cmap[p.id] = s
}
tmpl, err := template.New("gofile").Parse(gofileTmpl)
if err != nil {
log.Panicf("goFileTmpl error %s", err)
}
if err = tmpl.Execute(w, gofile); err != nil {
log.Fatal(err)
}
os.Exit(0)
}

View File

@@ -1,158 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. 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 (
"bufio"
"bytes"
"flag"
"fmt"
"io"
"log"
"os"
"path/filepath"
"strings"
)
const crUsageString = `xb copyright [options] <path>....
The xb copyright command adds a copyright remark to all go files below path.
-h prints this message and exits
`
func crUsage(w io.Writer) {
fmt.Fprint(w, crUsageString)
}
const copyrightText = `
Copyright 2014-2017 Ulrich Kunitz. All rights reserved.
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file.
`
func goComment(text string) string {
buf := new(bytes.Buffer)
scanner := bufio.NewScanner(strings.NewReader(text))
var err error
for scanner.Scan() {
s := strings.TrimSpace(scanner.Text())
if len(s) == 0 {
continue
}
if _, err = fmt.Fprintln(buf, "//", s); err != nil {
panic(err)
}
}
if err = scanner.Err(); err != nil {
panic(err)
}
if _, err = fmt.Fprintln(buf); err != nil {
panic(err)
}
return buf.String()
}
var goCopyright = goComment(copyrightText)
func addCopyright(path string) (err error) {
log.Printf("adding copyright to %s", path)
src, err := os.Open(path)
if err != nil {
return err
}
defer func() {
cerr := src.Close()
if cerr != nil && err == nil {
err = cerr
}
}()
newPath := path + ".new"
dst, err := os.Create(newPath)
if err != nil {
return err
}
defer func() {
cerr := dst.Close()
if cerr != nil && err == nil {
err = cerr
}
}()
out := bufio.NewWriter(dst)
fmt.Fprint(out, goCopyright)
scanner := bufio.NewScanner(src)
line := 0
del := false
for scanner.Scan() {
line++
txt := scanner.Text()
if line == 1 && strings.Contains(txt, "Copyright") {
del = true
continue
}
if del {
s := strings.TrimSpace(txt)
if len(s) == 0 {
del = false
}
continue
}
fmt.Fprintln(out, txt)
}
if err = scanner.Err(); err != nil {
return err
}
if err = out.Flush(); err != nil {
return
}
err = os.Rename(newPath, path)
return
}
func walkCopyrights(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
if !strings.HasSuffix(info.Name(), ".go") {
return nil
}
return addCopyright(path)
}
func copyright() {
cmdName := os.Args[0]
log.SetPrefix(fmt.Sprintf("%s: ", cmdName))
log.SetFlags(0)
flag.CommandLine = flag.NewFlagSet(cmdName, flag.ExitOnError)
flag.Usage = func() { crUsage(os.Stderr); os.Exit(1) }
help := flag.Bool("h", false, "")
flag.Parse()
if *help {
crUsage(os.Stdout)
os.Exit(0)
}
for _, path := range flag.Args() {
fi, err := os.Stat(path)
if err != nil {
log.Print(err)
continue
}
if !fi.IsDir() {
log.Printf("%s is not a directory", path)
continue
}
if err = filepath.Walk(path, walkCopyrights); err != nil {
log.Fatalf("%s error %s", path, err)
}
}
}

View File

@@ -1,67 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Command xb supports the xz for Go project builds.
//
// Use xb help to get information about the supported commands.
package main
//go:generate xb version-file -o version.go
import (
"fmt"
"log"
"os"
)
const usage = `xb <command>
xb is a supporting building tool from the xz project for Go.
xb help -- prints this message
xb version-file -- generates go file with version information
xb cat -- generates go file that includes the given text files
xb copyright -- adds copyright statements to relevant files
xb version -- prints version information for xb
Report bugs using <https://github.com/ulikunitz/xz/issues>.
`
func updateArgs(cmd string) {
args := make([]string, 1, len(os.Args)-1)
args[0] = "xb " + cmd
os.Args = append(args, os.Args[2:]...)
}
func main() {
log.SetPrefix("xb: ")
log.SetFlags(0)
if len(os.Args) < 2 {
log.Fatal("to show help, use xb help")
}
switch os.Args[1] {
case "help", "-h":
fmt.Print(usage)
os.Exit(0)
case "version":
fmt.Printf("xb %s\n", version)
os.Exit(0)
case "cat":
updateArgs("cat")
cat()
os.Exit(0)
case "version-file":
updateArgs("version-file")
versionFile()
os.Exit(0)
case "copyright":
updateArgs("copyright")
copyright()
os.Exit(0)
default:
log.Fatalf("command %q not supported", os.Args[1])
}
}

View File

@@ -1,85 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. 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 (
"flag"
"fmt"
"io"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"text/template"
)
const vfUsage = `xb version-file [options] <id>:<path>...
The command creates go file with a version constant. The version string
contains the contents of the VERSION environment variable or the output
of git describe.
-h prints this message and exits
-p package name (default main)
-o file name of output
`
func versionFileUsage(w io.Writer) {
fmt.Fprint(w, vfUsage)
}
func versionFile() {
cmdName := filepath.Base(os.Args[0])
log.SetPrefix(fmt.Sprintf("%s: ", cmdName))
log.SetFlags(0)
flag.CommandLine = flag.NewFlagSet(cmdName, flag.ExitOnError)
flag.Usage = func() { versionFileUsage(os.Stderr); os.Exit(1) }
help := flag.Bool("h", false, "")
pkg := flag.String("p", "main", "")
out := flag.String("o", "", "")
flag.Parse()
if *help {
versionFileUsage(os.Stdout)
os.Exit(0)
}
if *pkg == "" {
log.Fatal("option -p must not be empty")
}
var err error
w := os.Stdout
if *out != "" {
if w, err = os.Create(*out); err != nil {
log.Fatal(err)
}
}
// get the version string
version := os.Getenv("VERSION")
if version == "" {
b, err := exec.Command("git", "describe").Output()
if err != nil {
log.Fatalf("error %s while executing git describe", err)
}
version = string(b)
}
version = strings.TrimSpace(version)
versionTmpl := `package main
const version = "{{.}}"
`
tmpl := template.Must(template.New("version").Parse(versionTmpl))
if err = tmpl.Execute(w, version); err != nil {
log.Fatal(err)
}
}

View File

@@ -1,3 +0,0 @@
package main
const version = "0.5.4"

View File

@@ -1,2 +0,0 @@
# .gitignore
LZMA2.html

View File

@@ -1,91 +0,0 @@
% LZMA2 format
The LZMA2 format supports flushing, parallel encoding or decoding.
Chunks of data that cannot be compressed are copied as such.
## Dictionary Size
LZMA2 requires information about the size of the dictionary. This is
provided by a single byte.
Bits | Mask | Description
----:|-----:|:------------------------------------------------
0-5 | 0x3F | Dictionary Size
6-7 | 0xC0 | Reserved for future use; Must be zero
The dictionary size is encoded with a one-bit mantissa and five-bit
exponent. The smallest dictionary size is 4 KiB and the biggest is 4 GiB
- 1 B.
|Raw Value | Mantissa | Exponent | Dictionary size|
|---------:|---------:|---------:|---------------:|
| 0 | 2 | 11 | 4 KiB |
| 1 | 3 | 11 | 6 KiB |
| 2 | 2 | 12 | 8 KiB |
| 3 | 3 | 12 | 12 KiB |
| ... | ... | ... | ... |
| 36 | 2 | 29 | 1024 MiB |
| 37 | 3 | 29 | 1536 MiB |
| 38 | 2 | 30 | 2048 MiB |
| 39 | 3 | 30 | 3072 MiB |
| 40 | 2 | 31 | 4096 MiB - 1B |
For test purposes we add the dictionary size byte as first byte of an
LZMA2 stream.
## Chunks
An LZMA2 stream is a sequence of chunks. Each chunk is preceded by a
control byte and other information.
Following the C implementation in the LZMA SDK the control byte can be
described as such:
Chunk header | Description
:------------------- | :--------------------------------------------------
`00000000` | End of LZMA2 stream
`00000001 U U` | Uncompressed chunk, reset dictionary
`00000010 U U` | Uncompressed chunk, no reset of dictionary
`100uuuuu U U C C` | LZMA, no reset
`101uuuuu U U C C` | LZMA, reset state
`110uuuuu U U C C S` | LZMA, reset state, new properties
`111uuuuu U U C C S` | LZMA, reset state, new properties, reset dictionary
The symbols used are described by following table.
Symbol | Description
:----- | :--------------------
u | uncompressed size bit
U | uncompressed size byte
C | uncompressed size byte
S | properties byte
A dictionary reset requires always new properties. If this is an
uncompressed chunk the properties need to be provided in the next
compressed chunk. New properties require a reset of the state.
A dictionary reset puts the current position to zero. Uncompressed data
is written into the dictionary.
The uncompressed size and compressed size are given in big-endian byte order.
The values need to be incremented for the actual size. So a chunk with 1
byte uncompressed data will store size 0 in the uncompressed bits and bytes.
The properties byte provides the parameters pb, lc, lp using following
formula:
S = (pb * 5 + lp) * 9 + lc
This is same encoding used for LZMA. For LZMA2 following condition has
been introduced:
lc + lp <= 4.
The parameters are defined as follows:
Name | Range | Description
:---- | :----- | :------------------------------
lc | [0,8] | number of literal context bits
lp | [0,4] | number of literal pos bits
pb | [0,4] | the number of pos bits

View File

@@ -1,4 +0,0 @@
#!/bin/sh
set -x
pandoc -t html5 -f markdown -s --css=md.css -o LZMA2.html LZMA2.md

View File

@@ -1,20 +0,0 @@
/* md.css */
body {
font-family: "Verdana", sans-serif;
font-size: 10pt;
width: 40em;
background-color: #FFFAF0;
}
h1 { font-size: 18pt; }
h2 { font-size: 14pt; }
h3 { font-size: 12pt; }
h4 { font-size: 10pt; }
code { font-size: 10pt; }
.nobr { white-space: nowrap; }

View File

@@ -1,12 +0,0 @@
# Release Notes v0.3
This release provides an lzmago command that provides a complete set of
flags to decompress and compress .lzma files. It is interoperable with
the lzma tool from the xz package.
The release changed the lzma implementation to support later
optimizations of the compression algorithm as well as the plumbing
required to support the LZMA2 format.
The release provides the ground work to provide full support for the
full xz specification.

View File

@@ -1,4 +0,0 @@
# Release Notes v0.4.1
The release fixes issue #7 LZMA2 reader. There has been a bug in the
LZMA2 reader.

View File

@@ -1,12 +0,0 @@
# Release Notes v0.4
This release support the compression and decompression to xz files. Note
that only the LZMA filter is supported for the xz format, but this seems
to be the standard setup anyway.
The performance and compression ration is not good compared to the xz
tool written in C. But optimization has not been the target of this
release.
A gxz binary is included that supports the compression and decompression of
xz files.

View File

@@ -1,5 +0,0 @@
# Release Notes v0.5.1
The release fixes a problem with 32-bit integers on 32-bit platforms.
Many thanks to Bruno Bigras, who reported the issue.

View File

@@ -1,6 +0,0 @@
# Release Notes v0.5.2
The release fixes an issue decoding files that contain a block header
padding of 4 bytes.
Many thanks to Greg (@myfreeweb on github) for reporting this issue.

View File

@@ -1,5 +0,0 @@
# Release Notes v0.5.2
The realease fixes issue #12 related an XZ stream with no data.
Many thanks to Tomasz Kłak for reporting the issue.

View File

@@ -1,6 +0,0 @@
# Release Notes v0.5.4
The release fixes issue #15 related to an unexpeded padding size of 5.
The padding size test has now been removed.
Many thanks to Dórian C. Langbeck for reporting the issue.

View File

@@ -1,16 +0,0 @@
# Release Notes v0.5
This release supports multiple xz streams in xz files. The older release
couldn't support those files and there are files (linux kernel
tarballs) that couldn't be decompressed by the code.
The API has changed. Types ReaderConfig, WriterConfig, etc. are
introduced to provide parameters to the readers and writers in the
packages xz and lzma. The old API had multiple inconsistent mechanisms.
Making NewReader or NewWriter a method of the Config types provides more
clarity then the old NewReaderParams and NewWriterParams.
The compression ratio and performance has been improved. An experimental
Binary Tree Matcher has been added, but performance and compression
ratio is poor. It's is not recommended.

View File

@@ -1,55 +0,0 @@
# Issues in the XZ file format
During the development of the xz package for Go a number of issues with
the xz file format were observed. They are documented here to help a
later development of an improved format.
# xz file format
## Consistency
## General
Packets should either be constant size or should have encoded the size
in the header. File header and footer are constant size and the block
header has the size encoded. The index doesn't fulfill the criteria even
when its size is included in the footer.
## Index
The index doesn't have the size in the header. So in a stream you are
forced to read the whole index to identify its length.
The index should have made optional. This would require to remove the
index size from the footer and include its own footer in the index.
## Padding
The padding should allow direct mapping of the CRC values into memory, but it
wastes bytes bearing no information. This is certainly not optimal for a
compression format. It is argued alignment makes it faster to read and
write the checksum values, but the time spent there is much less than on
encoding and decoding itself.
## Filters for each block
Filters should have been defined in front of blocks. This way they
would not need to be repeated.
# LZMA2
## Consistent header byte.
LZMA2 consists of a series of chunks with a header byte. The header byte
has a different format depending on whether it is an uncompressed or
compressed chunk. This has the consequence a complete reset of state,
properties and dictionary is not possible with an uncompressed chunk.
The encoder has to keep a state variable tracking a dictionary reset in
an uncompressed chunk to ensure that the flags are added in the first
compressed chunk to follow. This complicates the implementation of the
encoder and decoder.
## Dictionary capacity is not encoded
LZMA2 doesn't encode the dictionary capacity, so LZMA2 doesn't work
standalone.

View File

@@ -1,142 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xz
import (
"bytes"
"testing"
)
func TestHeader(t *testing.T) {
h := header{flags: CRC32}
data, err := h.MarshalBinary()
if err != nil {
t.Fatalf("MarshalBinary error %s", err)
}
var g header
if err = g.UnmarshalBinary(data); err != nil {
t.Fatalf("UnmarshalBinary error %s", err)
}
if g != h {
t.Fatalf("unmarshalled %#v; want %#v", g, h)
}
}
func TestFooter(t *testing.T) {
f := footer{indexSize: 64, flags: CRC32}
data, err := f.MarshalBinary()
if err != nil {
t.Fatalf("MarshalBinary error %s", err)
}
var g footer
if err = g.UnmarshalBinary(data); err != nil {
t.Fatalf("UnmarshalBinary error %s", err)
}
if g != f {
t.Fatalf("unmarshalled %#v; want %#v", g, f)
}
}
func TestRecord(t *testing.T) {
r := record{1234567, 10000}
p, err := r.MarshalBinary()
if err != nil {
t.Fatalf("MarshalBinary error %s", err)
}
n := len(p)
buf := bytes.NewReader(p)
g, m, err := readRecord(buf)
if err != nil {
t.Fatalf("readFrom error %s", err)
}
if m != n {
t.Fatalf("read %d bytes; wrote %d", m, n)
}
if g.unpaddedSize != r.unpaddedSize {
t.Fatalf("got unpaddedSize %d; want %d", g.unpaddedSize,
r.unpaddedSize)
}
if g.uncompressedSize != r.uncompressedSize {
t.Fatalf("got uncompressedSize %d; want %d", g.uncompressedSize,
r.uncompressedSize)
}
}
func TestIndex(t *testing.T) {
records := []record{{1234, 1}, {2345, 2}}
var buf bytes.Buffer
n, err := writeIndex(&buf, records)
if err != nil {
t.Fatalf("writeIndex error %s", err)
}
if n != int64(buf.Len()) {
t.Fatalf("writeIndex returned %d; want %d", n, buf.Len())
}
// indicator
c, err := buf.ReadByte()
if err != nil {
t.Fatalf("buf.ReadByte error %s", err)
}
if c != 0 {
t.Fatalf("indicator %d; want %d", c, 0)
}
g, m, err := readIndexBody(&buf)
if err != nil {
for i, r := range g {
t.Logf("records[%d] %v", i, r)
}
t.Fatalf("readIndexBody error %s", err)
}
if m != n-1 {
t.Fatalf("readIndexBody returned %d; want %d", m, n-1)
}
for i, rec := range records {
if g[i] != rec {
t.Errorf("records[%d] is %v; want %v", i, g[i], rec)
}
}
}
func TestBlockHeader(t *testing.T) {
h := blockHeader{
compressedSize: 1234,
uncompressedSize: -1,
filters: []filter{&lzmaFilter{4096}},
}
data, err := h.MarshalBinary()
if err != nil {
t.Fatalf("MarshalBinary error %s", err)
}
r := bytes.NewReader(data)
g, n, err := readBlockHeader(r)
if err != nil {
t.Fatalf("readBlockHeader error %s", err)
}
if n != len(data) {
t.Fatalf("readBlockHeader returns %d bytes; want %d", n,
len(data))
}
if g.compressedSize != h.compressedSize {
t.Errorf("got compressedSize %d; want %d",
g.compressedSize, h.compressedSize)
}
if g.uncompressedSize != h.uncompressedSize {
t.Errorf("got uncompressedSize %d; want %d",
g.uncompressedSize, h.uncompressedSize)
}
if len(g.filters) != len(h.filters) {
t.Errorf("got len(filters) %d; want %d",
len(g.filters), len(h.filters))
}
glf := g.filters[0].(*lzmaFilter)
hlf := h.filters[0].(*lzmaFilter)
if glf.dictCap != hlf.dictCap {
t.Errorf("got dictCap %d; want %d", glf.dictCap, hlf.dictCap)
}
}

BIN
vendor/github.com/ulikunitz/xz/fox.xz generated vendored

Binary file not shown.

View File

@@ -1,953 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Package gflag implements GNU-style command line flag parsing. It
supports the transformation of programs using the Go standard library
flag package. However it doesn't target full compatibility with the Go
standard library flag package. The Flag structure doesn't support all
fields of the flag package and the Var method and function does have a
different signature.
The typical use case looks like this:
b := Bool("flag-b", "b", false, "boolean flag")
h := Bool("help", "h", false, "prints this message")
Parse()
if *h {
gflag.Usage()
}
*/
package gflag
import (
"bytes"
"fmt"
"io"
"os"
"sort"
"strconv"
"strings"
)
// CommandLine is the default set of command-line flags parsed from
// os.Args. The top-level functions such as BoolVar, Arg, etc. are
// wrappers for the methods of command line.
var CommandLine = NewFlagSet(os.Args[0], ExitOnError)
// ErrorHandling defines how flag parsing errors are handled.
type ErrorHandling int
// The constants define how errors should be handled.
const (
ContinueOnError ErrorHandling = iota
ExitOnError
PanicOnError
)
// HasArg defines whether a flag argument is required, optional or not
// supported.
type HasArg int
// The constants define whether a flag argument is required, not
// supported or optional.
const (
RequiredArg HasArg = iota
NoArg
OptionalArg
)
// Value is the interface to the value of a specific flag.
type Value interface {
Set(string) error
Update()
Get() interface{}
String() string
}
// Flag represents a single flag.
type Flag struct {
Name string
Shorthands string
HasArg HasArg
Value Value
}
// line provides a single line of usage information.
type line struct {
flags string
usage string
}
// lineFlags computes the flags string for a usage line.
func lineFlags(name, shorthands, defaultValue string) string {
buf := new(bytes.Buffer)
if shorthands != "" {
for i, r := range shorthands {
if i > 0 {
fmt.Fprint(buf, ", ")
}
fmt.Fprintf(buf, "-%c", r)
}
}
if name != "" {
if buf.Len() > 0 {
fmt.Fprintf(buf, ", ")
}
fmt.Fprint(buf, "--", name)
if defaultValue != "" {
fmt.Fprintf(buf, "=%s", defaultValue)
}
}
return buf.String()
}
// lines provides a set of usage lines.
type lines []line
// writeLines writes usage line to the writer.
func writeLines(w io.Writer, ls lines) (n int, err error) {
l := make(lines, len(ls))
copy(l, ls)
sort.Sort(l)
maxLenFlags := 0
for _, line := range l {
k := len(line.flags)
if k > maxLenFlags {
maxLenFlags = k
}
}
for _, line := range l {
format := fmt.Sprintf(" %%-%ds %%s\n", maxLenFlags)
var k int
k, err = fmt.Fprintf(w, format, line.flags, line.usage)
n += k
if err != nil {
return
}
}
return
}
func (l lines) Len() int { return len(l) }
func (l lines) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
func (l lines) Less(i, j int) bool { return l[i].flags < l[j].flags }
// FlagSet represents a set of option flags.
type FlagSet struct {
// Provides a custom usage function if set.
Usage func()
name string
parsed bool
actual map[string]*Flag
formal map[string]*Flag
lines lines
args []string
output io.Writer
errorHandling ErrorHandling
preset bool
}
// Init initializes a flag set variable.
func (f *FlagSet) Init(name string, errorHandling ErrorHandling) {
f.name = name
f.errorHandling = errorHandling
}
// NewFlagSet creates a new flag set.
func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet {
f := new(FlagSet)
f.Init(name, errorHandling)
return f
}
// Arg returns the argument number i after parsing has been successful.
func (f *FlagSet) Arg(i int) string {
if !(0 <= i && i < len(f.args)) {
return ""
}
return f.args[i]
}
// Arg provides the argument number i after parsing of the command line
// flags.
func Arg(i int) string {
return CommandLine.Arg(i)
}
// Args returns all arguments after parsing.
func (f *FlagSet) Args() []string { return f.args }
// Args returns all arguments after the command line flags have been
// parsed.
func Args() []string { return CommandLine.args }
// NArg returns the number of remaining arguments after parsing.
func (f *FlagSet) NArg() int { return len(f.args) }
// NArg returns the number of remaining arguments after command line
// parsing.
func NArg() int { return len(CommandLine.args) }
// Parsed returns whether the command line has already been parsed.
func Parsed() bool {
return CommandLine.parsed
}
// Parsed returns whether the flag set has already been parsed.
func (f *FlagSet) Parsed() bool {
return f.parsed
}
// Parse parses the command line.
func Parse() {
// errors are ignored because CommandLine is set on ExitOnError
CommandLine.Parse(os.Args[1:])
}
// lookupLongOption looks up a long option flag.
func (f *FlagSet) lookupLongOption(name string) (flag *Flag, err error) {
if len(name) < 2 {
f.panicf("%s is not a long option", name)
}
var ok bool
if flag, ok = f.formal[name]; !ok {
return nil, fmt.Errorf("long option %s is unsupported", name)
}
if flag.Name != name {
f.panicf("got %s flag; want %s flag", flag.Name, name)
}
return flag, nil
}
// lookupShortOption looks a short option up.
func (f *FlagSet) lookupShortOption(r rune) (flag *Flag, err error) {
var ok bool
name := string([]rune{r})
if flag, ok = f.formal[name]; !ok {
return nil, fmt.Errorf("short option %s is unsupported", name)
}
if !strings.ContainsRune(flag.Shorthands, r) {
f.panicf("flag supports shorthands %q; but doesn't contain %s",
flag.Shorthands, name)
}
return flag, nil
}
// processExtraFlagArg processes a flag with extra arguments not using
// the form --long-option=arg.
func (f *FlagSet) processExtraFlagArg(flag *Flag, i int) error {
if flag.HasArg == NoArg {
// no argument required
flag.Value.Update()
return nil
}
if i < len(f.args) {
arg := f.args[i]
if len(arg) == 0 || arg[0] != '-' {
err := flag.Value.Set(arg)
switch flag.HasArg {
case RequiredArg:
f.removeArg(i)
return err
case OptionalArg:
if err != nil {
flag.Value.Update()
return nil
}
f.removeArg(i)
return nil
}
}
}
// no argument
if flag.HasArg == RequiredArg {
return fmt.Errorf("no argument present")
}
// flag.HasArg == OptionalArg
flag.Value.Update()
return nil
}
// removeArg removes the arguments at position i from the args field of
// the flag set.
func (f *FlagSet) removeArg(i int) {
copy(f.args[i:], f.args[i+1:])
f.args = f.args[:len(f.args)-1]
}
// parseArg parses the argument i.
func (f *FlagSet) parseArg(i int) (next int, err error) {
arg := f.args[i]
if len(arg) < 2 || arg[0] != '-' {
return i + 1, nil
}
if arg[1] == '-' {
// argument starts with --
f.removeArg(i)
if len(arg) == 2 {
// argument is --; remove it and ignore all
// following arguments
return len(f.args), nil
}
arg = arg[2:]
flagArg := strings.SplitN(arg, "=", 2)
flag, err := f.lookupLongOption(flagArg[0])
if err != nil {
return i, err
}
// case 1: no equal sign
if len(flagArg) == 1 {
err = f.processExtraFlagArg(flag, i)
return i, err
}
// case 2: equal sign
if flag.HasArg == NoArg {
err = fmt.Errorf("option %s doesn't support argument",
arg)
} else {
err = flag.Value.Set(flagArg[1])
}
return i, err
}
// short options
f.removeArg(i)
arg = arg[1:]
for _, r := range arg {
flag, err := f.lookupShortOption(r)
if err != nil {
return i, err
}
if err = f.processExtraFlagArg(flag, i); err != nil {
return i, err
}
}
return i, nil
}
// defaultUsage provides the default usage information.
func defaultUsage(f *FlagSet) {
if f.name == "" {
fmt.Fprintf(f.out(), "Usage:\n")
} else {
fmt.Fprintf(f.out(), "Usage of %s:\n", f.name)
}
f.PrintDefaults()
}
// Usage prints the default usage message.
var Usage = func() {
fmt.Fprintf(CommandLine.out(), "Usage of %s:\n", os.Args[0])
PrintDefaults()
}
// usage provides the usage information for the flag set.
func (f *FlagSet) usage() {
if f.Usage == nil {
if f == CommandLine {
Usage()
} else {
defaultUsage(f)
}
} else {
f.Usage()
}
}
// Parse parses the arguments. If an error happens the error is printed
// as well as the usage information.
func (f *FlagSet) Parse(arguments []string) error {
f.parsed = true
f.args = arguments
for i := 0; i < len(f.args); {
var err error
i, err = f.parseArg(i)
if err == nil {
continue
}
fmt.Fprintf(f.out(), "%s: %s\n", f.name, err)
f.usage()
switch f.errorHandling {
case ContinueOnError:
return err
case ExitOnError:
os.Exit(2)
case PanicOnError:
panic(err)
}
}
return nil
}
// PrintDefaults prints information about all flags.
func (f *FlagSet) PrintDefaults() {
_, err := writeLines(f.out(), f.lines)
if err != nil {
f.panicf("writeLines error %s", err)
}
}
// PrintDefaults prints the information about all command line flags.
func PrintDefaults() {
CommandLine.PrintDefaults()
}
// out returns a writer. If the field output has not been set os.Stderr
// is returned.
func (f *FlagSet) out() io.Writer {
if f.output == nil {
return os.Stderr
}
return f.output
}
// SetOutput sets the default output writer for the flag set.
func (f *FlagSet) SetOutput(w io.Writer) {
f.output = w
}
// panicf prints a formatted error message and panics.
func (f *FlagSet) panicf(format string, values ...interface{}) {
var msg string
if f.name == "" {
msg = fmt.Sprintf(format, values...)
} else {
v := make([]interface{}, 1+len(values))
v[0] = f.name
copy(v[1:], values)
msg = fmt.Sprintf("%s "+format, v...)
}
fmt.Fprintln(f.out(), msg)
panic(msg)
}
// setFormal sets the flag with the given name to the flag parameter.
func (f *FlagSet) setFormal(name string, flag *Flag) {
if name == "" {
f.panicf("no support for empty name strings")
}
if _, alreadythere := f.formal[name]; alreadythere {
f.panicf("flag redefined: %s", flag.Name)
}
if f.formal == nil {
f.formal = make(map[string]*Flag)
}
f.formal[name] = flag
}
// VarP creates a flag with a long and shorthand options.
func (f *FlagSet) VarP(value Value, name, shorthands string, hasArg HasArg) {
flag := &Flag{
Name: name,
Shorthands: shorthands,
Value: value,
HasArg: hasArg,
}
if flag.Name == "" && flag.Shorthands == "" {
f.panicf("flag with no name or shorthands")
}
if len(flag.Name) == 1 {
f.panicf("flag has single character name %q; use shorthands",
flag.Name)
}
if flag.Name != "" {
f.setFormal(flag.Name, flag)
}
if flag.Shorthands != "" {
for _, r := range flag.Shorthands {
name := string([]rune{r})
f.setFormal(name, flag)
}
}
}
// VarP creates a flag for the given value for the command line.
func VarP(value Value, name, shorthands string, hasArg HasArg) {
CommandLine.VarP(value, name, shorthands, hasArg)
}
// Var creates a flag for the given option name.
func (f *FlagSet) Var(value Value, name string, hasArg HasArg) {
shorthands := ""
if len(name) == 1 {
shorthands = name
name = ""
}
f.VarP(value, name, shorthands, hasArg)
}
// Var creates a flag for the given option name for the command line.
func Var(value Value, name string, hasArg HasArg) {
CommandLine.Var(value, name, hasArg)
}
// addLine adds a usage line to the flag set.
func (f *FlagSet) addLine(l line) {
if l.flags == "" {
f.panicf("no flags for %q", l.usage)
}
f.lines = append(f.lines, l)
}
// boolValue represents a bool value in the flag.
type boolValue bool
// newBoolValue creates a new Bool Value.
func newBoolValue(val bool, p *bool) *boolValue {
*p = val
return (*boolValue)(p)
}
// Get returns the bool value as boolean.
func (b *boolValue) Get() interface{} {
return bool(*b)
}
// Set sets the bool value to the value provided by the string.
func (b *boolValue) Set(s string) error {
v, err := strconv.ParseBool(s)
*b = boolValue(v)
return err
}
// Update sets the bool value to true.
func (b *boolValue) Update() {
*b = true
}
// String returns the boll value as string.
func (b *boolValue) String() string {
return fmt.Sprintf("%t", *b)
}
// boolLine creates the usage line for a bool flag.
func boolLine(name, shorthands string, value bool, usage string) line {
defaultValue := ""
if value {
defaultValue = "true"
}
return line{lineFlags(name, shorthands, defaultValue), usage}
}
// BoolVarP defines a bool flag with specified name, shorthands, default
// value and usage string. The argument p points to a bool variable in
// which to store the value of the flag.
func (f *FlagSet) BoolVarP(p *bool, name, shorthands string, value bool, usage string) {
f.addLine(boolLine(name, shorthands, value, usage))
f.VarP(newBoolValue(value, p), name, shorthands, OptionalArg)
}
// BoolP defines a bool flag with specified name, shorthands, default
// value and usage string. The return value is the address of a bool
// variable that stores the value of the flag.
func (f *FlagSet) BoolP(name, shorthands string, value bool, usage string) *bool {
p := new(bool)
f.BoolVarP(p, name, shorthands, value, usage)
return p
}
// BoolP defines a bool flag with specified name, shorthands, default
// value and usage string. The return value is the address of a bool
// variable that stores the value of the flag.
func BoolP(name, shorthands string, value bool, usage string) *bool {
return CommandLine.BoolP(name, shorthands, value, usage)
}
// BoolVarP defines a bool flag with specified name, shorthands, default
// value and usage string. The argument p points to a bool variable in
// which to store the value of the flag.
func BoolVarP(p *bool, name, shorthands string, value bool, usage string) {
CommandLine.BoolVarP(p, name, shorthands, value, usage)
}
// BoolVar defines a bool flag with specified name, default value and
// usage string. The argument p points to a bool variable in which to
// store the value of the flag.
func (f *FlagSet) BoolVar(p *bool, name string, value bool, usage string) {
f.addLine(boolLine(name, "", value, usage))
f.Var(newBoolValue(value, p), name, OptionalArg)
}
// BoolVar defines a bool flag with specified name, default value and
// usage string. The argument p points to a bool variable in which to
// store the value of the flag.
func BoolVar(p *bool, name string, value bool, usage string) {
CommandLine.BoolVar(p, name, value, usage)
}
// Bool defines a bool flag with specified name, default value and
// usage string. The return value is the address of a bool variable that
// stores the value of the flag.
func (f *FlagSet) Bool(name string, value bool, usage string) *bool {
p := new(bool)
f.BoolVar(p, name, value, usage)
return p
}
// Bool defines a bool flag with specified name, default value and
// usage string. The return value is the address of a bool variable that
// stores the value of the flag.
func Bool(name string, value bool, usage string) *bool {
return CommandLine.Bool(name, value, usage)
}
// intValue stores an integer value.
type intValue int
// newIntValue allocates a new integer value and returns its pointer.
func newIntValue(val int, p *int) *intValue {
*p = val
return (*intValue)(p)
}
// Get returns the integer.
func (n *intValue) Get() interface{} {
return int(*n)
}
// Set sets the integer value.
func (n *intValue) Set(s string) error {
v, err := strconv.ParseInt(s, 0, 0)
if err != nil {
return err
}
*n = intValue(v)
return nil
}
// Update increments the integer value.
func (n *intValue) Update() {
(*n)++
}
// String represents the integer value as string.
func (n *intValue) String() string {
return fmt.Sprintf("%d", *n)
}
// counterLine returns the usage line for a counter flag.
func counterLine(name, shorthands, usage string) line {
return line{lineFlags(name, shorthands, ""), usage}
}
// CounterVarP defines a counter flag with specified name, shorthands, default
// value and usage string. The argument p points to an integer variable in
// which to store the value of the flag.
func (f *FlagSet) CounterVarP(p *int, name, shorthands string, value int, usage string) {
f.addLine(counterLine(name, shorthands, usage))
f.VarP(newIntValue(value, p), name, shorthands, OptionalArg)
}
// CounterVarP defines a counter flag with specified name, shorthands, default
// value and usage string. The argument p points to an integer variable in
// which to store the value of the flag.
func CounterVarP(p *int, name, shorthands string, value int, usage string) {
CommandLine.CounterVarP(p, name, shorthands, value, usage)
}
// CounterP defines a counter flag with specified name, shorthands, default
// value and usage string. The return value is the address of an integer
// variable that stores the value of the flag.
func (f *FlagSet) CounterP(name, shorthands string, value int, usage string) *int {
p := new(int)
f.CounterVarP(p, name, shorthands, value, usage)
return p
}
// CounterP defines a counter flag with specified name, shorthands, default
// value and usage string. The return value is the address of an integer
// variable that stores the value of the flag.
func CounterP(name, shorthands string, value int, usage string) *int {
return CommandLine.CounterP(name, shorthands, value, usage)
}
// CounterVar defines a counter flag with specified name, default value and
// usage string. The argument p points to an integer variable in which to
// store the value of the flag.
func (f *FlagSet) CounterVar(p *int, name string, value int, usage string) {
f.addLine(counterLine(name, "", usage))
f.Var(newIntValue(value, p), name, OptionalArg)
}
// CounterVar defines a counter flag with specified name, default value and
// usage string. The argument p points to an integer variable in which to
// store the value of the flag.
func CounterVar(p *int, name string, value int, usage string) {
CommandLine.CounterVar(p, name, value, usage)
}
// Counter defines a counter flag with specified name, default value and
// usage string. The return value is the address of an integer variable that
// stores the value of the flag.
func (f *FlagSet) Counter(name string, value int, usage string) *int {
p := new(int)
f.CounterVar(p, name, value, usage)
return p
}
// Counter defines a counter flag with specified name, default value and
// usage string. The return value is the address of an integer variable that
// stores the value of the flag.
func Counter(name string, value int, usage string) *int {
return CommandLine.Counter(name, value, usage)
}
// intLine returns the usage line for an integer flag.
func intLine(name, shorthands string, value int, usage string) line {
defaultValue := ""
if value != 0 {
defaultValue = fmt.Sprintf("%d", value)
}
return line{lineFlags(name, shorthands, defaultValue), usage}
}
// IntVarP defines an integer flag with specified name, shorthands, default
// value and usage string. The argument p points to an integer variable in
// which to store the value of the flag.
func (f *FlagSet) IntVarP(p *int, name, shorthands string, value int, usage string) {
f.addLine(intLine(name, shorthands, value, usage))
f.VarP(newIntValue(value, p), name, shorthands, RequiredArg)
}
// IntVarP defines an integer flag with specified name, shorthands, default
// value and usage string. The argument p points to an integer variable in
// which to store the value of the flag.
func IntVarP(p *int, name, shorthands string, value int, usage string) {
CommandLine.IntVarP(p, name, shorthands, value, usage)
}
// IntP defines an integer flag with specified name, shorthands, default
// value and usage string. The return value is the address of an integer
// variable that stores the value of the flag.
func (f *FlagSet) IntP(name, shorthands string, value int, usage string) *int {
p := new(int)
f.IntVarP(p, name, shorthands, value, usage)
return p
}
// IntP defines an integer flag with specified name, shorthands, default
// value and usage string. The return value is the address of an integer
// variable that stores the value of the flag.
func IntP(name, shorthands string, value int, usage string) *int {
return CommandLine.IntP(name, shorthands, value, usage)
}
// IntVar defines an integer flag with specified name, default value and
// usage string. The argument p points to an integer variable in which to
// store the value of the flag.
func (f *FlagSet) IntVar(p *int, name string, value int, usage string) {
f.addLine(intLine(name, "", value, usage))
f.Var(newIntValue(value, p), name, RequiredArg)
}
// IntVar defines an integer flag with specified name, default value and
// usage string. The argument p points to an integer variable in which to
// store the value of the flag.
func IntVar(p *int, name string, value int, usage string) {
CommandLine.IntVar(p, name, value, usage)
}
// Int defines an integer flag with specified name, default value and
// usage string. The return value is the address of an integer variable that
// stores the value of the flag.
func (f *FlagSet) Int(name string, value int, usage string) *int {
p := new(int)
f.IntVar(p, name, value, usage)
return p
}
// Int defines an integer flag with specified name, default value and
// usage string. The return value is the address of an integer variable that
// stores the value of the flag.
func Int(name string, value int, usage string) *int {
return CommandLine.Int(name, value, usage)
}
// The stringValue will store a string option.
type stringValue struct {
p *string
value string
}
// newStringValue will create a new stringValue.
func newStringValue(val string, p *string) *stringValue {
*p = val
return &stringValue{p, val}
}
// Get returns the string stored in the stringValue.
func (s *stringValue) Get() interface{} {
return *s.p
}
// Set sets the string value.
func (s *stringValue) Set(str string) error {
*s.p = str
return nil
}
// Update resets the string value to its default.
func (s *stringValue) Update() {
*s.p = s.value
}
// String returns simply the string stored in the value.
func (s *stringValue) String() string {
return *s.p
}
// stringLine creates a usage line.
func stringLine(name, shorthands, value, usage string) line {
return line{lineFlags(name, shorthands, value), usage}
}
// StringVarP defines an string flag with specified name, shorthands, default
// value and usage string. The argument p points to a string variable in
// which to store the value of the flag.
func (f *FlagSet) StringVarP(p *string, name, shorthands, value, usage string) {
f.addLine(stringLine(name, shorthands, value, usage))
f.VarP(newStringValue(value, p), name, shorthands, RequiredArg)
}
// StringVarP defines an string flag with specified name, shorthands, default
// value and usage string. The argument p points to a string variable in
// which to store the value of the flag.
func StringVarP(p *string, name, shorthands, value, usage string) {
CommandLine.StringVarP(p, name, shorthands, value, usage)
}
// StringP defines a string flag with specified name, shorthands, default
// value and usage string. The return value is the address of a string
// variable that stores the value of the flag.
func (f *FlagSet) StringP(name, shorthands, value, usage string) *string {
p := new(string)
f.StringVarP(p, name, shorthands, value, usage)
return p
}
// StringP defines a string flag with specified name, shorthands, default
// value and usage string. The return value is the address of a string
// variable that stores the value of the flag.
func StringP(name, shorthands, value, usage string) *string {
return CommandLine.StringP(name, shorthands, value, usage)
}
// StringVar defines a string flag with specified name, default value and
// usage string. The argument p points to a string variable in which to
// store the value of the flag.
func (f *FlagSet) StringVar(p *string, name, value, usage string) {
f.addLine(stringLine(name, "", value, usage))
f.Var(newStringValue(value, p), name, RequiredArg)
}
// StringVar defines a string flag with specified name, default value and
// usage string. The argument p points to a string variable in which to
// store the value of the flag.
func StringVar(p *string, name, value, usage string) {
CommandLine.StringVar(p, name, value, usage)
}
// String defines a string flag with specified name, default value and
// usage string. The return value is the address of a string variable that
// stores the value of the flag.
func (f *FlagSet) String(name, value, usage string) *string {
p := new(string)
f.StringVar(p, name, value, usage)
return p
}
// String defines a string flag with specified name, default value and
// usage string. The return value is the address of a string variable that
// stores the value of the flag.
func String(name, value, usage string) *string {
return CommandLine.String(name, value, usage)
}
// presetValue represents an integer value that can be set with multiple
// flags as -1 ... -9.
type presetValue struct {
p *int
preset int
}
// newPresetValue allocates a new preset value and returns its pointer.
func newPresetValue(p *int, preset int) *presetValue {
return &presetValue{p, preset}
}
// Get returns the actual preset value as integer.
func (p *presetValue) Get() interface{} {
return *p.p
}
// Set sets the preset value from an integer string.
func (p *presetValue) Set(s string) error {
val, err := strconv.ParseInt(s, 0, 0)
*p.p = int(val)
return err
}
// Update sets the preset value to the default.
func (p *presetValue) Update() {
*p.p = p.preset
}
// String returns the integer representation of the preset value.
func (p *presetValue) String() string {
return fmt.Sprintf("%d", *p.p)
}
// presetLine creates the usage line for a preset value.
func presetLine(start, end int, usage string) line {
return line{fmt.Sprintf("-%d ... -%d", start, end), usage}
}
// PresetVar defines a range of preset flags starting at start and
// ending at end. The argument p points to a preset variable in which to
// store the value of the flag.
//
// If start is 1 and end is 9 the flags -1 to -9 will be supported.
func (f *FlagSet) PresetVar(p *int, start, end, value int, usage string) {
if f.preset {
f.panicf("flagset %s has already a preset", f.name)
}
f.addLine(presetLine(start, end, usage))
*p = value
for i := start; i <= end; i++ {
f.Var(newPresetValue(p, i), fmt.Sprintf("%d", i), NoArg)
}
}
// PresetVar defines a range of preset flags starting at start and
// ending at end. The argument p points to a preset variable in which to
// store the value of the flag.
//
// If start is 1 and end is 9 the flags -1 to -9 will be supported.
func PresetVar(p *int, start, end, value int, usage string) {
CommandLine.PresetVar(p, start, end, value, usage)
}
// Preset defines a range of preset flags starting at start and
// ending at end. The return value is the address of a preset variable
// in which to store the value of the flag.
//
// If start is 1 and end is 9 the flags -1 to -9 will be supported.
func (f *FlagSet) Preset(start, end, value int, usage string) *int {
p := new(int)
f.PresetVar(p, start, end, value, usage)
return p
}
// Preset defines a range of preset flags starting at start and
// ending at end. The return value is the address of a preset variable
// in which to store the value of the flag.
//
// If start is 1 and end is 9 the flags -1 to -9 will be supported.
func Preset(start, end, value int, usage string) *int {
return CommandLine.Preset(start, end, value, usage)
}

View File

@@ -1,147 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gflag
import (
"bytes"
"testing"
)
func TestFlagSet_Bool(t *testing.T) {
f := NewFlagSet("Bool", ContinueOnError)
a := f.Bool("test-a", false, "")
b := f.BoolP("test-b", "b", true, "")
err := f.Parse([]string{"--test-a", "-b", "false"})
if err != nil {
t.Fatalf("f.Parse error %s", err)
}
if *a != true {
t.Errorf("*a is %t; want %t", *a, true)
}
if *b != false {
t.Errorf("*b is %t; want %t", *b, false)
}
t.Logf("args %v", f.Args())
if f.NArg() != 0 {
t.Errorf("f.NArg() is %d; want %d", f.NArg(), 0)
}
}
func TestFlagSet_Counter_1(t *testing.T) {
f := NewFlagSet("Counter_1", ContinueOnError)
a := f.Counter("test-a", 0, "")
b := f.CounterP("test-b", "b", 0, "")
err := f.Parse([]string{"--test-a=3", "-b", "5", "--test-a", "-b"})
if err != nil {
t.Fatalf("f.Parse error %s", err)
}
if *a != 4 {
t.Errorf("*a is %d; want %d", *a, 4)
}
if *b != 6 {
t.Errorf("*b is %d; want %d", *b, 6)
}
if f.NArg() != 0 {
t.Errorf("f.NArg() is %d; want %d", f.NArg(), 0)
}
}
func TestFlagSet_Counter_2(t *testing.T) {
f := NewFlagSet("Counter_2", ContinueOnError)
v := f.CounterP("verbose", "v", 0, "")
err := f.Parse([]string{"-vvvv", "test.txt"})
if err != nil {
t.Fatalf("f.Parse error %s", err)
}
if f.NArg() != 1 {
t.Fatalf("f.NArg() is %d; want %d", f.NArg(), 1)
}
if f.Arg(0) != "test.txt" {
t.Errorf("f.Arg(%d) is %q; want %q", 0, f.Arg(0), "test.txt")
}
if *v != 4 {
t.Errorf("*v is %d; want %d", *v, 4)
}
}
func TestFlagSet_Int(t *testing.T) {
f := NewFlagSet("Int", ContinueOnError)
a := f.Int("test-a", 0, "")
b := f.IntP("test-b", "b", 0, "")
c := f.Int("c", 0, "")
err := f.Parse([]string{"--test-a=0x23", "foo", "-b", "077",
"-c", "33", "bar"})
if err != nil {
t.Fatalf("f.Parse error %s", err)
}
if *a != 0x23 {
t.Errorf("*a is %d; want %d", *a, 0x23)
}
if *b != 077 {
t.Errorf("*b is %d; want %d", *b, 077)
}
if *c != 33 {
t.Errorf("*c is %d; want %d", *c, 33)
}
if f.NArg() != 2 {
t.Errorf("f.NArg() is %d; want %d", f.NArg(), 2)
}
for i, s := range []string{"foo", "bar"} {
if f.Arg(i) != s {
t.Errorf("f.Arg(%d) is %s; want %s", i, f.Arg(i), s)
}
}
}
func TestFlagSet_String(t *testing.T) {
f := NewFlagSet("String", ContinueOnError)
a := f.StringP("test-s", "s", "test", "")
err := f.Parse([]string{})
if err != nil {
t.Fatalf("f.Parse error %s", err)
}
if *a != "test" {
t.Fatalf("*a is %q; want %q", *a, "test")
}
if err = f.Parse([]string{"--test-s=s"}); err != nil {
t.Fatalf("f.Parse error %s", err)
}
if *a != "s" {
t.Fatalf("*a is %q; want %q", *a, "s")
}
}
func TestFlagSet_Usage(t *testing.T) {
f := NewFlagSet("test", ContinueOnError)
f.IntP("test-a", "a", 3, "tests a")
f.CounterP("count-b", "b", 0, "counts b")
buf := new(bytes.Buffer)
f.SetOutput(buf)
f.usage()
t.Log(buf.String())
}
func TestFlagSet_Preset(t *testing.T) {
f := NewFlagSet("test", ContinueOnError)
n := f.Preset(0, 9, 6, "preset flag")
if *n != 6 {
t.Fatalf("preset is %d; want %d", *n, 6)
}
err := f.Parse([]string{"-0", "-9", "-8"})
if err != nil {
t.Fatalf("f.Parse returned %s", err)
}
if *n != 8 {
t.Errorf("preset is %d; want %d", *n, 8)
}
}

View File

@@ -1,30 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package hash
import "testing"
func TestCyclicPolySimple(t *testing.T) {
p := []byte("abcde")
r := NewCyclicPoly(4)
h2 := Hashes(r, p)
for i, h := range h2 {
w := Hashes(r, p[i:i+4])[0]
t.Logf("%d h=%#016x w=%#016x", i, h, w)
if h != w {
t.Errorf("rolling hash %d: %#016x; want %#016x",
i, h, w)
}
}
}
func BenchmarkCyclicPoly(b *testing.B) {
p := makeBenchmarkBytes(4096)
r := NewCyclicPoly(4)
b.ResetTimer()
for i := 0; i < b.N; i++ {
Hashes(r, p)
}
}

View File

@@ -1,42 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package hash
import (
"math/rand"
"testing"
)
func TestRabinKarpSimple(t *testing.T) {
p := []byte("abcde")
r := NewRabinKarp(4)
h2 := Hashes(r, p)
for i, h := range h2 {
w := Hashes(r, p[i:i+4])[0]
t.Logf("%d h=%#016x w=%#016x", i, h, w)
if h != w {
t.Errorf("rolling hash %d: %#016x; want %#016x",
i, h, w)
}
}
}
func makeBenchmarkBytes(n int) []byte {
rnd := rand.New(rand.NewSource(42))
p := make([]byte, n)
for i := range p {
p[i] = byte(rnd.Uint32())
}
return p
}
func BenchmarkRabinKarp(b *testing.B) {
p := makeBenchmarkBytes(4096)
r := NewRabinKarp(4)
b.ResetTimer()
for i := 0; i < b.N; i++ {
Hashes(r, p)
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,82 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package randtxt
import (
"bufio"
"io"
"unicode"
)
// GroupReader groups the incoming text in groups of 5, whereby the
// number of groups per line can be controlled.
type GroupReader struct {
R io.ByteReader
GroupsPerLine int
off int64
eof bool
}
// NewGroupReader creates a new group reader.
func NewGroupReader(r io.Reader) *GroupReader {
return &GroupReader{R: bufio.NewReader(r)}
}
// Read formats the data provided by the internal reader in groups of 5
// characters. If GroupsPerLine hasn't been initialized 8 groups per
// line will be produced.
func (r *GroupReader) Read(p []byte) (n int, err error) {
if r.eof {
return 0, io.EOF
}
groupsPerLine := r.GroupsPerLine
if groupsPerLine < 1 {
groupsPerLine = 8
}
lineLen := int64(groupsPerLine * 6)
var c byte
for i := range p {
switch {
case r.off%lineLen == lineLen-1:
if i+1 == len(p) && len(p) > 1 {
return i, nil
}
c = '\n'
case r.off%6 == 5:
if i+1 == len(p) && len(p) > 1 {
return i, nil
}
c = ' '
default:
c, err = r.R.ReadByte()
if err == io.EOF {
r.eof = true
if i > 0 {
switch p[i-1] {
case ' ':
p[i-1] = '\n'
fallthrough
case '\n':
return i, io.EOF
}
}
p[i] = '\n'
return i + 1, io.EOF
}
if err != nil {
return i, err
}
switch {
case c == ' ':
c = '_'
case !unicode.IsPrint(rune(c)):
c = '-'
}
}
p[i] = c
r.off++
}
return len(p), nil
}

View File

@@ -1,185 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package randtxt supports the generation of random text using a
// trigram model for the English language.
package randtxt
import (
"math"
"math/rand"
"sort"
)
// ngram stores an entry from the language model.
type ngram struct {
s string
lgP float64
lgQ float64
}
// ngrams represents a slice of ngram values and is used to represent a
// language model.
type ngrams []ngram
func (s ngrams) Len() int { return len(s) }
func (s ngrams) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s ngrams) Less(i, j int) bool { return s[i].s < s[j].s }
// Sorts the language model in the sequence of their ngrams.
func (s ngrams) Sort() { sort.Sort(s) }
// Search is looking for an ngram or the position where it would be
// inserted.
func (s ngrams) Search(g string) int {
return sort.Search(len(s), func(k int) bool { return s[k].s >= g })
}
// prob represents a string, usually an ngram, and a probability value.
type prob struct {
s string
p float64
}
// probs is a slice of prob values that can be sorted and searched.
type probs []prob
func (s probs) Len() int { return len(s) }
func (s probs) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s probs) Less(i, j int) bool { return s[i].s < s[j].s }
// SortByNgram sorts the probs slice by ngram, field s.
func (s probs) SortByNgram() { sort.Sort(s) }
// SortsByProb sorts the probs slice by probability, field p.
func (s probs) SortByProb() { sort.Sort(byProb{s}) }
// SearchNgram searches for an ngram or the position where it would be
// inserted.
func (s probs) SearchNgram(g string) int {
return sort.Search(len(s), func(k int) bool { return s[k].s >= g })
}
// SearchProb searches ngrams for a specific probability or where it
// would be inserted.
func (s probs) SearchProb(p float64) int {
return sort.Search(len(s), func(k int) bool { return s[k].p >= p })
}
// byProb is used to sort probs slice by probability, field p.
type byProb struct {
probs
}
func (s byProb) Less(i, j int) bool {
return s.probs[i].p < s.probs[j].p
}
// cdf can be used to setup a cumulative distribution function
// represented by a probs slice. We should have returned an actual
// function.
func cdf(n int, p func(i int) prob) probs {
prs := make(probs, n)
sum := 0.0
for i := range prs {
pr := p(i)
sum += pr.p
prs[i] = pr
}
q := 1.0 / sum
x := 0.0
for i, pr := range prs {
x += pr.p * q
if x > 1.0 {
x = 1.0
}
prs[i].p = x
}
if !sort.IsSorted(byProb{prs}) {
panic("cdf not sorted")
}
return prs
}
// pCDFOfLM converts a language model into a cumulative distribution
// function represented by probs.
func pCDFOfLM(lm ngrams) probs {
return cdf(len(lm), func(i int) prob {
return prob{lm[i].s, math.Exp2(lm[i].lgP)}
})
}
// cCDF converts a ngrams slice into a cumulative distribution function
// using the conditional probability lgQ.
func cCDF(s ngrams) probs {
return cdf(len(s), func(i int) prob {
return prob{s[i].s, math.Exp2(s[i].lgQ)}
})
}
// comap contains a map of conditional distribution function for the
// last character.
type comap map[string]probs
// comapOfLM converts a language model in a map of conditional
// distribution functions.
func comapOfLM(lm ngrams) comap {
if !sort.IsSorted(lm) {
panic("lm is not sorted")
}
m := make(comap, 26*26)
for i := 0; i < len(lm); {
j := i
g := lm[i].s
g2 := g[:2]
z := g2 + "Z"
i = lm.Search(z)
if i >= len(lm) || lm[i].s != z {
panic("unexpected search result")
}
i++
m[g2] = cCDF(lm[j:i])
}
return m
}
// trigram returns the trigram with prefix g2 using a probability value
// in the range [0.0,1.0).
func (c comap) trigram(g2 string, p float64) string {
prs := c[g2]
i := prs.SearchProb(p)
return prs[i].s
}
var (
// CDF for normal probabilities
pcdf = pCDFOfLM(englm3)
// map of two letter conditionals
cmap = comapOfLM(englm3)
)
// Reader generates a stream of text of uppercase letters with trigrams
// distributed according to a language model of the English language.
type Reader struct {
rnd *rand.Rand
g3 string
}
// NewReader creates a new reader. The argument src must create a uniformly
// distributed stream of random values.
func NewReader(src rand.Source) *Reader {
rnd := rand.New(src)
i := pcdf.SearchProb(rnd.Float64())
return &Reader{rnd, pcdf[i].s}
}
// Read reads random text. The Read function will always return len(p)
// bytes and will never return an error.
func (r *Reader) Read(p []byte) (n int, err error) {
for i := range p {
r.g3 = cmap.trigram(r.g3[1:], r.rnd.Float64())
p[i] = r.g3[2]
}
return len(p), nil
}

View File

@@ -1,37 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package randtxt
import (
"bufio"
"io"
"math/rand"
"testing"
)
func TestReader(t *testing.T) {
lr := io.LimitReader(NewReader(rand.NewSource(13)), 195)
pretty := NewGroupReader(lr)
scanner := bufio.NewScanner(pretty)
for scanner.Scan() {
t.Log(scanner.Text())
}
if err := scanner.Err(); err != nil {
t.Fatalf("scanner error %s", err)
}
}
func TestComap(t *testing.T) {
prs := cmap["TH"]
for _, p := range prs[3:6] {
t.Logf("%v", p)
}
p := 0.2
x := cmap.trigram("TH", p)
if x != "THE" {
t.Fatalf("cmap.trigram(%q, %.1f) returned %q; want %q",
"TH", p, x, "THE")
}
}

View File

@@ -1,11 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd netbsd openbsd
package term
import "syscall"
const ioctlGetTermios = syscall.TIOCGETA

View File

@@ -1,7 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package term
const ioctlGetTermios = 0x5401 // syscall.TCGETS

View File

@@ -1,21 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux,!appengine netbsd openbsd
// Package term provides the IsTerminal function.
package term
import (
"syscall"
"unsafe"
)
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd uintptr) bool {
var termios syscall.Termios
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd,
ioctlGetTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
}

View File

@@ -1,22 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package term
import (
"syscall"
"unsafe"
)
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
var getConsoleMode = kernel32.NewProc("GetConsoleMode")
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd uintptr) bool {
var st uint32
r, _, e := syscall.Syscall(getConsoleMode.Addr(),
2, fd, uintptr(unsafe.Pointer(&st)), 0)
return r != 0 && e == 0
}

View File

@@ -1,107 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. 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"
"math/rand"
"strings"
"testing"
"github.com/ulikunitz/xz/internal/randtxt"
)
func TestBinTree_Find(t *testing.T) {
bt, err := newBinTree(30)
if err != nil {
t.Fatal(err)
}
const s = "Klopp feiert mit Liverpool seinen hoechsten SiegSieg"
n, err := io.WriteString(bt, s)
if err != nil {
t.Fatalf("WriteString error %s", err)
}
if n != len(s) {
t.Fatalf("WriteString returned %d; want %d", n, len(s))
}
/* dump info writes the complete tree
if err = bt.dump(os.Stdout); err != nil {
t.Fatalf("bt.dump error %s", err)
}
*/
tests := []string{"Sieg", "Sieb", "Simu"}
for _, c := range tests {
x := xval([]byte(c))
a, b := bt.search(bt.root, x)
t.Logf("%q: a, b == %d, %d", c, a, b)
}
}
func TestBinTree_PredSucc(t *testing.T) {
bt, err := newBinTree(30)
if err != nil {
t.Fatal(err)
}
const s = "Klopp feiert mit Liverpool seinen hoechsten Sieg."
n, err := io.WriteString(bt, s)
if err != nil {
t.Fatalf("WriteString error %s", err)
}
if n != len(s) {
t.Fatalf("WriteString returned %d; want %d", n, len(s))
}
for v := bt.min(bt.root); v != null; v = bt.succ(v) {
t.Log(dumpX(bt.node[v].x))
}
t.Log("")
for v := bt.max(bt.root); v != null; v = bt.pred(v) {
t.Log(dumpX(bt.node[v].x))
}
}
func TestBinTree_Cycle(t *testing.T) {
buf := new(bytes.Buffer)
w, err := Writer2Config{
DictCap: 4096,
Matcher: BinaryTree,
}.NewWriter2(buf)
if err != nil {
t.Fatalf("NewWriter error %s", err)
}
// const txtlen = 1024
const txtlen = 10000
io.CopyN(buf, randtxt.NewReader(rand.NewSource(42)), txtlen)
txt := buf.String()
buf.Reset()
n, err := io.Copy(w, strings.NewReader(txt))
if err != nil {
t.Fatalf("Compressing copy error %s", err)
}
if n != txtlen {
t.Fatalf("Compressing data length %d; want %d", n, txtlen)
}
if err = w.Close(); err != nil {
t.Fatalf("w.Close error %s", err)
}
t.Logf("buf.Len() %d", buf.Len())
r, err := Reader2Config{DictCap: 4096}.NewReader2(buf)
if err != nil {
t.Fatalf("NewReader error %s", err)
}
out := new(bytes.Buffer)
n, err = io.Copy(out, r)
if err != nil {
t.Fatalf("Decompressing copy error %s after %d bytes", err, n)
}
if n != txtlen {
t.Fatalf("Decompression data length %d; want %d", n, txtlen)
}
if txt != out.String() {
t.Fatal("decompressed data differs from original")
}
}

View File

@@ -1,230 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. 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"
"testing"
)
func TestBuffer_Write(t *testing.T) {
buf := newBuffer(10)
b := []byte("1234567890")
for i := range b {
n, err := buf.Write(b[i : i+1])
if err != nil {
t.Fatalf("buf.Write(b[%d:%d]) error %s", i, i+1, err)
}
if n != 1 {
t.Fatalf("buf.Write(b[%d:%d]) returned %d; want %d",
i, i+1, n, 1)
}
}
const c = 8
n, err := buf.Discard(c)
if err != nil {
t.Fatalf("Discard error %s", err)
}
if n != c {
t.Fatalf("Discard returned %d; want %d", n, c)
}
n, err = buf.Write(b)
if err == nil {
t.Fatalf("Write length exceed returned no error; n %d", n)
}
if n != c {
t.Fatalf("Write length exceeding returned %d; want %d", n, c)
}
n, err = buf.Discard(4)
if err != nil {
t.Fatalf("Discard error %s", err)
}
if n != 4 {
t.Fatalf("Discard returned %d; want %d", n, 4)
}
n, err = buf.Write(b[:3])
if err != nil {
t.Fatalf("buf.Write(b[:3]) error %s; n %d", err, n)
}
if n != 3 {
t.Fatalf("buf.Write(b[:3]) returned %d; want %d", n, 3)
}
}
func TestBuffer_Buffered_Available(t *testing.T) {
buf := newBuffer(19)
b := []byte("0123456789")
var err error
if _, err = buf.Write(b); err != nil {
t.Fatalf("buf.Write(b) error %s", err)
}
if n := buf.Buffered(); n != 10 {
t.Fatalf("buf.Buffered() returns %d; want %d", n, 10)
}
if _, err = buf.Discard(8); err != nil {
t.Fatalf("buf.Discard(8) error %s", err)
}
if _, err = buf.Write(b[:7]); err != nil {
t.Fatalf("buf.Write(b[:7]) error %s", err)
}
if n := buf.Buffered(); n != 9 {
t.Fatalf("buf.Buffered() returns %d; want %d", n, 9)
}
}
func TestBuffer_Read(t *testing.T) {
buf := newBuffer(10)
b := []byte("0123456789")
var err error
if _, err = buf.Write(b); err != nil {
t.Fatalf("buf.Write(b) error %s", err)
}
p := make([]byte, 8)
n, err := buf.Read(p)
if err != nil {
t.Fatalf("buf.Read(p) error %s", err)
}
if n != len(p) {
t.Fatalf("buf.Read(p) returned %d; want %d", n, len(p))
}
if !bytes.Equal(p, b[:8]) {
t.Fatalf("buf.Read(p) put %s into p; want %s", p, b[:8])
}
if _, err = buf.Write(b[:7]); err != nil {
t.Fatalf("buf.Write(b[:7]) error %s", err)
}
q := make([]byte, 7)
n, err = buf.Read(q)
if err != nil {
t.Fatalf("buf.Read(q) error %s", err)
}
if n != len(q) {
t.Fatalf("buf.Read(q) returns %d; want %d", n, len(q))
}
c := []byte("8901234")
if !bytes.Equal(q, c) {
t.Fatalf("buf.Read(q) put %s into q; want %s", q, c)
}
if _, err := buf.Write(b[7:]); err != nil {
t.Fatalf("buf.Write(b[7:]) error %s", err)
}
if _, err := buf.Write(b[:2]); err != nil {
t.Fatalf("buf.Write(b[:2]) error %s", err)
}
t.Logf("buf.rear %d buf.front %d", buf.rear, buf.front)
r := make([]byte, 2)
n, err = buf.Read(r)
if err != nil {
t.Fatalf("buf.Read(r) error %s", err)
}
if n != len(r) {
t.Fatalf("buf.Read(r) returns %d; want %d", n, len(r))
}
d := []byte("56")
if !bytes.Equal(r, d) {
t.Fatalf("buf.Read(r) put %s into r; want %s", r, d)
}
}
func TestBuffer_Discard(t *testing.T) {
buf := newBuffer(10)
b := []byte("0123456789")
var err error
if _, err = buf.Write(b); err != nil {
t.Fatalf("buf.Write(b) error %s", err)
}
n, err := buf.Discard(11)
if err == nil {
t.Fatalf("buf.Discard(11) didn't return error")
}
if n != 10 {
t.Fatalf("buf.Discard(11) returned %d; want %d", n, 10)
}
if _, err := buf.Write(b); err != nil {
t.Fatalf("buf.Write(b) #2 error %s", err)
}
n, err = buf.Discard(10)
if err != nil {
t.Fatalf("buf.Discard(10) error %s", err)
}
if n != 10 {
t.Fatalf("buf.Discard(11) returned %d; want %d", n, 10)
}
if _, err := buf.Write(b[:4]); err != nil {
t.Fatalf("buf.Write(b[:4]) error %s", err)
}
n, err = buf.Discard(1)
if err != nil {
t.Fatalf("buf.Discard(1) error %s", err)
}
if n != 1 {
t.Fatalf("buf.Discard(1) returned %d; want %d", n, 1)
}
}
func TestBuffer_Discard_error(t *testing.T) {
buf := newBuffer(10)
n, err := buf.Discard(-1)
if err == nil {
t.Fatal("buf.Discard(-1) didn't return an error")
}
if n != 0 {
t.Fatalf("buf.Discard(-1) returned %d; want %d", n, 0)
}
}
func TestPrefixLen(t *testing.T) {
tests := []struct {
a, b []byte
k int
}{
{[]byte("abcde"), []byte("abc"), 3},
{[]byte("abc"), []byte("uvw"), 0},
{[]byte(""), []byte("uvw"), 0},
{[]byte("abcde"), []byte("abcuvw"), 3},
}
for _, c := range tests {
k := prefixLen(c.a, c.b)
if k != c.k {
t.Errorf("prefixLen(%q,%q) returned %d; want %d",
c.a, c.b, k, c.k)
}
k = prefixLen(c.b, c.a)
if k != c.k {
t.Errorf("prefixLen(%q,%q) returned %d; want %d",
c.b, c.a, k, c.k)
}
}
}
func TestMatchLen(t *testing.T) {
buf := newBuffer(13)
const s = "abcaba"
_, err := io.WriteString(buf, s)
if err != nil {
t.Fatalf("WriteString error %s", err)
}
_, err = io.WriteString(buf, s)
if err != nil {
t.Fatalf("WriteString error %s", err)
}
if _, err = buf.Discard(12); err != nil {
t.Fatalf("buf.Discard(6) error %s", err)
}
_, err = io.WriteString(buf, s)
if err != nil {
t.Fatalf("WriteString error %s", err)
}
tests := []struct{ d, n int }{{1, 1}, {3, 2}, {6, 6}, {5, 0}, {2, 0}}
for _, c := range tests {
n := buf.matchLen(c.d, []byte(s))
if n != c.n {
t.Errorf(
"MatchLen(%d,[]byte(%q)) returned %d; want %d",
c.d, s, n, c.n)
}
}
}

View File

@@ -1,59 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. 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"
"io/ioutil"
"os"
"testing"
)
func TestDecoder(t *testing.T) {
filename := "fox.lzma"
want := "The quick brown fox jumps over the lazy dog.\n"
for i := 0; i < 2; i++ {
f, err := os.Open(filename)
if err != nil {
t.Fatalf("os.Open(%q) error %s", filename, err)
}
p := make([]byte, 13)
_, err = io.ReadFull(f, p)
if err != nil {
t.Fatalf("io.ReadFull error %s", err)
}
props, err := PropertiesForCode(p[0])
if err != nil {
t.Fatalf("p[0] error %s", err)
}
state := newState(props)
const capacity = 0x800000
dict, err := newDecoderDict(capacity)
if err != nil {
t.Fatalf("newDecoderDict: error %s", err)
}
size := int64(-1)
if i > 0 {
size = int64(len(want))
}
br := bufio.NewReader(f)
r, err := newDecoder(br, state, dict, size)
if err != nil {
t.Fatalf("newDecoder error %s", err)
}
bytes, err := ioutil.ReadAll(r)
if err != nil {
t.Fatalf("[%d] ReadAll error %s", i, err)
}
if err = f.Close(); err != nil {
t.Fatalf("Close error %s", err)
}
got := string(bytes)
if got != want {
t.Fatalf("read %q; but want %q", got, want)
}
}
}

View File

@@ -1,33 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. 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 (
"fmt"
"testing"
)
func peek(d *decoderDict) []byte {
p := make([]byte, d.buffered())
k, err := d.peek(p)
if err != nil {
panic(fmt.Errorf("peek: "+
"Read returned unexpected error %s", err))
}
if k != len(p) {
panic(fmt.Errorf("peek: "+
"Read returned %d; wanted %d", k, len(p)))
}
return p
}
func TestNewDecoderDict(t *testing.T) {
if _, err := newDecoderDict(0); err == nil {
t.Fatalf("no error for zero dictionary capacity")
}
if _, err := newDecoderDict(8); err != nil {
t.Fatalf("error %s", err)
}
}

View File

@@ -1,151 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. 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"
"math/rand"
"testing"
"github.com/ulikunitz/xz/internal/randtxt"
)
var testString = `LZMA decoder test example
=========================
! LZMA ! Decoder ! TEST !
=========================
! TEST ! LZMA ! Decoder !
=========================
---- Test Line 1 --------
=========================
---- Test Line 2 --------
=========================
=== End of test file ====
=========================
`
func cycle(t *testing.T, n int) {
t.Logf("cycle(t,%d)", n)
if n > len(testString) {
t.Fatalf("cycle: n=%d larger than len(testString)=%d", n,
len(testString))
}
const dictCap = MinDictCap
m, err := newHashTable(dictCap, 4)
if err != nil {
t.Fatal(err)
}
encoderDict, err := newEncoderDict(dictCap, dictCap+1024, m)
if err != nil {
t.Fatal(err)
}
props := Properties{2, 0, 2}
if err := props.verify(); err != nil {
t.Fatalf("properties error %s", err)
}
state := newState(props)
var buf bytes.Buffer
w, err := newEncoder(&buf, state, encoderDict, eosMarker)
if err != nil {
t.Fatalf("newEncoder error %s", err)
}
orig := []byte(testString)[:n]
t.Logf("len(orig) %d", len(orig))
k, err := w.Write(orig)
if err != nil {
t.Fatalf("w.Write error %s", err)
}
if k != len(orig) {
t.Fatalf("w.Write returned %d; want %d", k, len(orig))
}
if err = w.Close(); err != nil {
t.Fatalf("w.Close error %s", err)
}
t.Logf("buf.Len() %d len(orig) %d", buf.Len(), len(orig))
decoderDict, err := newDecoderDict(dictCap)
if err != nil {
t.Fatalf("newDecoderDict error %s", err)
}
state.Reset()
r, err := newDecoder(&buf, state, decoderDict, -1)
if err != nil {
t.Fatalf("newDecoder error %s", err)
}
decoded, err := ioutil.ReadAll(r)
if err != nil {
t.Fatalf("ReadAll(lr) error %s", err)
}
t.Logf("decoded: %s", decoded)
if len(orig) != len(decoded) {
t.Fatalf("length decoded is %d; want %d", len(decoded),
len(orig))
}
if !bytes.Equal(orig, decoded) {
t.Fatalf("decoded file differs from original")
}
}
func TestEncoderCycle1(t *testing.T) {
cycle(t, len(testString))
}
func TestEncoderCycle2(t *testing.T) {
buf := new(bytes.Buffer)
const txtlen = 50000
io.CopyN(buf, randtxt.NewReader(rand.NewSource(42)), txtlen)
txt := buf.String()
buf.Reset()
const dictCap = MinDictCap
m, err := newHashTable(dictCap, 4)
if err != nil {
t.Fatal(err)
}
encoderDict, err := newEncoderDict(dictCap, dictCap+1024, m)
if err != nil {
t.Fatal(err)
}
props := Properties{3, 0, 2}
if err := props.verify(); err != nil {
t.Fatalf("properties error %s", err)
}
state := newState(props)
lbw := &LimitedByteWriter{BW: buf, N: 100}
w, err := newEncoder(lbw, state, encoderDict, 0)
if err != nil {
t.Fatalf("NewEncoder error %s", err)
}
_, err = io.WriteString(w, txt)
if err != nil && err != ErrLimit {
t.Fatalf("WriteString error %s", err)
}
if err = w.Close(); err != nil {
t.Fatalf("w.Close error %s", err)
}
n := w.Compressed()
txt = txt[:n]
decoderDict, err := newDecoderDict(dictCap)
if err != nil {
t.Fatalf("NewDecoderDict error %s", err)
}
state.Reset()
r, err := newDecoder(buf, state, decoderDict, n)
if err != nil {
t.Fatalf("NewDecoder error %s", err)
}
out := new(bytes.Buffer)
if _, err = io.Copy(out, r); err != nil {
t.Fatalf("decompress copy error %s", err)
}
got := out.String()
t.Logf("%s", got)
if len(got) != int(n) {
t.Fatalf("len(got) %d; want %d", len(got), n)
}
if got != txt {
t.Fatalf("got and txt differ")
}
}

View File

@@ -1,5 +0,0 @@
These examples are taken from the draft LZMA specification as published.
This is publishjed by 7-zip.org under
http://www.7-zip.org/sdk.html

Binary file not shown.

View File

@@ -1,12 +0,0 @@
LZMA decoder test example
=========================
! LZMA ! Decoder ! TEST !
=========================
! TEST ! LZMA ! Decoder !
=========================
---- Test Line 1 --------
=========================
---- Test Line 2 --------
=========================
=== End of test file ====
=========================

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,20 +0,0 @@
GOOD archives:
a.lzma
the stream was compressed with default properties lp=0 lc=3 pb=2 and 64 KiB dictionary
a_eos.lzma
the stream has EOS marker
a_eos_and_size.lzma
the stream has EOS marker and unpack size is defined
a_lp1_lc2_pb1.lzma
the stream was compressed with lp=1 lc=2 pb=1 properties
BAD ARCHIVES:
bad_corrupted.lzma
some bytes in compressed stream were changed
bad_eos_incorrect_size.lzma
the stream has EOS marker and unpack size in header is larger than real uncompressed size
bad_incorrect_size.lzma
the header contains incorrect size (290). The correct size is 327

Binary file not shown.

View File

@@ -1,47 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. 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 (
"fmt"
"testing"
)
func TestHashTable(t *testing.T) {
ht, err := newHashTable(32, 2)
if err != nil {
t.Fatalf("newHashTable: error %s", err)
}
// 01234567890123456
s := "abcabcdefghijklmn"
n, err := ht.Write([]byte(s))
if err != nil {
t.Fatalf("ht.Write: error %s", err)
}
if n != len(s) {
t.Fatalf("ht.Write returned %d; want %d", n, len(s))
}
tests := []struct {
s string
w string
}{
{"ab", "[3 0]"},
{"bc", "[4 1]"},
{"ca", "[2]"},
{"xx", "[]"},
{"gh", "[9]"},
{"mn", "[15]"},
}
distances := make([]int64, 20)
for _, c := range tests {
distances := distances[:20]
k := ht.Matches([]byte(c.s), distances)
distances = distances[:k]
o := fmt.Sprintf("%v", distances)
if o != c.w {
t.Errorf("%s: offsets %s; want %s", c.s, o, c.w)
}
}
}

View File

@@ -1,153 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. 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"
"fmt"
"testing"
)
func TestChunkTypeString(t *testing.T) {
tests := [...]struct {
c chunkType
s string
}{
{cEOS, "EOS"},
{cUD, "UD"},
{cU, "U"},
{cL, "L"},
{cLR, "LR"},
{cLRN, "LRN"},
{cLRND, "LRND"},
}
for _, c := range tests {
s := fmt.Sprintf("%v", c.c)
if s != c.s {
t.Errorf("got %s; want %s", s, c.s)
}
}
}
func TestHeaderChunkType(t *testing.T) {
tests := []struct {
h byte
c chunkType
}{
{h: 0, c: cEOS},
{h: 1, c: cUD},
{h: 2, c: cU},
{h: 1<<7 | 0x1f, c: cL},
{h: 1<<7 | 1<<5 | 0x1f, c: cLR},
{h: 1<<7 | 1<<6 | 0x1f, c: cLRN},
{h: 1<<7 | 1<<6 | 1<<5 | 0x1f, c: cLRND},
{h: 1<<7 | 1<<6 | 1<<5, c: cLRND},
}
if _, err := headerChunkType(3); err == nil {
t.Fatalf("headerChunkType(%d) got %v; want %v",
3, err, errHeaderByte)
}
for _, tc := range tests {
c, err := headerChunkType(tc.h)
if err != nil {
t.Fatalf("headerChunkType error %s", err)
}
if c != tc.c {
t.Errorf("got %s; want %s", c, tc.c)
}
}
}
func TestHeaderLen(t *testing.T) {
tests := []struct {
c chunkType
n int
}{
{cEOS, 1}, {cU, 3}, {cUD, 3}, {cL, 5}, {cLR, 5}, {cLRN, 6},
{cLRND, 6},
}
for _, tc := range tests {
n := headerLen(tc.c)
if n != tc.n {
t.Errorf("header length for %s %d; want %d",
tc.c, n, tc.n)
}
}
}
func chunkHeaderSamples(t *testing.T) []chunkHeader {
props := Properties{LC: 3, LP: 0, PB: 2}
headers := make([]chunkHeader, 0, 12)
for c := cEOS; c <= cLRND; c++ {
var h chunkHeader
h.ctype = c
if c >= cUD {
h.uncompressed = 0x0304
}
if c >= cL {
h.compressed = 0x0201
}
if c >= cLRN {
h.props = props
}
headers = append(headers, h)
}
return headers
}
func TestChunkHeaderMarshalling(t *testing.T) {
for _, h := range chunkHeaderSamples(t) {
data, err := h.MarshalBinary()
if err != nil {
t.Fatalf("MarshalBinary for %v error %s", h, err)
}
var g chunkHeader
if err = g.UnmarshalBinary(data); err != nil {
t.Fatalf("UnmarshalBinary error %s", err)
}
if g != h {
t.Fatalf("got %v; want %v", g, h)
}
}
}
func TestReadChunkHeader(t *testing.T) {
for _, h := range chunkHeaderSamples(t) {
data, err := h.MarshalBinary()
if err != nil {
t.Fatalf("MarshalBinary for %v error %s", h, err)
}
r := bytes.NewReader(data)
g, err := readChunkHeader(r)
if err != nil {
t.Fatalf("readChunkHeader for %v error %s", h, err)
}
if *g != h {
t.Fatalf("got %v; want %v", g, h)
}
}
}
func TestReadEOS(t *testing.T) {
var b [1]byte
r := bytes.NewReader(b[:])
h, err := readChunkHeader(r)
if err != nil {
t.Fatalf("readChunkHeader error %s", err)
}
if h.ctype != cEOS {
t.Errorf("ctype got %s; want %s", h.ctype, cEOS)
}
if h.compressed != 0 {
t.Errorf("compressed got %d; want %d", h.compressed, 0)
}
if h.uncompressed != 0 {
t.Errorf("uncompressed got %d; want %d", h.uncompressed, 0)
}
wantProps := Properties{}
if h.props != wantProps {
t.Errorf("props got %v; want %v", h.props, wantProps)
}
}

View File

@@ -1,52 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. 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 "testing"
func TestHeaderMarshalling(t *testing.T) {
tests := []header{
{properties: Properties{3, 0, 2}, dictCap: 8 * 1024 * 1024,
size: -1},
{properties: Properties{4, 3, 3}, dictCap: 4096,
size: 10},
}
for _, h := range tests {
data, err := h.marshalBinary()
if err != nil {
t.Fatalf("marshalBinary error %s", err)
}
var g header
if err = g.unmarshalBinary(data); err != nil {
t.Fatalf("unmarshalBinary error %s", err)
}
if h != g {
t.Errorf("got header %#v; want %#v", g, h)
}
}
}
func TestValidHeader(t *testing.T) {
tests := []header{
{properties: Properties{3, 0, 2}, dictCap: 8 * 1024 * 1024,
size: -1},
{properties: Properties{4, 3, 3}, dictCap: 4096,
size: 10},
}
for _, h := range tests {
data, err := h.marshalBinary()
if err != nil {
t.Fatalf("marshalBinary error %s", err)
}
if !ValidHeader(data) {
t.Errorf("ValidHeader returns false for header %v;"+
" want true", h)
}
}
const a = "1234567890123"
if ValidHeader([]byte(a)) {
t.Errorf("ValidHeader returns true for %s; want false", a)
}
}

View File

@@ -1,312 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. 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"
"bytes"
"io"
"io/ioutil"
"log"
"os"
"path/filepath"
"testing"
"testing/iotest"
)
func TestNewReader(t *testing.T) {
f, err := os.Open("examples/a.lzma")
if err != nil {
t.Fatalf("open examples/a.lzma: %s", err)
}
defer f.Close()
_, err = NewReader(bufio.NewReader(f))
if err != nil {
t.Fatalf("NewReader: %s", err)
}
}
const (
dirname = "examples"
origname = "a.txt"
)
func readOrigFile(t *testing.T) []byte {
orig, err := ioutil.ReadFile(filepath.Join(dirname, origname))
if err != nil {
t.Fatalf("ReadFile: %s", err)
}
return orig
}
func testDecodeFile(t *testing.T, filename string, orig []byte) {
pathname := filepath.Join(dirname, filename)
f, err := os.Open(pathname)
if err != nil {
t.Fatalf("Open(%q): %s", pathname, err)
}
defer func() {
if err = f.Close(); err != nil {
t.Fatalf("f.Close() error %s", err)
}
}()
t.Logf("file %s opened", filename)
l, err := NewReader(bufio.NewReader(f))
if err != nil {
t.Fatalf("NewReader: %s", err)
}
decoded, err := ioutil.ReadAll(l)
if err != nil {
t.Fatalf("ReadAll: %s", err)
}
t.Logf("%s", decoded)
if len(orig) != len(decoded) {
t.Fatalf("length decoded is %d; want %d",
len(decoded), len(orig))
}
if !bytes.Equal(orig, decoded) {
t.Fatalf("decoded file differs from original")
}
}
func TestReaderSimple(t *testing.T) {
// DebugOn(os.Stderr)
// defer DebugOff()
testDecodeFile(t, "a.lzma", readOrigFile(t))
}
func TestReaderAll(t *testing.T) {
dirname := "examples"
dir, err := os.Open(dirname)
if err != nil {
t.Fatalf("Open: %s", err)
}
defer func() {
if err := dir.Close(); err != nil {
t.Fatalf("dir.Close() error %s", err)
}
}()
all, err := dir.Readdirnames(0)
if err != nil {
t.Fatalf("Readdirnames: %s", err)
}
// filter now all file with the pattern "a*.lzma"
files := make([]string, 0, len(all))
for _, fn := range all {
match, err := filepath.Match("a*.lzma", fn)
if err != nil {
t.Fatalf("Match: %s", err)
}
if match {
files = append(files, fn)
}
}
t.Log("files:", files)
orig := readOrigFile(t)
// actually test the files
for _, fn := range files {
testDecodeFile(t, fn, orig)
}
}
//
func Example_reader() {
f, err := os.Open("fox.lzma")
if err != nil {
log.Fatal(err)
}
// no need for defer; Fatal calls os.Exit(1) that doesn't execute deferred functions
r, err := NewReader(bufio.NewReader(f))
if err != nil {
log.Fatal(err)
}
_, err = io.Copy(os.Stdout, r)
if err != nil {
log.Fatal(err)
}
if err := f.Close(); err != nil {
log.Fatal(err)
}
// Output:
// The quick brown fox jumps over the lazy dog.
}
type wrapTest struct {
name string
wrap func(io.Reader) io.Reader
}
func (w *wrapTest) testFile(t *testing.T, filename string, orig []byte) {
pathname := filepath.Join(dirname, filename)
f, err := os.Open(pathname)
if err != nil {
t.Fatalf("Open(\"%s\"): %s", pathname, err)
}
defer func() {
if err := f.Close(); err != nil {
log.Fatal(err)
}
}()
t.Logf("%s file %s opened", w.name, filename)
l, err := NewReader(w.wrap(f))
if err != nil {
t.Fatalf("%s NewReader: %s", w.name, err)
}
decoded, err := ioutil.ReadAll(l)
if err != nil {
t.Fatalf("%s ReadAll: %s", w.name, err)
}
t.Logf("%s", decoded)
if len(orig) != len(decoded) {
t.Fatalf("%s length decoded is %d; want %d",
w.name, len(decoded), len(orig))
}
if !bytes.Equal(orig, decoded) {
t.Fatalf("%s decoded file differs from original", w.name)
}
}
func TestReaderWrap(t *testing.T) {
tests := [...]wrapTest{
{"DataErrReader", iotest.DataErrReader},
{"HalfReader", iotest.HalfReader},
{"OneByteReader", iotest.OneByteReader},
// TimeOutReader would require buffer
}
orig := readOrigFile(t)
for _, tst := range tests {
tst.testFile(t, "a.lzma", orig)
}
}
func TestReaderBadFiles(t *testing.T) {
dirname := "examples"
dir, err := os.Open(dirname)
if err != nil {
t.Fatalf("Open: %s", err)
}
defer func() {
if err := dir.Close(); err != nil {
t.Fatalf("dir.Close() error %s", err)
}
}()
all, err := dir.Readdirnames(0)
if err != nil {
t.Fatalf("Readdirnames: %s", err)
}
// filter now all file with the pattern "bad*.lzma"
files := make([]string, 0, len(all))
for _, fn := range all {
match, err := filepath.Match("bad*.lzma", fn)
if err != nil {
t.Fatalf("Match: %s", err)
}
if match {
files = append(files, fn)
}
}
t.Log("files:", files)
for _, filename := range files {
pathname := filepath.Join(dirname, filename)
f, err := os.Open(pathname)
if err != nil {
t.Fatalf("Open(\"%s\"): %s", pathname, err)
}
defer func(f *os.File) {
if err := f.Close(); err != nil {
t.Fatalf("f.Close() error %s", err)
}
}(f)
t.Logf("file %s opened", filename)
l, err := NewReader(f)
if err != nil {
t.Fatalf("NewReader: %s", err)
}
decoded, err := ioutil.ReadAll(l)
if err == nil {
t.Errorf("ReadAll for %s: no error", filename)
t.Logf("%s", decoded)
continue
}
t.Logf("%s: error %s", filename, err)
}
}
type repReader byte
func (r repReader) Read(p []byte) (n int, err error) {
for i := range p {
p[i] = byte(r)
}
return len(p), nil
}
func newRepReader(c byte, n int64) *io.LimitedReader {
return &io.LimitedReader{R: repReader(c), N: n}
}
func newCodeReader(r io.Reader) *io.PipeReader {
pr, pw := io.Pipe()
go func() {
bw := bufio.NewWriter(pw)
lw, err := NewWriter(bw)
if err != nil {
log.Fatalf("NewWriter error %s", err)
}
if _, err = io.Copy(lw, r); err != nil {
log.Fatalf("io.Copy error %s", err)
}
if err = lw.Close(); err != nil {
log.Fatalf("lw.Close error %s", err)
}
if err = bw.Flush(); err != nil {
log.Fatalf("bw.Flush() error %s", err)
}
if err = pw.CloseWithError(io.EOF); err != nil {
log.Fatalf("pw.CloseWithError(io.EOF) error %s", err)
}
}()
return pr
}
func TestReaderErrAgain(t *testing.T) {
lengths := []int64{0, 128, 1024, 4095, 4096, 4097, 8191, 8192, 8193}
buf := make([]byte, 128)
const c = 'A'
for _, n := range lengths {
t.Logf("n: %d", n)
pr := newCodeReader(newRepReader(c, n))
r, err := NewReader(pr)
if err != nil {
t.Fatalf("NewReader(pr) error %s", err)
}
k := int64(0)
for {
m, err := r.Read(buf)
k += int64(m)
if err == io.EOF {
break
}
if err != nil {
t.Errorf("r.Read(buf) error %s", err)
break
}
if m > len(buf) {
t.Fatalf("r.Read(buf) %d; want <= %d", m,
len(buf))
}
for i, b := range buf[:m] {
if b != c {
t.Fatalf("buf[%d]=%c; want %c", i, b,
c)
}
}
}
if k != n {
t.Errorf("Read %d bytes; want %d", k, n)
}
}
}

View File

@@ -1,109 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. 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"
"math/rand"
"strings"
"testing"
"github.com/ulikunitz/xz/internal/randtxt"
)
func TestWriter2(t *testing.T) {
var buf bytes.Buffer
w, err := Writer2Config{DictCap: 4096}.NewWriter2(&buf)
if err != nil {
t.Fatalf("NewWriter error %s", err)
}
n, err := w.Write([]byte{'a'})
if err != nil {
t.Fatalf("w.Write([]byte{'a'}) error %s", err)
}
if n != 1 {
t.Fatalf("w.Write([]byte{'a'}) returned %d; want %d", n, 1)
}
if err = w.Flush(); err != nil {
t.Fatalf("w.Flush() error %s", err)
}
// check that double Flush doesn't write another chunk
if err = w.Flush(); err != nil {
t.Fatalf("w.Flush() error %s", err)
}
if err = w.Close(); err != nil {
t.Fatalf("w.Close() error %s", err)
}
p := buf.Bytes()
want := []byte{1, 0, 0, 'a', 0}
if !bytes.Equal(p, want) {
t.Fatalf("bytes written %#v; want %#v", p, want)
}
}
func TestCycle1(t *testing.T) {
var buf bytes.Buffer
w, err := Writer2Config{DictCap: 4096}.NewWriter2(&buf)
if err != nil {
t.Fatalf("NewWriter error %s", err)
}
n, err := w.Write([]byte{'a'})
if err != nil {
t.Fatalf("w.Write([]byte{'a'}) error %s", err)
}
if n != 1 {
t.Fatalf("w.Write([]byte{'a'}) returned %d; want %d", n, 1)
}
if err = w.Close(); err != nil {
t.Fatalf("w.Close() error %s", err)
}
r, err := Reader2Config{DictCap: 4096}.NewReader2(&buf)
if err != nil {
t.Fatalf("NewReader error %s", err)
}
p := make([]byte, 3)
n, err = r.Read(p)
t.Logf("n %d error %v", n, err)
}
func TestCycle2(t *testing.T) {
buf := new(bytes.Buffer)
w, err := Writer2Config{DictCap: 4096}.NewWriter2(buf)
if err != nil {
t.Fatalf("NewWriter error %s", err)
}
// const txtlen = 1024
const txtlen = 2100000
io.CopyN(buf, randtxt.NewReader(rand.NewSource(42)), txtlen)
txt := buf.String()
buf.Reset()
n, err := io.Copy(w, strings.NewReader(txt))
if err != nil {
t.Fatalf("Compressing copy error %s", err)
}
if n != txtlen {
t.Fatalf("Compressing data length %d; want %d", n, txtlen)
}
if err = w.Close(); err != nil {
t.Fatalf("w.Close error %s", err)
}
t.Logf("buf.Len() %d", buf.Len())
r, err := Reader2Config{DictCap: 4096}.NewReader2(buf)
if err != nil {
t.Fatalf("NewReader error %s", err)
}
out := new(bytes.Buffer)
n, err = io.Copy(out, r)
if err != nil {
t.Fatalf("Decompressing copy error %s after %d bytes", err, n)
}
if n != txtlen {
t.Fatalf("Decompression data length %d; want %d", n, txtlen)
}
if txt != out.String() {
t.Fatal("decompressed data differs from original")
}
}

View File

@@ -1,249 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. 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"
"bytes"
"io"
"io/ioutil"
"log"
"math/rand"
"os"
"testing"
"github.com/ulikunitz/xz/internal/randtxt"
)
func TestWriterCycle(t *testing.T) {
orig := readOrigFile(t)
buf := new(bytes.Buffer)
w, err := NewWriter(buf)
if err != nil {
t.Fatalf("NewWriter: error %s", err)
}
n, err := w.Write(orig)
if err != nil {
t.Fatalf("w.Write error %s", err)
}
if n != len(orig) {
t.Fatalf("w.Write returned %d; want %d", n, len(orig))
}
if err = w.Close(); err != nil {
t.Fatalf("w.Close error %s", err)
}
t.Logf("buf.Len() %d len(orig) %d", buf.Len(), len(orig))
if buf.Len() > len(orig) {
t.Errorf("buf.Len()=%d bigger then len(orig)=%d", buf.Len(),
len(orig))
}
lr, err := NewReader(buf)
if err != nil {
t.Fatalf("NewReader error %s", err)
}
decoded, err := ioutil.ReadAll(lr)
if err != nil {
t.Fatalf("ReadAll(lr) error %s", err)
}
t.Logf("%s", decoded)
if len(orig) != len(decoded) {
t.Fatalf("length decoded is %d; want %d", len(decoded),
len(orig))
}
if !bytes.Equal(orig, decoded) {
t.Fatalf("decoded file differs from original")
}
}
func TestWriterLongData(t *testing.T) {
const (
seed = 49
size = 82237
)
r := io.LimitReader(randtxt.NewReader(rand.NewSource(seed)), size)
txt, err := ioutil.ReadAll(r)
if err != nil {
t.Fatalf("ReadAll error %s", err)
}
if len(txt) != size {
t.Fatalf("ReadAll read %d bytes; want %d", len(txt), size)
}
buf := &bytes.Buffer{}
w, err := WriterConfig{DictCap: 0x4000}.NewWriter(buf)
if err != nil {
t.Fatalf("WriterConfig.NewWriter error %s", err)
}
n, err := w.Write(txt)
if err != nil {
t.Fatalf("w.Write error %s", err)
}
if n != len(txt) {
t.Fatalf("w.Write wrote %d bytes; want %d", n, size)
}
if err = w.Close(); err != nil {
t.Fatalf("w.Close error %s", err)
}
t.Logf("compressed length %d", buf.Len())
lr, err := NewReader(buf)
if err != nil {
t.Fatalf("NewReader error %s", err)
}
txtRead, err := ioutil.ReadAll(lr)
if err != nil {
t.Fatalf("ReadAll(lr) error %s", err)
}
if len(txtRead) != size {
t.Fatalf("ReadAll(lr) returned %d bytes; want %d",
len(txtRead), size)
}
if !bytes.Equal(txtRead, txt) {
t.Fatal("ReadAll(lr) returned txt differs from origin")
}
}
func TestWriter_Size(t *testing.T) {
buf := new(bytes.Buffer)
w, err := WriterConfig{Size: 10, EOSMarker: true}.NewWriter(buf)
if err != nil {
t.Fatalf("WriterConfig.NewWriter error %s", err)
}
q := []byte{'a'}
for i := 0; i < 9; i++ {
n, err := w.Write(q)
if err != nil {
t.Fatalf("w.Write error %s", err)
}
if n != 1 {
t.Fatalf("w.Write returned %d; want %d", n, 1)
}
q[0]++
}
if err := w.Close(); err != errSize {
t.Fatalf("expected errSize, but got %v", err)
}
n, err := w.Write(q)
if err != nil {
t.Fatalf("w.Write error %s", err)
}
if n != 1 {
t.Fatalf("w.Write returned %d; want %d", n, 1)
}
if err = w.Close(); err != nil {
t.Fatalf("w.Close error %s", err)
}
t.Logf("compressed size %d", buf.Len())
r, err := NewReader(buf)
if err != nil {
t.Fatalf("NewReader error %s", err)
}
b, err := ioutil.ReadAll(r)
if err != nil {
t.Fatalf("ReadAll error %s", err)
}
s := string(b)
want := "abcdefghij"
if s != want {
t.Fatalf("read %q, want %q", s, want)
}
}
// The example uses the buffered reader and writer from package bufio.
func Example_writer() {
pr, pw := io.Pipe()
go func() {
bw := bufio.NewWriter(pw)
w, err := NewWriter(bw)
if err != nil {
log.Fatal(err)
}
input := []byte("The quick brown fox jumps over the lazy dog.")
if _, err = w.Write(input); err != nil {
log.Fatal(err)
}
if err = w.Close(); err != nil {
log.Fatal(err)
}
// reader waits for the data
if err = bw.Flush(); err != nil {
log.Fatal(err)
}
}()
r, err := NewReader(pr)
if err != nil {
log.Fatal(err)
}
_, err = io.Copy(os.Stdout, r)
if err != nil {
log.Fatal(err)
}
// Output:
// The quick brown fox jumps over the lazy dog.
}
func BenchmarkReader(b *testing.B) {
const (
seed = 49
size = 50000
)
r := io.LimitReader(randtxt.NewReader(rand.NewSource(seed)), size)
txt, err := ioutil.ReadAll(r)
if err != nil {
b.Fatalf("ReadAll error %s", err)
}
buf := &bytes.Buffer{}
w, err := WriterConfig{DictCap: 0x4000}.NewWriter(buf)
if err != nil {
b.Fatalf("WriterConfig{}.NewWriter error %s", err)
}
if _, err = w.Write(txt); err != nil {
b.Fatalf("w.Write error %s", err)
}
if err = w.Close(); err != nil {
b.Fatalf("w.Close error %s", err)
}
data, err := ioutil.ReadAll(buf)
if err != nil {
b.Fatalf("ReadAll error %s", err)
}
b.SetBytes(int64(len(txt)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
lr, err := NewReader(bytes.NewReader(data))
if err != nil {
b.Fatalf("NewReader error %s", err)
}
if _, err = ioutil.ReadAll(lr); err != nil {
b.Fatalf("ReadAll(lr) error %s", err)
}
}
}
func BenchmarkWriter(b *testing.B) {
const (
seed = 49
size = 50000
)
r := io.LimitReader(randtxt.NewReader(rand.NewSource(seed)), size)
txt, err := ioutil.ReadAll(r)
if err != nil {
b.Fatalf("ReadAll error %s", err)
}
buf := &bytes.Buffer{}
b.SetBytes(int64(len(txt)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
buf.Reset()
w, err := WriterConfig{DictCap: 0x4000}.NewWriter(buf)
if err != nil {
b.Fatalf("NewWriter error %s", err)
}
if _, err = w.Write(txt); err != nil {
b.Fatalf("w.Write error %s", err)
}
if err = w.Close(); err != nil {
b.Fatalf("w.Close error %s", err)
}
}
}

View File

@@ -1,5 +0,0 @@
#!/bin/sh
set -x
pandoc -t html5 -f markdown -s --css=doc/md.css -o README.html README.md
pandoc -t html5 -f markdown -s --css=doc/md.css -o TODO.html TODO.md

View File

@@ -1,81 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xz
import (
"bytes"
"io"
"io/ioutil"
"os"
"testing"
)
func TestReaderSimple(t *testing.T) {
const file = "fox.xz"
xz, err := os.Open(file)
if err != nil {
t.Fatalf("os.Open(%q) error %s", file, err)
}
r, err := NewReader(xz)
if err != nil {
t.Fatalf("NewReader error %s", err)
}
var buf bytes.Buffer
if _, err = io.Copy(&buf, r); err != nil {
t.Fatalf("io.Copy error %s", err)
}
}
func TestReaderSingleStream(t *testing.T) {
data, err := ioutil.ReadFile("fox.xz")
if err != nil {
t.Fatalf("ReadFile error %s", err)
}
xz := bytes.NewReader(data)
rc := ReaderConfig{SingleStream: true}
r, err := rc.NewReader(xz)
if err != nil {
t.Fatalf("NewReader error %s", err)
}
var buf bytes.Buffer
if _, err = io.Copy(&buf, r); err != nil {
t.Fatalf("io.Copy error %s", err)
}
buf.Reset()
data = append(data, 0)
xz = bytes.NewReader(data)
r, err = rc.NewReader(xz)
if err != nil {
t.Fatalf("NewReader error %s", err)
}
if _, err = io.Copy(&buf, r); err != errUnexpectedData {
t.Fatalf("io.Copy returned %v; want %v", err, errUnexpectedData)
}
}
func TestReaaderMultipleStreams(t *testing.T) {
data, err := ioutil.ReadFile("fox.xz")
if err != nil {
t.Fatalf("ReadFile error %s", err)
}
m := make([]byte, 0, 4*len(data)+4*4)
m = append(m, data...)
m = append(m, data...)
m = append(m, 0, 0, 0, 0)
m = append(m, data...)
m = append(m, 0, 0, 0, 0)
m = append(m, 0, 0, 0, 0)
m = append(m, data...)
m = append(m, 0, 0, 0, 0)
xz := bytes.NewReader(m)
r, err := NewReader(xz)
if err != nil {
t.Fatalf("NewReader error %s", err)
}
var buf bytes.Buffer
if _, err = io.Copy(&buf, r); err != nil {
t.Fatalf("io.Copy error %s", err)
}
}

View File

@@ -1,138 +0,0 @@
// Copyright 2014-2017 Ulrich Kunitz. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xz
import (
"bytes"
"io"
"log"
"math/rand"
"os"
"testing"
"github.com/ulikunitz/xz/internal/randtxt"
)
func TestWriter(t *testing.T) {
const text = "The quick brown fox jumps over the lazy dog."
var buf bytes.Buffer
w, err := NewWriter(&buf)
if err != nil {
t.Fatalf("NewWriter error %s", err)
}
n, err := io.WriteString(w, text)
if err != nil {
t.Fatalf("WriteString error %s", err)
}
if n != len(text) {
t.Fatalf("Writestring wrote %d bytes; want %d", n, len(text))
}
if err = w.Close(); err != nil {
t.Fatalf("w.Close error %s", err)
}
var out bytes.Buffer
r, err := NewReader(&buf)
if err != nil {
t.Fatalf("NewReader error %s", err)
}
if _, err = io.Copy(&out, r); err != nil {
t.Fatalf("io.Copy error %s", err)
}
s := out.String()
if s != text {
t.Fatalf("reader decompressed to %q; want %q", s, text)
}
}
func TestIssue12(t *testing.T) {
var buf bytes.Buffer
w, err := NewWriter(&buf)
if err != nil {
t.Fatalf("NewWriter error %s", err)
}
if err = w.Close(); err != nil {
t.Fatalf("w.Close error %s", err)
}
r, err := NewReader(&buf)
if err != nil {
t.Fatalf("NewReader error %s", err)
}
var out bytes.Buffer
if _, err = io.Copy(&out, r); err != nil {
t.Fatalf("io.Copy error %s", err)
}
s := out.String()
if s != "" {
t.Fatalf("reader decompressed to %q; want %q", s, "")
}
}
func Example() {
const text = "The quick brown fox jumps over the lazy dog."
var buf bytes.Buffer
// compress text
w, err := NewWriter(&buf)
if err != nil {
log.Fatalf("NewWriter error %s", err)
}
if _, err := io.WriteString(w, text); err != nil {
log.Fatalf("WriteString error %s", err)
}
if err := w.Close(); err != nil {
log.Fatalf("w.Close error %s", err)
}
// decompress buffer and write result to stdout
r, err := NewReader(&buf)
if err != nil {
log.Fatalf("NewReader error %s", err)
}
if _, err = io.Copy(os.Stdout, r); err != nil {
log.Fatalf("io.Copy error %s", err)
}
// Output:
// The quick brown fox jumps over the lazy dog.
}
func TestWriter2(t *testing.T) {
const txtlen = 1023
var buf bytes.Buffer
io.CopyN(&buf, randtxt.NewReader(rand.NewSource(41)), txtlen)
txt := buf.String()
buf.Reset()
w, err := NewWriter(&buf)
if err != nil {
t.Fatalf("NewWriter error %s", err)
}
n, err := io.WriteString(w, txt)
if err != nil {
t.Fatalf("WriteString error %s", err)
}
if n != len(txt) {
t.Fatalf("WriteString wrote %d bytes; want %d", n, len(txt))
}
if err = w.Close(); err != nil {
t.Fatalf("Close error %s", err)
}
t.Logf("buf.Len() %d", buf.Len())
r, err := NewReader(&buf)
if err != nil {
t.Fatalf("NewReader error %s", err)
}
var out bytes.Buffer
k, err := io.Copy(&out, r)
if err != nil {
t.Fatalf("Decompressing copy error %s after %d bytes", err, n)
}
if k != txtlen {
t.Fatalf("Decompression data length %d; want %d", k, txtlen)
}
if txt != out.String() {
t.Fatal("decompressed data differs from original")
}
}