Container and Element interfaces, new encoder is untested
This commit is contained in:
parent
9609819393
commit
d70adbd6ce
58
element.go
58
element.go
|
@ -2,8 +2,58 @@ package ebml
|
||||||
|
|
||||||
import "io"
|
import "io"
|
||||||
|
|
||||||
type Element struct {
|
const (
|
||||||
ID uint32
|
HeaderID = 0xa45dfa3
|
||||||
Size uint64
|
DocTypeID = 0x4282
|
||||||
Data io.Reader
|
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
|
||||||
}
|
}
|
||||||
|
|
165
encoder.go
165
encoder.go
|
@ -15,3 +15,168 @@ func NewEncoder(w io.Writer) *Encoder {
|
||||||
return &Encoder{Writer: bufio.NewWriter(w)}
|
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
44
id.go
|
@ -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
85
size.go
|
@ -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
102
value.go
Normal 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)}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user