meta: Return io.ErrUnexpectedEOF if EOF occurs in the middle of a metadata block.

This commit is contained in:
mewmew 2014-08-08 06:42:26 +02:00
parent ddd621f24d
commit 7a33256cf7
9 changed files with 67 additions and 47 deletions

View file

@ -189,8 +189,8 @@ func (frame *Frame) parseHeader() error {
frame.br = br
x, err := br.Read(14)
if err != nil {
// This should be the only place for a frame to return io.EOF, which
// signals a graceful end of FLAC stream.
// This is the only place an audio frame may return io.EOF, which signals
// a graceful end of a FLAC stream.
return err
}
if x != 0x3FFE {

View file

@ -24,7 +24,7 @@ func (block *Block) parseApplication() error {
block.Body = app
err := binary.Read(block.lr, binary.BigEndian, &app.ID)
if err != nil {
return err
return unexpected(err)
}
// Check if the Application block only contains an ID.
@ -34,5 +34,5 @@ func (block *Block) parseApplication() error {
// (block length)-4 bytes: Data.
app.Data, err = ioutil.ReadAll(block.lr)
return err
return unexpected(err)
}

View file

@ -32,7 +32,7 @@ func (block *Block) parseCueSheet() error {
// 128 bytes: MCN.
buf, err := readBytes(block.lr, 128)
if err != nil {
return err
return unexpected(err)
}
cs := new(CueSheet)
block.Body = cs
@ -41,14 +41,14 @@ func (block *Block) parseCueSheet() error {
// 64 bits: NLeadInSamples.
err = binary.Read(block.lr, binary.BigEndian, &cs.NLeadInSamples)
if err != nil {
return err
return unexpected(err)
}
// 1 bit: IsCompactDisc.
var x uint8
err = binary.Read(block.lr, binary.BigEndian, &x)
if err != nil {
return err
return unexpected(err)
}
// mask = 10000000
if x&0x80 != 0 {
@ -71,7 +71,7 @@ func (block *Block) parseCueSheet() error {
// 8 bits: (number of tracks)
err = binary.Read(block.lr, binary.BigEndian, &x)
if err != nil {
return err
return unexpected(err)
}
if x < 1 {
return errors.New("meta.Block.parseCueSheet: at least one track required")
@ -88,7 +88,7 @@ func (block *Block) parseCueSheet() error {
track := &cs.Tracks[i]
err = binary.Read(block.lr, binary.BigEndian, &track.Offset)
if err != nil {
return err
return unexpected(err)
}
if cs.IsCompactDisc && track.Offset%588 != 0 {
return fmt.Errorf("meta.Block.parseCueSheet: CD-DA track offset (%d) must be evenly divisible by 588", track.Offset)
@ -97,7 +97,7 @@ func (block *Block) parseCueSheet() error {
// 8 bits: Num.
err = binary.Read(block.lr, binary.BigEndian, &track.Num)
if err != nil {
return err
return unexpected(err)
}
if _, ok := uniq[track.Num]; ok {
return fmt.Errorf("meta.Block.parseCueSheet: duplicated track number %d", track.Num)
@ -126,14 +126,14 @@ func (block *Block) parseCueSheet() error {
// 12 bytes: ISRC.
buf, err = readBytes(block.lr, 12)
if err != nil {
return err
return unexpected(err)
}
track.ISRC = stringFromSZ(buf)
// 1 bit: IsAudio.
err = binary.Read(block.lr, binary.BigEndian, &x)
if err != nil {
return err
return unexpected(err)
}
// mask = 10000000
if x&0x80 == 0 {
@ -162,7 +162,7 @@ func (block *Block) parseCueSheet() error {
// 8 bits: (number of indicies)
err = binary.Read(block.lr, binary.BigEndian, &x)
if err != nil {
return err
return unexpected(err)
}
if x < 1 {
if !isLeadOut {
@ -176,13 +176,13 @@ func (block *Block) parseCueSheet() error {
// 64 bits: Offset.
err = binary.Read(block.lr, binary.BigEndian, &index.Offset)
if err != nil {
return err
return unexpected(err)
}
// 8 bits: Num.
err = binary.Read(block.lr, binary.BigEndian, &index.Num)
if err != nil {
return err
return unexpected(err)
}
// 3 bytes: reserved.

View file

@ -1,6 +1,3 @@
// TODO(u): Return io.ErrUnexpectedEOF if EOF occurs in the middle of a metadata
// block.
// Package meta implements access to FLAC metadata blocks.
//
// A brief introduction of the FLAC metadata format [1] follows. FLAC metadata
@ -139,6 +136,14 @@ func (block *Block) parseHeader(r io.Reader) error {
br := bit.NewReader(r)
x, err := br.Read(1)
if err != nil {
// This is the only place a metadata block may return io.EOF, which
// signals a graceful end of a FLAC stream (from a metadata point of
// view).
//
// Note that valid FLAC streams always contain at least one audio frame
// after the last metadata block. Therefore an io.EOF error at this
// location is always invalid. This logic is to be handled by the flac
// package however.
return err
}
if x != 0 {
@ -148,14 +153,14 @@ func (block *Block) parseHeader(r io.Reader) error {
// 7 bits: Type.
x, err = br.Read(7)
if err != nil {
return err
return unexpected(err)
}
block.Type = Type(x)
// 24 bits: Length.
x, err = br.Read(24)
if err != nil {
return err
return unexpected(err)
}
block.Length = int64(x)
@ -175,3 +180,12 @@ const (
TypeCueSheet
TypePicture
)
// unexpected returns io.ErrUnexpectedEOF if err is io.EOF, and returns err
// otherwise.
func unexpected(err error) error {
if err == io.EOF {
return io.ErrUnexpectedEOF
}
return err
}

View file

@ -57,68 +57,71 @@ func (block *Block) parsePicture() error {
block.Body = pic
err := binary.Read(block.lr, binary.BigEndian, &pic.Type)
if err != nil {
return err
return unexpected(err)
}
// 32 bits: (MIME type length).
var x uint32
err = binary.Read(block.lr, binary.BigEndian, &x)
if err != nil {
return err
return unexpected(err)
}
// (MIME type length) bytes: MIMEType.
buf, err := readBytes(block.lr, int(x))
if err != nil {
return err
return unexpected(err)
}
pic.MIMEType = string(buf)
// 32 bits: (description length).
err = binary.Read(block.lr, binary.BigEndian, &x)
if err != nil {
return err
return unexpected(err)
}
// (description length) bytes: Desc.
buf, err = readBytes(block.lr, int(x))
if err != nil {
return err
return unexpected(err)
}
pic.Desc = string(buf)
// 32 bits: Width.
err = binary.Read(block.lr, binary.BigEndian, &pic.Width)
if err != nil {
return err
return unexpected(err)
}
// 32 bits: Height.
err = binary.Read(block.lr, binary.BigEndian, &pic.Height)
if err != nil {
return err
return unexpected(err)
}
// 32 bits: Depth.
err = binary.Read(block.lr, binary.BigEndian, &pic.Depth)
if err != nil {
return err
return unexpected(err)
}
// 32 bits: NPalColors.
err = binary.Read(block.lr, binary.BigEndian, &pic.NPalColors)
if err != nil {
return err
return unexpected(err)
}
// 32 bits: (data length).
err = binary.Read(block.lr, binary.BigEndian, &x)
if err != nil {
return err
return unexpected(err)
}
if x == 0 {
return nil
}
// (data length) bytes: Data.
pic.Data = make([]byte, x)
_, err = io.ReadFull(block.lr, pic.Data)
return err
return unexpected(err)
}

View file

@ -7,7 +7,10 @@ var readBuf = make([]byte, 4096)
// readBytes reads and returns exactly n bytes from the provided io.Reader. The
// local buffer is reused in between calls to reduce garbage generation. It is
// the callers responsibility to make a copy of the returned data.
// the callers responsibility to make a copy of the returned data. The error is
// io.EOF only if no bytes were read. If an io.EOF happens after reading some
// but not all the bytes, ReadFull returns io.ErrUnexpectedEOF. On return, n ==
// len(buf) if and only if err == nil.
//
// The local buffer is initially 4096 bytes and will grow automatically if so
// required.

View file

@ -29,7 +29,7 @@ func (block *Block) parseSeekTable() error {
point := &table.Points[i]
err := binary.Read(block.lr, binary.BigEndian, point)
if err != nil {
return err
return unexpected(err)
}
// Seek points within a table must be sorted in ascending order by sample
// number. Each seek point must have a unique sample number, except for

View file

@ -45,7 +45,7 @@ func (block *Block) parseStreamInfo() error {
br := bit.NewReader(block.lr)
x, err := br.Read(16)
if err != nil {
return err
return unexpected(err)
}
if x < 16 {
return fmt.Errorf("meta.Block.parseStreamInfo: invalid minimum block size (%d); expected >= 16", x)
@ -57,7 +57,7 @@ func (block *Block) parseStreamInfo() error {
// 16 bits: BlockSizeMax.
x, err = br.Read(16)
if err != nil {
return err
return unexpected(err)
}
if x < 16 {
return fmt.Errorf("meta.Block.parseStreamInfo: invalid maximum block size (%d); expected >= 16", x)
@ -67,21 +67,21 @@ func (block *Block) parseStreamInfo() error {
// 24 bits: FrameSizeMin.
x, err = br.Read(24)
if err != nil {
return err
return unexpected(err)
}
si.FrameSizeMin = uint32(x)
// 24 bits: FrameSizeMax.
x, err = br.Read(24)
if err != nil {
return err
return unexpected(err)
}
si.FrameSizeMax = uint32(x)
// 20 bits: SampleRate.
x, err = br.Read(20)
if err != nil {
return err
return unexpected(err)
}
if x == 0 {
return errors.New("meta.Block.parseStreamInfo: invalid sample rate (0)")
@ -91,7 +91,7 @@ func (block *Block) parseStreamInfo() error {
// 3 bits: NChannels.
x, err = br.Read(3)
if err != nil {
return err
return unexpected(err)
}
// x contains: (number of channels) - 1
si.NChannels = uint8(x + 1)
@ -99,7 +99,7 @@ func (block *Block) parseStreamInfo() error {
// 5 bits: BitsPerSample.
x, err = br.Read(5)
if err != nil {
return err
return unexpected(err)
}
// x contains: (bits-per-sample) - 1
si.BitsPerSample = uint8(x + 1)
@ -107,10 +107,10 @@ func (block *Block) parseStreamInfo() error {
// 36 bits: NSamples.
si.NSamples, err = br.Read(36)
if err != nil {
return err
return unexpected(err)
}
// 16 bytes: MD5sum.
_, err = io.ReadFull(block.lr, si.MD5sum[:])
return err
return unexpected(err)
}

View file

@ -23,13 +23,13 @@ func (block *Block) parseVorbisComment() error {
var x uint32
err := binary.Read(block.lr, binary.LittleEndian, &x)
if err != nil {
return err
return unexpected(err)
}
// (vendor length) bits: Vendor.
buf, err := readBytes(block.lr, int(x))
if err != nil {
return err
return unexpected(err)
}
comment := new(VorbisComment)
block.Body = comment
@ -39,7 +39,7 @@ func (block *Block) parseVorbisComment() error {
// 32 bits: number of tags.
err = binary.Read(block.lr, binary.LittleEndian, &x)
if err != nil {
return err
return unexpected(err)
}
if x < 1 {
return nil
@ -49,13 +49,13 @@ func (block *Block) parseVorbisComment() error {
// 32 bits: vector length
err = binary.Read(block.lr, binary.LittleEndian, &x)
if err != nil {
return err
return unexpected(err)
}
// (vector length): vector.
buf, err = readBytes(block.lr, int(x))
if err != nil {
return err
return unexpected(err)
}
vector := string(buf)