diff options
| author | Felix Hanley <felix@userspace.com.au> | 2017-03-19 15:19:42 +0000 |
|---|---|---|
| committer | Felix Hanley <felix@userspace.com.au> | 2017-03-19 15:19:42 +0000 |
| commit | 8a541d499b6f117cd3a81e475ee779ba60fc0637 (patch) | |
| tree | 7b3b5326235725ab93056b5ff4637d987fb0a7b6 /vendor/golang.org/x/image/riff | |
| parent | fe847b2d01060044274d20d2c35ae01a684d4ee3 (diff) | |
| download | crjw-maps-master.tar.gz crjw-maps-master.tar.bz2 | |
Diffstat (limited to 'vendor/golang.org/x/image/riff')
| -rw-r--r-- | vendor/golang.org/x/image/riff/example_test.go | 113 | ||||
| -rw-r--r-- | vendor/golang.org/x/image/riff/riff.go | 193 | ||||
| -rw-r--r-- | vendor/golang.org/x/image/riff/riff_test.go | 69 |
3 files changed, 375 insertions, 0 deletions
diff --git a/vendor/golang.org/x/image/riff/example_test.go b/vendor/golang.org/x/image/riff/example_test.go new file mode 100644 index 0000000..93c72b0 --- /dev/null +++ b/vendor/golang.org/x/image/riff/example_test.go @@ -0,0 +1,113 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package riff_test + +import ( + "fmt" + "io" + "io/ioutil" + "log" + "strings" + + "golang.org/x/image/riff" +) + +func ExampleReader() { + formType, r, err := riff.NewReader(strings.NewReader(data)) + if err != nil { + log.Fatal(err) + } + fmt.Printf("RIFF(%s)\n", formType) + if err := dump(r, ".\t"); err != nil { + log.Fatal(err) + } + // Output: + // RIFF(ROOT) + // . ZERO "" + // . ONE "a" + // . LIST(META) + // . . LIST(GOOD) + // . . . ONE "a" + // . . . FIVE "klmno" + // . . ZERO "" + // . . LIST(BAD ) + // . . . THRE "def" + // . TWO "bc" + // . LIST(UGLY) + // . . FOUR "ghij" + // . . SIX "pqrstu" +} + +func dump(r *riff.Reader, indent string) error { + for { + chunkID, chunkLen, chunkData, err := r.Next() + if err == io.EOF { + return nil + } + if err != nil { + return err + } + if chunkID == riff.LIST { + listType, list, err := riff.NewListReader(chunkLen, chunkData) + if err != nil { + return err + } + fmt.Printf("%sLIST(%s)\n", indent, listType) + if err := dump(list, indent+".\t"); err != nil { + return err + } + continue + } + b, err := ioutil.ReadAll(chunkData) + if err != nil { + return err + } + fmt.Printf("%s%s %q\n", indent, chunkID, b) + } +} + +func encodeU32(u uint32) string { + return string([]byte{ + byte(u >> 0), + byte(u >> 8), + byte(u >> 16), + byte(u >> 24), + }) +} + +func encode(chunkID, contents string) string { + n := len(contents) + if n&1 == 1 { + contents += "\x00" + } + return chunkID + encodeU32(uint32(n)) + contents +} + +func encodeMulti(typ0, typ1 string, chunks ...string) string { + n := 4 + for _, c := range chunks { + n += len(c) + } + s := typ0 + encodeU32(uint32(n)) + typ1 + for _, c := range chunks { + s += c + } + return s +} + +var ( + d0 = encode("ZERO", "") + d1 = encode("ONE ", "a") + d2 = encode("TWO ", "bc") + d3 = encode("THRE", "def") + d4 = encode("FOUR", "ghij") + d5 = encode("FIVE", "klmno") + d6 = encode("SIX ", "pqrstu") + l0 = encodeMulti("LIST", "GOOD", d1, d5) + l1 = encodeMulti("LIST", "BAD ", d3) + l2 = encodeMulti("LIST", "UGLY", d4, d6) + l01 = encodeMulti("LIST", "META", l0, d0, l1) + data = encodeMulti("RIFF", "ROOT", d0, d1, l01, d2, l2) +) diff --git a/vendor/golang.org/x/image/riff/riff.go b/vendor/golang.org/x/image/riff/riff.go new file mode 100644 index 0000000..38dc0e5 --- /dev/null +++ b/vendor/golang.org/x/image/riff/riff.go @@ -0,0 +1,193 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package riff implements the Resource Interchange File Format, used by media +// formats such as AVI, WAVE and WEBP. +// +// A RIFF stream contains a sequence of chunks. Each chunk consists of an 8-byte +// header (containing a 4-byte chunk type and a 4-byte chunk length), the chunk +// data (presented as an io.Reader), and some padding bytes. +// +// A detailed description of the format is at +// http://www.tactilemedia.com/info/MCI_Control_Info.html +package riff // import "golang.org/x/image/riff" + +import ( + "errors" + "io" + "io/ioutil" + "math" +) + +var ( + errMissingPaddingByte = errors.New("riff: missing padding byte") + errMissingRIFFChunkHeader = errors.New("riff: missing RIFF chunk header") + errListSubchunkTooLong = errors.New("riff: list subchunk too long") + errShortChunkData = errors.New("riff: short chunk data") + errShortChunkHeader = errors.New("riff: short chunk header") + errStaleReader = errors.New("riff: stale reader") +) + +// u32 decodes the first four bytes of b as a little-endian integer. +func u32(b []byte) uint32 { + return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 +} + +const chunkHeaderSize = 8 + +// FourCC is a four character code. +type FourCC [4]byte + +// LIST is the "LIST" FourCC. +var LIST = FourCC{'L', 'I', 'S', 'T'} + +// NewReader returns the RIFF stream's form type, such as "AVI " or "WAVE", and +// its chunks as a *Reader. +func NewReader(r io.Reader) (formType FourCC, data *Reader, err error) { + var buf [chunkHeaderSize]byte + if _, err := io.ReadFull(r, buf[:]); err != nil { + if err == io.EOF || err == io.ErrUnexpectedEOF { + err = errMissingRIFFChunkHeader + } + return FourCC{}, nil, err + } + if buf[0] != 'R' || buf[1] != 'I' || buf[2] != 'F' || buf[3] != 'F' { + return FourCC{}, nil, errMissingRIFFChunkHeader + } + return NewListReader(u32(buf[4:]), r) +} + +// NewListReader returns a LIST chunk's list type, such as "movi" or "wavl", +// and its chunks as a *Reader. +func NewListReader(chunkLen uint32, chunkData io.Reader) (listType FourCC, data *Reader, err error) { + if chunkLen < 4 { + return FourCC{}, nil, errShortChunkData + } + z := &Reader{r: chunkData} + if _, err := io.ReadFull(chunkData, z.buf[:4]); err != nil { + if err == io.EOF || err == io.ErrUnexpectedEOF { + err = errShortChunkData + } + return FourCC{}, nil, err + } + z.totalLen = chunkLen - 4 + return FourCC{z.buf[0], z.buf[1], z.buf[2], z.buf[3]}, z, nil +} + +// Reader reads chunks from an underlying io.Reader. +type Reader struct { + r io.Reader + err error + + totalLen uint32 + chunkLen uint32 + + chunkReader *chunkReader + buf [chunkHeaderSize]byte + padded bool +} + +// Next returns the next chunk's ID, length and data. It returns io.EOF if there +// are no more chunks. The io.Reader returned becomes stale after the next Next +// call, and should no longer be used. +// +// It is valid to call Next even if all of the previous chunk's data has not +// been read. +func (z *Reader) Next() (chunkID FourCC, chunkLen uint32, chunkData io.Reader, err error) { + if z.err != nil { + return FourCC{}, 0, nil, z.err + } + + // Drain the rest of the previous chunk. + if z.chunkLen != 0 { + want := z.chunkLen + var got int64 + got, z.err = io.Copy(ioutil.Discard, z.chunkReader) + if z.err == nil && uint32(got) != want { + z.err = errShortChunkData + } + if z.err != nil { + return FourCC{}, 0, nil, z.err + } + } + z.chunkReader = nil + if z.padded { + if z.totalLen == 0 { + z.err = errListSubchunkTooLong + return FourCC{}, 0, nil, z.err + } + z.totalLen-- + _, z.err = io.ReadFull(z.r, z.buf[:1]) + if z.err != nil { + if z.err == io.EOF { + z.err = errMissingPaddingByte + } + return FourCC{}, 0, nil, z.err + } + } + + // We are done if we have no more data. + if z.totalLen == 0 { + z.err = io.EOF + return FourCC{}, 0, nil, z.err + } + + // Read the next chunk header. + if z.totalLen < chunkHeaderSize { + z.err = errShortChunkHeader + return FourCC{}, 0, nil, z.err + } + z.totalLen -= chunkHeaderSize + if _, z.err = io.ReadFull(z.r, z.buf[:chunkHeaderSize]); z.err != nil { + if z.err == io.EOF || z.err == io.ErrUnexpectedEOF { + z.err = errShortChunkHeader + } + return FourCC{}, 0, nil, z.err + } + chunkID = FourCC{z.buf[0], z.buf[1], z.buf[2], z.buf[3]} + z.chunkLen = u32(z.buf[4:]) + if z.chunkLen > z.totalLen { + z.err = errListSubchunkTooLong + return FourCC{}, 0, nil, z.err + } + z.padded = z.chunkLen&1 == 1 + z.chunkReader = &chunkReader{z} + return chunkID, z.chunkLen, z.chunkReader, nil +} + +type chunkReader struct { + z *Reader +} + +func (c *chunkReader) Read(p []byte) (int, error) { + if c != c.z.chunkReader { + return 0, errStaleReader + } + z := c.z + if z.err != nil { + if z.err == io.EOF { + return 0, errStaleReader + } + return 0, z.err + } + + n := int(z.chunkLen) + if n == 0 { + return 0, io.EOF + } + if n < 0 { + // Converting uint32 to int overflowed. + n = math.MaxInt32 + } + if n > len(p) { + n = len(p) + } + n, err := z.r.Read(p[:n]) + z.totalLen -= uint32(n) + z.chunkLen -= uint32(n) + if err != io.EOF { + z.err = err + } + return n, err +} diff --git a/vendor/golang.org/x/image/riff/riff_test.go b/vendor/golang.org/x/image/riff/riff_test.go new file mode 100644 index 0000000..567e938 --- /dev/null +++ b/vendor/golang.org/x/image/riff/riff_test.go @@ -0,0 +1,69 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package riff + +import ( + "bytes" + "testing" +) + +func encodeU32(u uint32) []byte { + return []byte{ + byte(u >> 0), + byte(u >> 8), + byte(u >> 16), + byte(u >> 24), + } +} + +func TestShortChunks(t *testing.T) { + // s is a RIFF(ABCD) with allegedly 256 bytes of data (excluding the + // leading 8-byte "RIFF\x00\x01\x00\x00"). The first chunk of that ABCD + // list is an abcd chunk of length m followed by n zeroes. + for _, m := range []uint32{0, 8, 15, 200, 300} { + for _, n := range []int{0, 1, 2, 7} { + s := []byte("RIFF\x00\x01\x00\x00ABCDabcd") + s = append(s, encodeU32(m)...) + s = append(s, make([]byte, n)...) + _, r, err := NewReader(bytes.NewReader(s)) + if err != nil { + t.Errorf("m=%d, n=%d: NewReader: %v", m, n, err) + continue + } + + _, _, _, err0 := r.Next() + // The total "ABCD" list length is 256 bytes, of which the first 12 + // bytes are "ABCDabcd" plus the 4-byte encoding of m. If the + // "abcd" subchunk length (m) plus those 12 bytes is greater than + // the total list length, we have an invalid RIFF, and we expect an + // errListSubchunkTooLong error. + if m+12 > 256 { + if err0 != errListSubchunkTooLong { + t.Errorf("m=%d, n=%d: Next #0: got %v, want %v", m, n, err0, errListSubchunkTooLong) + } + continue + } + // Otherwise, we expect a nil error. + if err0 != nil { + t.Errorf("m=%d, n=%d: Next #0: %v", m, n, err0) + continue + } + + _, _, _, err1 := r.Next() + // If m > 0, then m > n, so that "abcd" subchunk doesn't have m + // bytes of data. If m == 0, then that "abcd" subchunk is OK in + // that it has 0 extra bytes of data, but the next subchunk (8 byte + // header plus body) is missing, as we only have n < 8 more bytes. + want := errShortChunkData + if m == 0 { + want = errShortChunkHeader + } + if err1 != want { + t.Errorf("m=%d, n=%d: Next #1: got %v, want %v", m, n, err1, want) + continue + } + } + } +} |
