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"
|
||||
|
||||
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
|
||||
}
|
||||
|
|
165
encoder.go
165
encoder.go
|
@ -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
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
|
||||
}
|
|
@ -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