diff --git a/decode.go b/decode.go index bd18166..08401fb 100644 --- a/decode.go +++ b/decode.go @@ -174,10 +174,7 @@ func (d *decodeState) readSize() int64 { return x } -var i int - func (d *decodeState) readValue(size int64, v reflect.Value) { - i++ if !v.IsValid() { _, err := d.r.Seek(size, 1) if err != nil { @@ -187,7 +184,15 @@ func (d *decodeState) readValue(size int64, v reflect.Value) { } switch v.Kind() { - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + b := make([]byte, size) + _, err := d.r.Read(b) + if err != nil { + d.error(err) + } + v.SetInt(unmarshalInt(b)) + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: b := make([]byte, size) _, err := d.r.Read(b) if err != nil { @@ -358,6 +363,15 @@ func indirect(v reflect.Value) reflect.Value { return v } +func unmarshalInt(b []byte) int64 { + x := int64(b[0]) + for _, c := range b[1:] { + x <<= 8 + x += int64(c) + } + return x +} + func unmarshalUint(b []byte) uint64 { x := uint64(b[0]) for _, c := range b[1:] { diff --git a/decoder.go b/decoder.go index a21b389..79eb37c 100644 --- a/decoder.go +++ b/decoder.go @@ -8,7 +8,6 @@ import ( "io" ) - type Decoder struct { r io.ReadSeeker err error diff --git a/ebml_test.go b/ebml_test.go index bc76659..0e33a48 100644 --- a/ebml_test.go +++ b/ebml_test.go @@ -1,6 +1,7 @@ package ebml import ( + "bytes" "reflect" "testing" ) @@ -15,18 +16,24 @@ func TestMatroskaEBMLHeader(t *testing.T) { headerA.DocTypeVersion = 1 headerA.DocTypeReadVersion = 1 - b, err := Marshal(headerA) + dst := new(bytes.Buffer) + enc := NewEncoder(dst) + + err := enc.Encode(headerA) if err != nil { t.Fatal("Marshal:", err) } + src := bytes.NewReader(dst.Bytes()) + dec := NewDecoder(src) + var headerB Header - err = Unmarshal(b, &headerB) + err = dec.Decode(&headerB) if err != nil { t.Fatal("Unmarshal:", err) } if !reflect.DeepEqual(headerA, headerB) { - t.Fatalf("Marshal -> Unmarshal: marshaled %v to %x, but unmarshaled %v", headerA, b, headerB) + t.Fatalf("Marshal -> Unmarshal: marshaled %v to %x, but unmarshaled %v", headerA, dst.Bytes(), headerB) } } diff --git a/encode.go b/encode.go index afe097a..31c75d7 100644 --- a/encode.go +++ b/encode.go @@ -215,7 +215,9 @@ func fieldByIndex(v reflect.Value, index []int) reflect.Value { return v } -func parseIdTag(s string) ([]byte, error) { +// ParseId marshals a hexadecimal number into a byte slice. +// It can be used to check that an Id has the proper width bit set. +func ParseId(s string) ([]byte, error) { x, err := strconv.ParseUint(s, 16, 32) if err != nil { return nil, err @@ -428,7 +430,7 @@ func typeFields(t reflect.Type) []field { if tag == "" { continue } - id, err := parseIdTag(tag) + id, err := ParseId(tag) if err != nil { panic(err.Error()) } diff --git a/idtest/idtest.go b/idtest/idtest.go new file mode 100644 index 0000000..03e076d --- /dev/null +++ b/idtest/idtest.go @@ -0,0 +1,42 @@ +// idtest is a utility for checking the validity of EBML ids +package main + +import ( + "fmt" + "git.gitorious.org/go-ebml/ebml.git" + "os" +) + +func main() { + for _, s := range os.Args[1:] { + b, err := ebml.ParseId(s) + if err != nil { + fmt.Println(err) + continue + } + + c := b[0] + var good bool + switch l := len(b); l { + case 1: + good = c <= 0xff && c > 0x80 + case 2: + good = c <= 0x7f && c > 0x40 + case 3: + good = c <= 0x3f && c > 0x20 + case 4: + good = c <= 0x1f && c > 0x10 + } + + if good { + fmt.Print("Id is good: ") + } else { + fmt.Print("Id is bad: ") + } + fmt.Printf("% 11x ", b) + for _, c := range b { + fmt.Printf(".%08b", c) + } + fmt.Println() + } +}