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  }