OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [compress/] [lzw/] [writer.go] - Rev 774

Go to most recent revision | Compare with Previous | Blame | View Log

// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package lzw

import (
        "bufio"
        "errors"
        "fmt"
        "io"
)

// A writer is a buffered, flushable writer.
type writer interface {
        WriteByte(byte) error
        Flush() error
}

// An errWriteCloser is an io.WriteCloser that always returns a given error.
type errWriteCloser struct {
        err error
}

func (e *errWriteCloser) Write([]byte) (int, error) {
        return 0, e.err
}

func (e *errWriteCloser) Close() error {
        return e.err
}

const (
        // A code is a 12 bit value, stored as a uint32 when encoding to avoid
        // type conversions when shifting bits.
        maxCode     = 1<<12 - 1
        invalidCode = 1<<32 - 1
        // There are 1<<12 possible codes, which is an upper bound on the number of
        // valid hash table entries at any given point in time. tableSize is 4x that.
        tableSize = 4 * 1 << 12
        tableMask = tableSize - 1
        // A hash table entry is a uint32. Zero is an invalid entry since the
        // lower 12 bits of a valid entry must be a non-literal code.
        invalidEntry = 0
)

// encoder is LZW compressor.
type encoder struct {
        // w is the writer that compressed bytes are written to.
        w writer
        // order, write, bits, nBits and width are the state for
        // converting a code stream into a byte stream.
        order Order
        write func(*encoder, uint32) error
        bits  uint32
        nBits uint
        width uint
        // litWidth is the width in bits of literal codes.
        litWidth uint
        // hi is the code implied by the next code emission.
        // overflow is the code at which hi overflows the code width.
        hi, overflow uint32
        // savedCode is the accumulated code at the end of the most recent Write
        // call. It is equal to invalidCode if there was no such call.
        savedCode uint32
        // err is the first error encountered during writing. Closing the encoder
        // will make any future Write calls return errClosed
        err error
        // table is the hash table from 20-bit keys to 12-bit values. Each table
        // entry contains key<<12|val and collisions resolve by linear probing.
        // The keys consist of a 12-bit code prefix and an 8-bit byte suffix.
        // The values are a 12-bit code.
        table [tableSize]uint32
}

// writeLSB writes the code c for "Least Significant Bits first" data.
func (e *encoder) writeLSB(c uint32) error {
        e.bits |= c << e.nBits
        e.nBits += e.width
        for e.nBits >= 8 {
                if err := e.w.WriteByte(uint8(e.bits)); err != nil {
                        return err
                }
                e.bits >>= 8
                e.nBits -= 8
        }
        return nil
}

// writeMSB writes the code c for "Most Significant Bits first" data.
func (e *encoder) writeMSB(c uint32) error {
        e.bits |= c << (32 - e.width - e.nBits)
        e.nBits += e.width
        for e.nBits >= 8 {
                if err := e.w.WriteByte(uint8(e.bits >> 24)); err != nil {
                        return err
                }
                e.bits <<= 8
                e.nBits -= 8
        }
        return nil
}

// errOutOfCodes is an internal error that means that the encoder has run out
// of unused codes and a clear code needs to be sent next.
var errOutOfCodes = errors.New("lzw: out of codes")

// incHi increments e.hi and checks for both overflow and running out of
// unused codes. In the latter case, incHi sends a clear code, resets the
// encoder state and returns errOutOfCodes.
func (e *encoder) incHi() error {
        e.hi++
        if e.hi == e.overflow {
                e.width++
                e.overflow <<= 1
        }
        if e.hi == maxCode {
                clear := uint32(1) << e.litWidth
                if err := e.write(e, clear); err != nil {
                        return err
                }
                e.width = uint(e.litWidth) + 1
                e.hi = clear + 1
                e.overflow = clear << 1
                for i := range e.table {
                        e.table[i] = invalidEntry
                }
                return errOutOfCodes
        }
        return nil
}

