git.lucas.co / go_mono
git clone https://git.lucas.co/go_mono.git

riff/riff.go (5.1K)

  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 	errListSubchunkTooLong    = errors.New("riff: list subchunk too long")
 27 	errShortChunkData         = errors.New("riff: short chunk data")
 28 	errShortChunkHeader       = errors.New("riff: short chunk header")
 29 	errStaleReader            = errors.New("riff: stale reader")
 30 )
 31 
 32 // u32 decodes the first four bytes of b as a little-endian integer.
 33 func u32(b []byte) uint32 {
 34 	return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
 35 }
 36 
 37 const chunkHeaderSize = 8
 38 
 39 // FourCC is a four character code.
 40 type FourCC [4]byte
 41 
 42 // LIST is the "LIST" FourCC.
 43 var LIST = FourCC{'L', 'I', 'S', 'T'}
 44 
 45 // NewReader returns the RIFF stream's form type, such as "AVI " or "WAVE", and
 46 // its chunks as a *Reader.
 47 func NewReader(r io.Reader) (formType FourCC, data *Reader, err error) {
 48 	var buf [chunkHeaderSize]byte
 49 	if _, err := io.ReadFull(r, buf[:]); err != nil {
 50 		if err == io.EOF || err == io.ErrUnexpectedEOF {
 51 			err = errMissingRIFFChunkHeader
 52 		}
 53 		return FourCC{}, nil, err
 54 	}
 55 	if buf[0] != 'R' || buf[1] != 'I' || buf[2] != 'F' || buf[3] != 'F' {
 56 		return FourCC{}, nil, errMissingRIFFChunkHeader
 57 	}
 58 	return NewListReader(u32(buf[4:]), r)
 59 }
 60 
 61 // NewListReader returns a LIST chunk's list type, such as "movi" or "wavl",
 62 // and its chunks as a *Reader.
 63 func NewListReader(chunkLen uint32, chunkData io.Reader) (listType FourCC, data *Reader, err error) {
 64 	if chunkLen < 4 {
 65 		return FourCC{}, nil, errShortChunkData
 66 	}
 67 	z := &Reader{r: chunkData}
 68 	if _, err := io.ReadFull(chunkData, z.buf[:4]); err != nil {
 69 		if err == io.EOF || err == io.ErrUnexpectedEOF {
 70 			err = errShortChunkData
 71 		}
 72 		return FourCC{}, nil, err
 73 	}
 74 	z.totalLen = chunkLen - 4
 75 	return FourCC{z.buf[0], z.buf[1], z.buf[2], z.buf[3]}, z, nil
 76 }
 77 
 78 // Reader reads chunks from an underlying io.Reader.
 79 type Reader struct {
 80 	r   io.Reader
 81 	err error
 82 
 83 	totalLen uint32
 84 	chunkLen uint32
 85 
 86 	chunkReader *chunkReader
 87 	buf         [chunkHeaderSize]byte
 88 	padded      bool
 89 }
 90 
 91 // Next returns the next chunk's ID, length and data. It returns io.EOF if there
 92 // are no more chunks. The io.Reader returned becomes stale after the next Next
 93 // call, and should no longer be used.
 94 //
 95 // It is valid to call Next even if all of the previous chunk's data has not
 96 // been read.
 97 func (z *Reader) Next() (chunkID FourCC, chunkLen uint32, chunkData io.Reader, err error) {
 98 	if z.err != nil {
 99 		return FourCC{}, 0, nil, z.err
100 	}
101 
102 	// Drain the rest of the previous chunk.
103 	if z.chunkLen != 0 {
104 		want := z.chunkLen
105 		var got int64
106 		got, z.err = io.Copy(ioutil.Discard, z.chunkReader)
107 		if z.err == nil && uint32(got) != want {
108 			z.err = errShortChunkData
109 		}
110 		if z.err != nil {
111 			return FourCC{}, 0, nil, z.err
112 		}
113 	}
114 	z.chunkReader = nil
115 	if z.padded {
116 		if z.totalLen == 0 {
117 			z.err = errListSubchunkTooLong
118 			return FourCC{}, 0, nil, z.err
119 		}
120 		z.totalLen--
121 		_, z.err = io.ReadFull(z.r, z.buf[:1])
122 		if z.err != nil {
123 			if z.err == io.EOF {
124 				z.err = errMissingPaddingByte
125 			}
126 			return FourCC{}, 0, nil, z.err
127 		}
128 	}
129 
130 	// We are done if we have no more data.
131 	if z.totalLen == 0 {
132 		z.err = io.EOF
133 		return FourCC{}, 0, nil, z.err
134 	}
135 
136 	// Read the next chunk header.
137 	if z.totalLen < chunkHeaderSize {
138 		z.err = errShortChunkHeader
139 		return FourCC{}, 0, nil, z.err
140 	}
141 	z.totalLen -= chunkHeaderSize
142 	if _, z.err = io.ReadFull(z.r, z.buf[:chunkHeaderSize]); z.err != nil {
143 		if z.err == io.EOF || z.err == io.ErrUnexpectedEOF {
144 			z.err = errShortChunkHeader
145 		}
146 		return FourCC{}, 0, nil, z.err
147 	}
148 	chunkID = FourCC{z.buf[0], z.buf[1], z.buf[2], z.buf[3]}
149 	z.chunkLen = u32(z.buf[4:])
150 	if z.chunkLen > z.totalLen {
151 		z.err = errListSubchunkTooLong
152 		return FourCC{}, 0, nil, z.err
153 	}
154 	z.padded = z.chunkLen&1 == 1
155 	z.chunkReader = &chunkReader{z}
156 	return chunkID, z.chunkLen, z.chunkReader, nil
157 }
158 
159 type chunkReader struct {
160 	z *Reader
161 }
162 
163 func (c *chunkReader) Read(p []byte) (int, error) {
164 	if c != c.z.chunkReader {
165 		return 0, errStaleReader
166 	}
167 	z := c.z
168 	if z.err != nil {
169 		if z.err == io.EOF {
170 			return 0, errStaleReader
171 		}
172 		return 0, z.err
173 	}
174 
175 	n := int(z.chunkLen)
176 	if n == 0 {
177 		return 0, io.EOF
178 	}
179 	if n < 0 {
180 		// Converting uint32 to int overflowed.
181 		n = math.MaxInt32
182 	}
183 	if n > len(p) {
184 		n = len(p)
185 	}
186 	n, err := z.r.Read(p[:n])
187 	z.totalLen -= uint32(n)
188 	z.chunkLen -= uint32(n)
189 	if err != io.EOF {
190 		z.err = err
191 	}
192 	return n, err
193 }