Inital commit

This commit is contained in:
Emery Hemingway 2013-05-21 21:00:06 -05:00
commit 9609819393
6 changed files with 254 additions and 0 deletions

9
element.go Normal file
View File

@ -0,0 +1,9 @@
package ebml
import "io"
type Element struct {
ID uint32
Size uint64
Data io.Reader
}

17
encoder.go Normal file
View 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
View 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
View 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
View 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
View 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))
}
}