// Write writes a compressed representation of p to e's underlying writer.
func (e *encoder) Write(p []byte) (int, error) {
        if e.err != nil {
                return 0, e.err
        }
        if len(p) == 0 {
                return 0, nil
        }
        litMask := uint32(1<<e.litWidth - 1)
        code := e.savedCode
        if code == invalidCode {
                // The first code sent is always a literal code.
                code, p = uint32(p[0])&litMask, p[1:]
        }
loop:
        for _, x := range p {
                literal := uint32(x) & litMask
                key := code<<8 | literal
                // If there is a hash table hit for this key then we continue the loop
                // and do not emit a code yet.
                hash := (key>>12 ^ key) & tableMask
                for h, t := hash, e.table[hash]; t != invalidEntry; {
                        if key == t>>12 {
                                code = t & maxCode
                                continue loop
                        }
                        h = (h + 1) & tableMask
                        t = e.table[h]
                }
                // Otherwise, write the current code, and literal becomes the start of
                // the next emitted code.
                if e.err = e.write(e, code); e.err != nil {
                        return 0, e.err
                }
                code = literal
                // Increment e.hi, the next implied code. If we run out of codes, reset
                // the encoder state (including clearing the hash table) and continue.
                if err := e.incHi(); err != nil {
                        if err == errOutOfCodes {
                                continue
                        }
                        e.err = err
                        return 0, e.err
                }
                // Otherwise, insert key -> e.hi into the map that e.table represents.
                for {
                        if e.table[hash] == invalidEntry {
                                e.table[hash] = (key << 12) | e.hi
                                break
                        }
                        hash = (hash + 1) & tableMask
                }
        }
        e.savedCode = code
        return len(p), nil
}

// Close closes the encoder, flushing any pending output. It does not close or
// flush e's underlying writer.
func (e *encoder) Close() error {
        if e.err != nil {
                if e.err == errClosed {
                        return nil
                }
                return e.err
        }
        // Make any future calls to Write return errClosed.
        e.err = errClosed
        // Write the savedCode if valid.
        if e.savedCode != invalidCode {
                if err := e.write(e, e.savedCode); err != nil {
                        return err
                }
                if err := e.incHi(); err != nil && err != errOutOfCodes {
                        return err
                }
        }
        // Write the eof code.
        eof := uint32(1)<<e.litWidth + 1
        if err := e.write(e, eof); err != nil {
                return err
        }
        // Write the final bits.
        if e.nBits > 0 {
                if e.order == MSB {
                        e.bits >>= 24
                }
                if err := e.w.WriteByte(uint8(e.bits)); err != nil {
                        return err
                }
        }
        return e.w.Flush()
}

// NewWriter creates a new io.WriteCloser that satisfies writes by compressing
// the data and writing it to w.
// It is the caller's responsibility to call Close on the WriteCloser when
// finished writing.
// The number of bits to use for literal codes, litWidth, must be in the
// range [2,8] and is typically 8.
func NewWriter(w io.Writer, order Order, litWidth int) io.WriteCloser {
        var write func(*encoder, uint32) error
        switch order {
        case LSB:
                write = (*encoder).writeLSB
        case MSB:
                write = (*encoder).writeMSB
        default:
                return &errWriteCloser{errors.New("lzw: unknown order")}
        }
        if litWidth < 2 || 8 < litWidth {
                return &errWriteCloser{fmt.Errorf("lzw: litWidth %d out of range", litWidth)}
        }
        bw, ok := w.(writer)
        if !ok {
                bw = bufio.NewWriter(w)
        }
        lw := uint(litWidth)
        return &encoder{
                w:         bw,
                order:     order,
                write:     write,
                width:     1 + lw,
                litWidth:  lw,
                hi:        1<<lw + 1,
                overflow:  1 << (lw + 1),
                savedCode: invalidCode,
        }
}

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.