Inital commit
This commit is contained in:
commit
9609819393
9
element.go
Normal file
9
element.go
Normal file
|
@ -0,0 +1,9 @@
|
|||
package ebml
|
||||
|
||||
import "io"
|
||||
|
||||
type Element struct {
|
||||
ID uint32
|
||||
Size uint64
|
||||
Data io.Reader
|
||||
}
|
17
encoder.go
Normal file
17
encoder.go
Normal file
|
@ -0,0 +1,17 @@
|
|||
package ebml
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
)
|
||||
|
||||
// An Encoder writes EBML data to an output stream.
|
||||
type Encoder struct {
|
||||
*bufio.Writer
|
||||
}
|
||||
|
||||
// NewEncoder returns a new encoder that writes to w.
|
||||
func NewEncoder(w io.Writer) *Encoder {
|
||||
return &Encoder{Writer: bufio.NewWriter(w)}
|
||||
}
|
||||
|
44
id.go
Normal file
44
id.go
Normal file
|
@ -0,0 +1,44 @@
|
|||
package ebml
|
||||
|
||||
func (e *Encoder) EncodeID(x uint32) (err error) {
|
||||
var buf []byte
|
||||
switch {
|
||||
case x == 0:
|
||||
_, err = e.Write([]byte{byte(0)})
|
||||
return err
|
||||
|
||||
case x < 127:
|
||||
b := byte(x)
|
||||
buf = []byte{b | 0x80}
|
||||
|
||||
case x < 16383:
|
||||
buf = make([]byte, 2)
|
||||
buf[1] = byte(x)
|
||||
x >>= 8
|
||||
buf[0] = byte(x) | 0x40
|
||||
|
||||
case x < 2097151:
|
||||
buf = make([]byte, 3)
|
||||
buf[2] = byte(x)
|
||||
x >>= 8
|
||||
buf[1] = byte(x)
|
||||
x >>= 8
|
||||
buf[0] = byte(x) | 0x20
|
||||
|
||||
case x < 268435455:
|
||||
buf = make([]byte, 4)
|
||||
buf[3] = byte(x)
|
||||
x >>= 8
|
||||
buf[2] = byte(x)
|
||||
x >>= 8
|
||||
buf[1] = byte(x)
|
||||
x >>= 8
|
||||
buf[0] = byte(x) | 0x10
|
||||
|
||||
default:
|
||||
panic("element ID overflow")
|
||||
}
|
||||
|
||||
_, err = e.Write(buf)
|
||||
return
|
||||
}
|
48
id_test.go
Normal file
48
id_test.go
Normal file
|
@ -0,0 +1,48 @@
|
|||
package ebml
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var goldenIDs = []struct {
|
||||
in uint32
|
||||
out []byte
|
||||
}{
|
||||
{0, []byte{0}},
|
||||
{1, []byte{129}},
|
||||
{127, []byte{64, 127}},
|
||||
{128, []byte{64, 128}},
|
||||
{256, []byte{65, 0}},
|
||||
{16382, []byte{127, 254}},
|
||||
{16383, []byte{32, 63, 255}},
|
||||
{16384, []byte{32, 64, 0}},
|
||||
{16385, []byte{32, 64, 1}},
|
||||
{32768, []byte{32, 128, 0}},
|
||||
{2097150, []byte{63, 255, 254}},
|
||||
{2097151, []byte{16, 31, 255, 255}},
|
||||
{2097152, []byte{16, 32, 0, 0}},
|
||||
{268435453, []byte{31, 255, 255, 253}},
|
||||
{268435454, []byte{31, 255, 255, 254}},
|
||||
}
|
||||
|
||||
func TestGoldenIDs(t *testing.T) {
|
||||
for _, g := range goldenIDs {
|
||||
buf := new(bytes.Buffer)
|
||||
enc := NewEncoder(buf)
|
||||
enc.EncodeID(g.in)
|
||||
enc.Flush()
|
||||
got := buf.Bytes()
|
||||
if !bytes.Equal(got, g.out) {
|
||||
t.Errorf("failed to marshal ID %d, wanted %v, got %v", g.in, g.out, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncodeID(b *testing.B) {
|
||||
enc := NewEncoder(ioutil.Discard)
|
||||
for i := 0; i < b.N; i++ {
|
||||
enc.EncodeID(uint32(i))
|
||||
}
|
||||
}
|
85
size.go
Normal file
85
size.go
Normal file
|
@ -0,0 +1,85 @@
|
|||
package ebml
|
||||
|
||||
const (
|
||||
o1 = 1<<7 - 2
|
||||
o2 = 1<<14 - 2
|
||||
o3 = 1<<21 - 2
|
||||
o4 = 1<<28 - 2
|
||||
o5 = 1<<35 - 2
|
||||
o6 = 1<<42 - 2
|
||||
o7 = 1<<49 - 2
|
||||
o8 = 1<<56 - 2
|
||||
)
|
||||
|
||||
func (e *Encoder) EncodeSize(x uint64) (err error) {
|
||||
var buf []byte
|
||||
switch {
|
||||
case x == 0:
|
||||
_, err = e.Write([]byte{byte(0)})
|
||||
return err
|
||||
|
||||
case x < o1:
|
||||
b := byte(x)
|
||||
buf = []byte{b | 0x80}
|
||||
|
||||
case x < o2:
|
||||
buf = make([]byte, 2)
|
||||
buf[1] = byte(x)
|
||||
x >>= 8
|
||||
buf[0] = byte(x) | 0x40
|
||||
|
||||
case x < o3:
|
||||
buf = make([]byte, 3)
|
||||
buf[2] = byte(x)
|
||||
x >>= 8
|
||||
buf[1] = byte(x)
|
||||
x >>= 8
|
||||
buf[0] = byte(x) | 0x20
|
||||
|
||||
case x < o4:
|
||||
buf = make([]byte, 4)
|
||||
for i := 3; i > 0; i-- {
|
||||
buf[i] = byte(x)
|
||||
x >>= 8
|
||||
}
|
||||
buf[0] = byte(x) | 0x10
|
||||
|
||||
case x < o5:
|
||||
buf = make([]byte, 5)
|
||||
for i := 4; i > 0; i-- {
|
||||
buf[i] = byte(x)
|
||||
x >>= 8
|
||||
}
|
||||
buf[0] = byte(x) | 0x08
|
||||
|
||||
case x < o6:
|
||||
buf = make([]byte, 6)
|
||||
for i := 5; i > 0; i-- {
|
||||
buf[i] = byte(x)
|
||||
x >>= 8
|
||||
}
|
||||
buf[0] = byte(x) | 0x04
|
||||
|
||||
case x < o7:
|
||||
buf = make([]byte, 7)
|
||||
for i := 6; i > 0; i-- {
|
||||
buf[i] = byte(x)
|
||||
x >>= 8
|
||||
}
|
||||
buf[0] = byte(x) | 0x02
|
||||
|
||||
case x < o8:
|
||||
buf = make([]byte, 8)
|
||||
for i := 7; i > 0; i-- {
|
||||
buf[i] = byte(x)
|
||||
x >>= 8
|
||||
}
|
||||
buf[0] = 0x01
|
||||
|
||||
default:
|
||||
panic("element size overflow")
|
||||
}
|
||||
|
||||
_, err = e.Write(buf)
|
||||
return
|
||||
}
|
51
size_test.go
Normal file
51
size_test.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
package ebml
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var goldenSizes = []struct {
|
||||
in uint64
|
||||
out []byte
|
||||
}{
|
||||
{0, []byte{0}},
|
||||
{1, []byte{129}},
|
||||
{127, []byte{64, 127}},
|
||||
{128, []byte{64, 128}},
|
||||
{256, []byte{65, 0}},
|
||||
{16382, []byte{32, 63, 254}},
|
||||
{16383, []byte{32, 63, 255}},
|
||||
{16384, []byte{32, 64, 0}},
|
||||
{16385, []byte{32, 64, 1}},
|
||||
{32768, []byte{32, 128, 0}},
|
||||
{2097150, []byte{16, 31, 255, 254}},
|
||||
{2097151, []byte{16, 31, 255, 255}},
|
||||
{2097152, []byte{16, 32, 0, 0}},
|
||||
{268435454, []byte{8, 15, 255, 255, 254}},
|
||||
{268435455, []byte{8, 15, 255, 255, 255}},
|
||||
// http://en.wikipedia.org/wiki/Big_Endian#Examples_of_storing_the_value_0A0B0C0Dh_in_memory
|
||||
{0x0A0B0C0D, []byte{16 | 0x0A, 0x0B, 0x0C, 0x0D}},
|
||||
{1<<56 - 3, []byte{1, 255, 255, 255, 255, 255, 255, 253}},
|
||||
}
|
||||
|
||||
func TestGoldenSizes(t *testing.T) {
|
||||
for _, g := range goldenSizes {
|
||||
buf := new(bytes.Buffer)
|
||||
enc := NewEncoder(buf)
|
||||
enc.EncodeSize(g.in)
|
||||
enc.Flush()
|
||||
got := buf.Bytes()
|
||||
if !bytes.Equal(got, g.out) {
|
||||
t.Errorf("failed to marshal size %d, wanted %v, got %v", g.in, g.out, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncodeSize(b *testing.B) {
|
||||
enc := NewEncoder(ioutil.Discard)
|
||||
for i := 0; i < b.N; i++ {
|
||||
enc.EncodeSize(uint64(i))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user