init
This commit is contained in:
115
internal/hashutil/crc16/crc16.go
Executable file
115
internal/hashutil/crc16/crc16.go
Executable file
@@ -0,0 +1,115 @@
|
||||
// Copyright 2013 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 crc16 implements the 16-bit cyclic redundancy check, or CRC-16,
|
||||
// checksum. See http://en.wikipedia.org/wiki/Cyclic_redundancy_check and
|
||||
// http://www.ross.net/crc/download/crc_v3.txt for information.
|
||||
package crc16
|
||||
|
||||
import "github.com/mewkiz/flac/internal/hashutil"
|
||||
|
||||
// Size of a CRC-16 checksum in bytes.
|
||||
const Size = 2
|
||||
|
||||
// Predefined polynomials.
|
||||
const (
|
||||
IBM = 0x8005 // x^16 + x^15 + x^2 + x^0
|
||||
)
|
||||
|
||||
// Table is a 256-word table representing the polynomial for efficient
|
||||
// processing.
|
||||
type Table [256]uint16
|
||||
|
||||
// IBMTable is the table for the IBM polynomial.
|
||||
var IBMTable = makeTable(IBM)
|
||||
|
||||
// MakeTable returns the Table constructed from the specified polynomial.
|
||||
func MakeTable(poly uint16) (table *Table) {
|
||||
switch poly {
|
||||
case IBM:
|
||||
return IBMTable
|
||||
}
|
||||
return makeTable(poly)
|
||||
}
|
||||
|
||||
// makeTable returns the Table constructed from the specified polynomial.
|
||||
func makeTable(poly uint16) (table *Table) {
|
||||
table = new(Table)
|
||||
for i := range table {
|
||||
crc := uint16(i << 8)
|
||||
for j := 0; j < 8; j++ {
|
||||
if crc&0x8000 != 0 {
|
||||
crc = crc<<1 ^ poly
|
||||
} else {
|
||||
crc <<= 1
|
||||
}
|
||||
}
|
||||
table[i] = crc
|
||||
}
|
||||
return table
|
||||
}
|
||||
|
||||
// digest represents the partial evaluation of a checksum.
|
||||
type digest struct {
|
||||
crc uint16
|
||||
table *Table
|
||||
}
|
||||
|
||||
// New creates a new hashutil.Hash16 computing the CRC-16 checksum using the
|
||||
// polynomial represented by the Table.
|
||||
func New(table *Table) hashutil.Hash16 {
|
||||
return &digest{0, table}
|
||||
}
|
||||
|
||||
// NewIBM creates a new hashutil.Hash16 computing the CRC-16 checksum using the
|
||||
// IBM polynomial.
|
||||
func NewIBM() hashutil.Hash16 {
|
||||
return New(IBMTable)
|
||||
}
|
||||
|
||||
func (d *digest) Size() int {
|
||||
return Size
|
||||
}
|
||||
|
||||
func (d *digest) BlockSize() int {
|
||||
return 1
|
||||
}
|
||||
|
||||
func (d *digest) Reset() {
|
||||
d.crc = 0
|
||||
}
|
||||
|
||||
// Update returns the result of adding the bytes in p to the crc.
|
||||
func Update(crc uint16, table *Table, p []byte) uint16 {
|
||||
for _, v := range p {
|
||||
crc = crc<<8 ^ table[crc>>8^uint16(v)]
|
||||
}
|
||||
return crc
|
||||
}
|
||||
|
||||
func (d *digest) Write(p []byte) (n int, err error) {
|
||||
d.crc = Update(d.crc, d.table, p)
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// Sum16 returns the 16-bit checksum of the hash.
|
||||
func (d *digest) Sum16() uint16 {
|
||||
return d.crc
|
||||
}
|
||||
|
||||
func (d *digest) Sum(in []byte) []byte {
|
||||
s := d.Sum16()
|
||||
return append(in, byte(s>>8), byte(s))
|
||||
}
|
||||
|
||||
// Checksum returns the CRC-16 checksum of data, using the polynomial
|
||||
// represented by the Table.
|
||||
func Checksum(data []byte, table *Table) uint16 {
|
||||
return Update(0, table, data)
|
||||
}
|
||||
|
||||
// ChecksumIBM returns the CRC-16 checksum of data using the IBM polynomial.
|
||||
func ChecksumIBM(data []byte) uint16 {
|
||||
return Update(0, IBMTable, data)
|
||||
}
|
106
internal/hashutil/crc16/crc16_test.go
Executable file
106
internal/hashutil/crc16/crc16_test.go
Executable file
@@ -0,0 +1,106 @@
|
||||
package crc16
|
||||
|
||||
import (
|
||||
"io"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type test struct {
|
||||
want uint16
|
||||
in string
|
||||
}
|
||||
|
||||
var golden = []test{
|
||||
{0x0000, ""},
|
||||
{0x8145, "a"},
|
||||
{0xC749, "ab"},
|
||||
{0xCADB, "abc"},
|
||||
{0x58E7, "abcd"},
|
||||
{0x678D, "abcde"},
|
||||
{0x0D05, "abcdef"},
|
||||
{0x047C, "abcdefg"},
|
||||
{0x7D68, "abcdefgh"},
|
||||
{0x6878, "abcdefghi"},
|
||||
{0xF80F, "abcdefghij"},
|
||||
{0x0F8E, "Discard medicine more than two years old."},
|
||||
{0xE149, "He who has a shady past knows that nice guys finish last."},
|
||||
{0x02B7, "I wouldn't marry him with a ten foot pole."},
|
||||
{0x7F6A, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
|
||||
{0x28BD, "The days of the digital watch are numbered. -Tom Stoppard"},
|
||||
{0x7C55, "Nepal premier won't resign."},
|
||||
{0xC92B, "For every action there is an equal and opposite government program."},
|
||||
{0x3E41, "His money is twice tainted: 'taint yours and 'taint mine."},
|
||||
{0xDA56, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
|
||||
{0x7F66, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
|
||||
{0x2A00, "size: a.out: bad magic"},
|
||||
{0x25B2, "The major problem is with sendmail. -Mark Horton"},
|
||||
{0xBD71, "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
|
||||
{0x8596, "If the enemy is within range, then so are you."},
|
||||
{0x74A2, "It's well we cannot hear the screams/That we create in others' dreams."},
|
||||
{0x0D73, "You remind me of a TV show, but that's all right: I watch it anyway."},
|
||||
{0xEE65, "C is as portable as Stonehedge!!"},
|
||||
{0xA94E, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
|
||||
{0x0B98, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
|
||||
{0xF560, "How can you write a big system without C++? -Paul Glick"},
|
||||
{0x60AE, "The quick brown fox jumps over the lazy dog"},
|
||||
}
|
||||
|
||||
func TestCrc16IBM(t *testing.T) {
|
||||
for _, g := range golden {
|
||||
h := NewIBM()
|
||||
if _, err := io.WriteString(h, g.in); err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
got := h.Sum16()
|
||||
if got != g.want {
|
||||
t.Errorf("IBM(%q); expected 0x%04X, got 0x%04X.", g.in, g.want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkNewIBM(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
NewIBM()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCrc16_1K(b *testing.B) {
|
||||
benchmarkCrc16(b, 1024)
|
||||
}
|
||||
|
||||
func BenchmarkCrc16_2K(b *testing.B) {
|
||||
benchmarkCrc16(b, 2*1024)
|
||||
}
|
||||
|
||||
func BenchmarkCrc16_4K(b *testing.B) {
|
||||
benchmarkCrc16(b, 4*1024)
|
||||
}
|
||||
|
||||
func BenchmarkCrc16_8K(b *testing.B) {
|
||||
benchmarkCrc16(b, 8*1024)
|
||||
}
|
||||
|
||||
func BenchmarkCrc16_16K(b *testing.B) {
|
||||
benchmarkCrc16(b, 16*1024)
|
||||
}
|
||||
|
||||
func benchmarkCrc16(b *testing.B, count int64) {
|
||||
b.SetBytes(count)
|
||||
data := make([]byte, count)
|
||||
for i := range data {
|
||||
data[i] = byte(i)
|
||||
}
|
||||
h := NewIBM()
|
||||
in := make([]byte, 0, h.Size())
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
h.Reset()
|
||||
if _, err := h.Write(data); err != nil {
|
||||
b.Error(err)
|
||||
continue
|
||||
}
|
||||
h.Sum(in)
|
||||
}
|
||||
}
|
114
internal/hashutil/crc8/crc8.go
Executable file
114
internal/hashutil/crc8/crc8.go
Executable file
@@ -0,0 +1,114 @@
|
||||
// Copyright 2012 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 crc8 implements the 8-bit cyclic redundancy check, or CRC-8,
|
||||
// checksum. See http://en.wikipedia.org/wiki/Cyclic_redundancy_check and
|
||||
// http://www.ross.net/crc/download/crc_v3.txt for information.
|
||||
package crc8
|
||||
|
||||
import "github.com/mewkiz/flac/internal/hashutil"
|
||||
|
||||
// Size of a CRC-8 checksum in bytes.
|
||||
const Size = 1
|
||||
|
||||
// Predefined polynomials.
|
||||
const (
|
||||
ATM = 0x07 // x^8 + x^2 + x + 1
|
||||
)
|
||||
|
||||
// Table is a 256-word table representing the polynomial for efficient
|
||||
// processing.
|
||||
type Table [256]uint8
|
||||
|
||||
// ATMTable is the table for the ATM polynomial.
|
||||
var ATMTable = makeTable(ATM)
|
||||
|
||||
// MakeTable returns the Table constructed from the specified polynomial.
|
||||
func MakeTable(poly uint8) (table *Table) {
|
||||
switch poly {
|
||||
case ATM:
|
||||
return ATMTable
|
||||
}
|
||||
return makeTable(poly)
|
||||
}
|
||||
|
||||
// makeTable returns the Table constructed from the specified polynomial.
|
||||
func makeTable(poly uint8) (table *Table) {
|
||||
table = new(Table)
|
||||
for i := range table {
|
||||
crc := uint8(i)
|
||||
for j := 0; j < 8; j++ {
|
||||
if crc&0x80 != 0 {
|
||||
crc = crc<<1 ^ poly
|
||||
} else {
|
||||
crc <<= 1
|
||||
}
|
||||
}
|
||||
table[i] = crc
|
||||
}
|
||||
return table
|
||||
}
|
||||
|
||||
// digest represents the partial evaluation of a checksum.
|
||||
type digest struct {
|
||||
crc uint8
|
||||
table *Table
|
||||
}
|
||||
|
||||
// New creates a new hashutil.Hash8 computing the CRC-8 checksum using the
|
||||
// polynomial represented by the Table.
|
||||
func New(table *Table) hashutil.Hash8 {
|
||||
return &digest{0, table}
|
||||
}
|
||||
|
||||
// NewATM creates a new hashutil.Hash8 computing the CRC-8 checksum using the
|
||||
// ATM polynomial.
|
||||
func NewATM() hashutil.Hash8 {
|
||||
return New(ATMTable)
|
||||
}
|
||||
|
||||
func (d *digest) Size() int {
|
||||
return Size
|
||||
}
|
||||
|
||||
func (d *digest) BlockSize() int {
|
||||
return 1
|
||||
}
|
||||
|
||||
func (d *digest) Reset() {
|
||||
d.crc = 0
|
||||
}
|
||||
|
||||
// Update returns the result of adding the bytes in p to the crc.
|
||||
func Update(crc uint8, table *Table, p []byte) uint8 {
|
||||
for _, v := range p {
|
||||
crc = table[crc^v]
|
||||
}
|
||||
return crc
|
||||
}
|
||||
|
||||
func (d *digest) Write(p []byte) (n int, err error) {
|
||||
d.crc = Update(d.crc, d.table, p)
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// Sum8 returns the 8-bit checksum of the hash.
|
||||
func (d *digest) Sum8() uint8 {
|
||||
return d.crc
|
||||
}
|
||||
|
||||
func (d *digest) Sum(in []byte) []byte {
|
||||
return append(in, d.crc)
|
||||
}
|
||||
|
||||
// Checksum returns the CRC-8 checksum of data, using the polynomial represented
|
||||
// by the Table.
|
||||
func Checksum(data []byte, table *Table) uint8 {
|
||||
return Update(0, table, data)
|
||||
}
|
||||
|
||||
// ChecksumATM returns the CRC-8 checksum of data using the ATM polynomial.
|
||||
func ChecksumATM(data []byte) uint8 {
|
||||
return Update(0, ATMTable, data)
|
||||
}
|
106
internal/hashutil/crc8/crc8_test.go
Executable file
106
internal/hashutil/crc8/crc8_test.go
Executable file
@@ -0,0 +1,106 @@
|
||||
package crc8
|
||||
|
||||
import (
|
||||
"io"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type test struct {
|
||||
want uint8
|
||||
in string
|
||||
}
|
||||
|
||||
var golden = []test{
|
||||
{0x00, ""},
|
||||
{0x20, "a"},
|
||||
{0xC9, "ab"},
|
||||
{0x5F, "abc"},
|
||||
{0xA1, "abcd"},
|
||||
{0x52, "abcde"},
|
||||
{0x8C, "abcdef"},
|
||||
{0x9F, "abcdefg"},
|
||||
{0xCB, "abcdefgh"},
|
||||
{0x67, "abcdefghi"},
|
||||
{0x23, "abcdefghij"},
|
||||
{0x56, "Discard medicine more than two years old."},
|
||||
{0x6B, "He who has a shady past knows that nice guys finish last."},
|
||||
{0x70, "I wouldn't marry him with a ten foot pole."},
|
||||
{0x8F, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
|
||||
{0x48, "The days of the digital watch are numbered. -Tom Stoppard"},
|
||||
{0x5E, "Nepal premier won't resign."},
|
||||
{0x3C, "For every action there is an equal and opposite government program."},
|
||||
{0xA8, "His money is twice tainted: 'taint yours and 'taint mine."},
|
||||
{0x46, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
|
||||
{0xC7, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
|
||||
{0x31, "size: a.out: bad magic"},
|
||||
{0xB6, "The major problem is with sendmail. -Mark Horton"},
|
||||
{0x7D, "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
|
||||
{0xDC, "If the enemy is within range, then so are you."},
|
||||
{0x13, "It's well we cannot hear the screams/That we create in others' dreams."},
|
||||
{0x96, "You remind me of a TV show, but that's all right: I watch it anyway."},
|
||||
{0x96, "C is as portable as Stonehedge!!"},
|
||||
{0x3C, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
|
||||
{0xEE, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
|
||||
{0x33, "How can you write a big system without C++? -Paul Glick"},
|
||||
{0xC1, "The quick brown fox jumps over the lazy dog"},
|
||||
}
|
||||
|
||||
func TestCrc8ATM(t *testing.T) {
|
||||
for _, g := range golden {
|
||||
h := NewATM()
|
||||
if _, err := io.WriteString(h, g.in); err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
got := h.Sum8()
|
||||
if got != g.want {
|
||||
t.Errorf("ATM(%q); expected 0x%02X, got 0x%02X.", g.in, g.want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkNewATM(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
NewATM()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCrc8_1K(b *testing.B) {
|
||||
benchmarkCrc8(b, 1024)
|
||||
}
|
||||
|
||||
func BenchmarkCrc8_2K(b *testing.B) {
|
||||
benchmarkCrc8(b, 2*1024)
|
||||
}
|
||||
|
||||
func BenchmarkCrc8_4K(b *testing.B) {
|
||||
benchmarkCrc8(b, 4*1024)
|
||||
}
|
||||
|
||||
func BenchmarkCrc8_8K(b *testing.B) {
|
||||
benchmarkCrc8(b, 8*1024)
|
||||
}
|
||||
|
||||
func BenchmarkCrc8_16K(b *testing.B) {
|
||||
benchmarkCrc8(b, 16*1024)
|
||||
}
|
||||
|
||||
func benchmarkCrc8(b *testing.B, count int64) {
|
||||
b.SetBytes(count)
|
||||
data := make([]byte, count)
|
||||
for i := range data {
|
||||
data[i] = byte(i)
|
||||
}
|
||||
h := NewATM()
|
||||
in := make([]byte, 0, h.Size())
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
h.Reset()
|
||||
if _, err := h.Write(data); err != nil {
|
||||
b.Error(err)
|
||||
continue
|
||||
}
|
||||
h.Sum(in)
|
||||
}
|
||||
}
|
18
internal/hashutil/hashutil.go
Executable file
18
internal/hashutil/hashutil.go
Executable file
@@ -0,0 +1,18 @@
|
||||
// Package hashutil provides utility interfaces for hash functions.
|
||||
package hashutil
|
||||
|
||||
import "hash"
|
||||
|
||||
// Hash8 is the common interface implemented by all 8-bit hash functions.
|
||||
type Hash8 interface {
|
||||
hash.Hash
|
||||
// Sum8 returns the 8-bit checksum of the hash.
|
||||
Sum8() uint8
|
||||
}
|
||||
|
||||
// Hash16 is the common interface implemented by all 16-bit hash functions.
|
||||
type Hash16 interface {
|
||||
hash.Hash
|
||||
// Sum16 returns the 16-bit checksum of the hash.
|
||||
Sum16() uint16
|
||||
}
|
Reference in New Issue
Block a user