func mscfbRdr(b *siegreader.Buffer) (Reader, error) { m, err := mscfb.New(siegreader.ReaderFrom(b)) if err != nil { return nil, err } return &mscfbReader{rdr: m}, nil }
func newGzip(b *siegreader.Buffer, path string) (decompressor, error) { b.Quit = make(chan struct{}) // in case a stream with a closed quit channel, make a new one _ = b.SizeNow() // in case a stream, force full read buf, err := b.EofSlice(0, 4) // gzip stores uncompressed size in last 4 bytes of the stream if err != nil { return nil, err } sz := int64(uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24) g, err := gzip.NewReader(siegreader.ReaderFrom(b)) return &gzipD{sz: sz, p: path, rdr: g}, err }
func identifyRdr(r io.Reader, ctx *context, ctxts chan *context, gf getFn) { s := ctx.s b, berr := s.Buffer(r) defer s.Put(b) ids, err := s.IdentifyBuffer(b, berr, ctx.path, ctx.mime) if ids == nil { ctx.res <- results{err, nil, nil} return } // calculate checksum var cs []byte if ctx.h != nil { var i int64 l := ctx.h.BlockSize() for ; ; i += int64(l) { buf, _ := b.Slice(i, l) if buf == nil { break } ctx.h.Write(buf) } cs = ctx.h.Sum(nil) } // decompress if an archive format if !ctx.z { ctx.res <- results{err, cs, ids} return } arc := isArc(ids) if arc == config.None { ctx.res <- results{err, cs, ids} return } var d decompressor switch arc { case config.Zip: d, err = newZip(siegreader.ReaderFrom(b), ctx.path, ctx.sz) case config.Gzip: d, err = newGzip(b, ctx.path) case config.Tar: d, err = newTar(siegreader.ReaderFrom(b), ctx.path) case config.ARC: d, err = newARC(siegreader.ReaderFrom(b), ctx.path) case config.WARC: d, err = newWARC(siegreader.ReaderFrom(b), ctx.path) } if err != nil { ctx.res <- results{fmt.Errorf("failed to decompress, got: %v", err), cs, ids} return } _, dw := ctx.w.(*droidWriter) // send the result ctx.res <- results{err, cs, ids} // decompress and recurse for err = d.next(); err == nil; err = d.next() { if dw { for _, v := range d.dirs() { dctx := gf(v, "", "", -1) dctx.res <- results{nil, nil, nil} dctx.wg.Add(1) ctxts <- dctx } } nctx := gf(d.path(), d.mime(), d.mod(), d.size()) nctx.wg.Add(1) ctxts <- nctx identifyRdr(d.reader(), nctx, ctxts, gf) } }
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 }