...

Source file src/golang.org/x/image/riff/riff.go

Documentation: golang.org/x/image/riff

     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  }
   194  

View as plain text