Container and Element interfaces, new encoder is untested

This commit is contained in:
Emery Hemingway 2013-05-22 21:40:00 -05:00
parent 9609819393
commit d70adbd6ce
5 changed files with 321 additions and 133 deletions

View File

@ -2,8 +2,58 @@ package ebml
import "io"
type Element struct {
ID uint32
Size uint64
Data io.Reader
const (
HeaderID = 0xa45dfa3
DocTypeID = 0x4282
DocTypeVersionID = 0x4287
DocTypeReadVersionID = 0x4285
)
type Element interface {
ID() uint32
Size() uint64
io.Reader
}
type Container interface {
ID() uint32
Size() uint64
Next() Element
}
type header struct {
docType *String
docTypeVersion *Uint
docTypeReadVersion *Uint
}
func newHeader(docType string, docTypeVersion, docTypeReadVersion uint64) *header {
return &header{
NewString(DocTypeID, docType),
NewUint(DocTypeVersionID, docTypeVersion),
NewUint(DocTypeReadVersionID, docTypeReadVersion),
}
}
func (h *header) ID() uint32 { return HeaderID }
func (h *header) Size() (n uint64) {
return h.docType.Size() + h.docTypeVersion.Size() + h.docTypeReadVersion.Size()
}
func (h *header) Next() (e Element) {
switch {
case h.docType != nil:
e = h.docType
h.docType = nil
case h.docTypeVersion != nil:
e = h.docTypeVersion
h.docTypeVersion = nil
case h.docTypeReadVersion != nil:
e = h.docTypeReadVersion
h.docTypeReadVersion = nil
}
return
}

View File

@ -15,3 +15,168 @@ func NewEncoder(w io.Writer) *Encoder {
return &Encoder{Writer: bufio.NewWriter(w)}
}
// Encode writes a value that conforms to the Container
// or Element interface.
func (e *Encoder) Encode(v interface{}) (err error) {
if V, ok := v.(Container); ok {
e.EncodeID(V.ID())
e.EncodeSize(V.Size())
for element := V.Next(); element != nil; element = V.Next() {
err = e.Encode(element)
if err != nil {
return
}
}
return
}
if V, ok := v.(Element); ok {
e.EncodeID(V.ID())
e.EncodeSize(V.Size())
_, err = io.Copy(e, V)
return
}
panic("Could not encode value")
}
// PutHeader writes a EBML header to the encoder stream
// docType is an ASCII string that identifies the type of the document.
// docTypeVersion is the version of document type to which the
// document conforms to.
// docTypeReadVersion is the minimum DocType version an interpreter
// has to support in order to read the document.
func (e *Encoder) PutHeader(docType string, docTypeVersion, docTypeReadVersion uint64) error {
return e.Encode(newHeader(docType, docTypeVersion, docTypeReadVersion))
}
// EncodeID writes an element ID to the encoder stream.
//
// See the Encode convenience function.
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
}
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
)
// EncodeID writes an element size to the encoder stream.
//
// See the Encode convenience function.
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
}

44
id.go
View File

@ -1,44 +0,0 @@
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
}

85
size.go
View File

@ -1,85 +0,0 @@
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
}

102
value.go Normal file
View File

@ -0,0 +1,102 @@
package ebml
import (
"bytes"
)
type Int struct {
id uint32
*bytes.Buffer
}
func (i *Int) ID() uint32 { return i.id }
func (i *Int) Size() uint64 { return uint64(i.Len()) }
func NewInt(id uint32, v int64) (i *Int) {
var s int
switch {
case v < 0x8F, v > -0x8F:
s = 1
case v < 0x8FFF, v > -0x8FFF:
s = 2
case v < 0x8FFFFF, v > -0x8FFFFF:
s = 3
case v < 0x8FFFFFFF, v > -0x8FFFFFFF:
s = 4
case v < 0x8FFFFFFFFF, v > -0x8FFFFFFFFF:
s = 5
case v < 0x8FFFFFFFFFFF, v > -0x8FFFFFFFFFFF:
s = 6
case v < 0x8FFFFFFFFFFFFF, v > -0x8FFFFFFFFFFFFF:
s = 7
default:
s = 8
}
b := make([]byte, s)
for s > 1 {
s--
b[s] = byte(v)
v = v >> 8
}
b[s] = byte(v)
return &Int{id, bytes.NewBuffer(b)}
}
type Uint struct {
id uint32
*bytes.Buffer
}
func (u *Uint) ID() uint32 { return u.id }
func (u *Uint) Size() uint64 { return uint64(u.Len()) }
func NewUint(id uint32, v uint64) *Uint {
var s int
switch {
case v < 0xFF:
s = 1
case v < 0xFFFF:
s = 2
case v < 0xFFFFFF:
s = 3
case v < 0xFFFFFFFF:
s = 4
case v < 0xFFFFFFFFFF:
s = 5
case v < 0xFFFFFFFFFFFF:
s = 6
case v < 0xFFFFFFFFFFFFFF:
s = 7
default:
s = 8
}
b := make([]byte, s)
for s > 1 {
s--
b[s] = byte(v)
v = v >> 8
}
return &Uint{id, bytes.NewBuffer(b)}
}
type Float struct {
s int
b []byte
}
type String struct {
id uint32
*bytes.Buffer
}
func (s *String) ID() uint32 { return s.id }
func (s *String) Size() uint64 { return uint64(s.Len()) }
func NewString(id uint32, s string) *String {
return &String{id, bytes.NewBufferString(s)}
}