func ExampleReader() { formType, r, err := riff.NewReader(strings.NewReader(data)) if err != nil { log.Fatal(err) } fmt.Printf("RIFF(%s)\n", formType) if err := dump(r, ".\t"); err != nil { log.Fatal(err) } // Output: // RIFF(ROOT) // . ZERO "" // . ONE "a" // . LIST(META) // . . LIST(GOOD) // . . . ONE "a" // . . . FIVE "klmno" // . . ZERO "" // . . LIST(BAD ) // . . . THRE "def" // . TWO "bc" // . LIST(UGLY) // . . FOUR "ghij" // . . SIX "pqrstu" }
func decode(r io.Reader, configOnly bool) (image.Image, image.Config, error) { formType, riffReader, err := riff.NewReader(r) if err != nil { return nil, image.Config{}, err } if formType != fccWEBP { return nil, image.Config{}, errInvalidFormat } var ( alpha []byte alphaStride int wantAlpha bool widthMinusOne uint32 heightMinusOne uint32 buf [10]byte ) for { chunkID, chunkLen, chunkData, err := riffReader.Next() if err == io.EOF { err = errInvalidFormat } if err != nil { return nil, image.Config{}, err } switch chunkID { case fccALPH: if !wantAlpha { return nil, image.Config{}, errInvalidFormat } wantAlpha = false // Read the Pre-processing | Filter | Compression byte. if _, err := io.ReadFull(chunkData, buf[:1]); err != nil { if err == io.EOF { err = errInvalidFormat } return nil, image.Config{}, err } alpha, alphaStride, err = readAlpha(chunkData, widthMinusOne, heightMinusOne, buf[0]&0x03) if err != nil { return nil, image.Config{}, err } unfilterAlpha(alpha, alphaStride, (buf[0]>>2)&0x03) case fccVP8: if wantAlpha { return nil, image.Config{}, errInvalidFormat } d := vp8.NewDecoder() d.Init(chunkData, int(chunkLen)) fh, err := d.DecodeFrameHeader() if err != nil { return nil, image.Config{}, err } if configOnly { return nil, image.Config{ ColorModel: color.YCbCrModel, Width: fh.Width, Height: fh.Height, }, nil } m, err := d.DecodeFrame() if err != nil { return nil, image.Config{}, err } if alpha != nil { return &nycbcra.Image{ YCbCr: *m, A: alpha, AStride: alphaStride, }, image.Config{}, nil } return m, image.Config{}, nil case fccVP8L: if wantAlpha || alpha != nil { return nil, image.Config{}, errInvalidFormat } if configOnly { c, err := vp8l.DecodeConfig(chunkData) return nil, c, err } m, err := vp8l.Decode(chunkData) return m, image.Config{}, err case fccVP8X: if chunkLen != 10 { return nil, image.Config{}, errInvalidFormat } if _, err := io.ReadFull(chunkData, buf[:10]); err != nil { return nil, image.Config{}, err } const ( animationBit = 1 << 1 xmpMetadataBit = 1 << 2 exifMetadataBit = 1 << 3 alphaBit = 1 << 4 iccProfileBit = 1 << 5 ) if buf[0] != alphaBit { return nil, image.Config{}, errors.New("webp: non-Alpha VP8X is not implemented") } widthMinusOne = uint32(buf[4]) | uint32(buf[5])<<8 | uint32(buf[6])<<16 heightMinusOne = uint32(buf[7]) | uint32(buf[8])<<8 | uint32(buf[9])<<16 if configOnly { return nil, image.Config{ ColorModel: nycbcra.ColorModel, Width: int(widthMinusOne) + 1, Height: int(heightMinusOne) + 1, }, nil } wantAlpha = true } } }
func (m Matcher) Identify(na string, b *siegreader.Buffer, exclude ...int) (chan core.Result, error) { buf, err := b.Slice(0, 8) if err != nil || buf[0] != 'R' || buf[1] != 'I' || buf[2] != 'F' || buf[3] != 'F' { res := make(chan core.Result) close(res) return res, nil } rcc, rrdr, err := riff.NewReader(siegreader.ReaderFrom(b)) if err != nil { res := make(chan core.Result) close(res) return res, nil } // now make structures for testing uniqs := make(map[riff.FourCC]bool) res := make(chan core.Result) waitset := m.priorities.WaitSet(exclude...) // send and report if satisified send := func(cc riff.FourCC) bool { if config.Debug() { fmt.Fprintf(config.Out(), "riff match %s\n", string(cc[:])) } if uniqs[cc] { return false } uniqs[cc] = true for _, hit := range m.riffs[cc] { if waitset.Check(hit) { if config.Debug() { fmt.Fprintf(config.Out(), "sending riff match %s\n", string(cc[:])) } res <- result{hit, cc} if waitset.Put(hit) { return true } } } return false } // riff walk var descend func(*riff.Reader) bool descend = func(r *riff.Reader) bool { for { chunkID, chunkLen, chunkData, err := r.Next() if err != nil || send(chunkID) { return true } if chunkID == riff.LIST { listType, list, err := riff.NewListReader(chunkLen, chunkData) if err != nil || send(listType) { return true } if descend(list) { return true } } } } // go time go func() { if send(rcc) { close(res) return } descend(rrdr) close(res) }() return res, nil }