github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/image/riff/riff.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package riff implements the Resource Interchange File Format, used by media 6 // formats such as AVI, WAVE and WEBP. 7 // 8 // A RIFF stream contains a sequence of chunks. Each chunk consists of an 8-byte 9 // header (containing a 4-byte chunk type and a 4-byte chunk length), the chunk 10 // data (presented as an io.Reader), and some padding bytes. 11 // 12 // A detailed description of the format is at 13 // http://www.tactilemedia.com/info/MCI_Control_Info.html 14 package riff // import "golang.org/x/image/riff" 15 16 import ( 17 "errors" 18 "io" 19 "io/ioutil" 20 "math" 21 ) 22 23 var ( 24 errMissingPaddingByte = errors.New("riff: missing padding byte") 25 errMissingRIFFChunkHeader = errors.New("riff: missing RIFF chunk header") 26 errShortChunkData = errors.New("riff: short chunk data") 27 errShortChunkHeader = errors.New("riff: short chunk header") 28 errStaleReader = errors.New("riff: stale reader") 29 ) 30 31 // u32 decodes the first four bytes of b as a little-endian integer. 32 func u32(b []byte) uint32 { 33 return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 34 } 35 36 const chunkHeaderSize = 8 37 38 // FourCC is a four character code. 39 type FourCC [4]byte 40 41 // LIST is the "LIST" FourCC. 42 var LIST = FourCC{'L', 'I', 'S', 'T'} 43 44 // NewReader returns the RIFF stream's form type, such as "AVI " or "WAVE", and 45 // its chunks as a *Reader. 46 func NewReader(r io.Reader) (formType FourCC, data *Reader, err error) { 47 var buf [chunkHeaderSize]byte 48 if _, err := io.ReadFull(r, buf[:]); err != nil { 49 if err == io.EOF || err == io.ErrUnexpectedEOF { 50 err = errMissingRIFFChunkHeader 51 } 52 return FourCC{}, nil, err 53 } 54 if buf[0] != 'R' || buf[1] != 'I' || buf[2] != 'F' || buf[3] != 'F' { 55 return FourCC{}, nil, errMissingRIFFChunkHeader 56 } 57 return NewListReader(u32(buf[4:]), r) 58 } 59 60 // NewListReader returns a LIST chunk's list type, such as "movi" or "wavl", 61 // and its chunks as a *Reader. 62 func NewListReader(chunkLen uint32, chunkData io.Reader) (listType FourCC, data *Reader, err error) { 63 if chunkLen < 4 { 64 return FourCC{}, nil, errShortChunkData 65 } 66 z := &Reader{r: chunkData} 67 if _, err := io.ReadFull(chunkData, z.buf[:4]); err != nil { 68 if err == io.EOF || err == io.ErrUnexpectedEOF { 69 err = errShortChunkData 70 } 71 return FourCC{}, nil, err 72 } 73 z.totalLen = chunkLen - 4 74 return FourCC{z.buf[0], z.buf[1], z.buf[2], z.buf[3]}, z, nil 75 } 76 77 // Reader reads chunks from an underlying io.Reader. 78 type Reader struct { 79 r io.Reader 80 err error 81 82 totalLen uint32 83 chunkLen uint32 84 85 chunkReader *chunkReader 86 buf [chunkHeaderSize]byte 87 padded bool 88 } 89 90 // Next returns the next chunk's ID, length and data. It returns io.EOF if there 91 // are no more chunks. The io.Reader returned becomes stale after the next Next 92 // call, and should no longer be used. 93 // 94 // It is valid to call Next even if all of the previous chunk's data has not 95 // been read. 96 func (z *Reader) Next() (chunkID FourCC, chunkLen uint32, chunkData io.Reader, err error) { 97 if z.err != nil { 98 return FourCC{}, 0, nil, z.err 99 } 100 101 // Drain the rest of the previous chunk. 102 if z.chunkLen != 0 { 103 _, z.err = io.Copy(ioutil.Discard, z.chunkReader) 104 if z.err != nil { 105 return FourCC{}, 0, nil, z.err 106 } 107 } 108 z.chunkReader = nil 109 if z.padded { 110 _, z.err = io.ReadFull(z.r, z.buf[:1]) 111 if z.err != nil { 112 if z.err == io.EOF { 113 z.err = errMissingPaddingByte 114 } 115 return FourCC{}, 0, nil, z.err 116 } 117 z.totalLen-- 118 } 119 120 // We are done if we have no more data. 121 if z.totalLen == 0 { 122 z.err = io.EOF 123 return FourCC{}, 0, nil, z.err 124 } 125 126 // Read the next chunk header. 127 if z.totalLen < chunkHeaderSize { 128 z.err = errShortChunkHeader 129 return FourCC{}, 0, nil, z.err 130 } 131 z.totalLen -= chunkHeaderSize 132 if _, err = io.ReadFull(z.r, z.buf[:chunkHeaderSize]); err != nil { 133 if z.err == io.EOF || z.err == io.ErrUnexpectedEOF { 134 z.err = errShortChunkHeader 135 } 136 return FourCC{}, 0, nil, z.err 137 } 138 chunkID = FourCC{z.buf[0], z.buf[1], z.buf[2], z.buf[3]} 139 z.chunkLen = u32(z.buf[4:]) 140 z.padded = z.chunkLen&1 == 1 141 z.chunkReader = &chunkReader{z} 142 return chunkID, z.chunkLen, z.chunkReader, nil 143 } 144 145 type chunkReader struct { 146 z *Reader 147 } 148 149 func (c *chunkReader) Read(p []byte) (int, error) { 150 if c != c.z.chunkReader { 151 return 0, errStaleReader 152 } 153 z := c.z 154 if z.err != nil { 155 if z.err == io.EOF { 156 return 0, errStaleReader 157 } 158 return 0, z.err 159 } 160 161 n := int(z.chunkLen) 162 if n == 0 { 163 return 0, io.EOF 164 } 165 if n < 0 { 166 // Converting uint32 to int overflowed. 167 n = math.MaxInt32 168 } 169 if n > len(p) { 170 n = len(p) 171 } 172 n, err := z.r.Read(p[:n]) 173 z.totalLen -= uint32(n) 174 z.chunkLen -= uint32(n) 175 if err != io.EOF { 176 z.err = err 177 } 178 return n, err 179 }