func (i *Identifier) Recognise(m core.MatcherType, idx int) (bool, string) { switch m { default: return false, "" case core.ExtensionMatcher: if idx >= i.eStart && idx < i.eStart+len(i.ePuids) { idx = idx - i.eStart return true, i.name + ": " + i.ePuids[idx] } return false, "" case core.MIMEMatcher: if idx >= i.mStart && idx < i.mStart+len(i.mPuids) { idx = idx - i.mStart return true, i.name + ": " + i.mPuids[idx] } return false, "" case core.ContainerMatcher: if idx >= i.cStart && idx < i.cStart+len(i.cPuids) { idx = idx - i.cStart return true, i.name + ": " + i.cPuids[idx] } return false, "" case core.ByteMatcher: if idx >= i.bStart && idx < i.bStart+len(i.bPuids) { return true, i.name + ": " + i.bPuids[idx] } return false, "" case core.TextMatcher: if idx == i.tStart { return true, i.name + ": " + config.TextPuid() } return false, "" } }
// add adds extension, bytematcher or containermatcher signatures to the identifier func (p *pronom) add(m core.Matcher, t core.MatcherType) error { switch t { default: return fmt.Errorf("Pronom: unknown matcher type %d", t) case core.ExtensionMatcher: if !config.NoExt() { var exts [][]string exts, p.ePuids = p.j.Globs() l, err := m.Add(stringmatcher.SignatureSet(exts), nil) if err != nil { return err } p.eStart = l - len(p.ePuids) return nil } case core.MIMEMatcher: if !config.NoMIME() { var mimes [][]string mimes, p.mPuids = p.j.MIMEs() l, err := m.Add(stringmatcher.SignatureSet(mimes), nil) if err != nil { return err } p.mStart = l - len(p.mPuids) return nil } case core.ContainerMatcher: return p.contMatcher(m) case core.ByteMatcher: var sigs []frames.Signature var err error sigs, p.bPuids, err = p.j.Signatures() if err != nil { return err } var plist priority.List if !config.NoPriority() { plist = p.pm.List(p.bPuids) } l, err := m.Add(bytematcher.SignatureSet(sigs), plist) if err != nil { return err } p.bStart = l - len(p.bPuids) case core.TextMatcher: if !config.NoText() && p.hasPuid(config.TextPuid()) { l, _ := m.Add(textmatcher.SignatureSet{}, nil) p.tStart = l } } return nil }
func (r *Recorder) Satisfied(mt core.MatcherType) bool { if r.cscore < incScore { if mt == core.ByteMatcher { return false } if len(r.ids) == 0 { return false } for _, res := range r.ids { if res.Puid == config.TextPuid() { return false } } } r.satisfied = true return true }
// add adds extension, bytematcher or containermatcher signatures to the identifier func (p *pronom) add(m core.Matcher) error { switch t := m.(type) { default: return fmt.Errorf("Pronom: unknown matcher type %T", t) case extensionmatcher.Matcher: if !config.NoExt() { var exts [][]string exts, p.ePuids = p.j.extensions() l, err := m.Add(extensionmatcher.SignatureSet(exts), nil) if err != nil { return err } p.eStart = l - len(p.ePuids) return nil } case containermatcher.Matcher: return p.contMatcher(m) case *bytematcher.Matcher: var sigs []frames.Signature var err error sigs, p.bPuids, err = p.j.signatures() if err != nil { return err } var plist priority.List if !config.NoPriority() { plist = p.pm.List(p.bPuids) } l, err := m.Add(bytematcher.SignatureSet(sigs), plist) if err != nil { return err } p.bStart = l - len(p.bPuids) case *textmatcher.Matcher: if !config.NoText() && p.hasPuid(config.TextPuid()) { l, _ := m.Add(textmatcher.SignatureSet{}, nil) p.tStart = l } } return nil }
func (r *Recorder) Report(res chan core.Identification) { if len(r.ids) > 0 { // if we don't have priority set, apply a warning if r.noPriority { for i := range r.ids { r.ids[i].Warning = "no priority set for this identifier" } } sort.Sort(r.ids) conf := r.ids[0].confidence // if we've only got extension / mime matches, check if those matches are ruled out by lack of byte match // only permit a single extension or mime only match // add warnings too if conf <= textScore { nids := make([]Identification, 0, 1) for _, v := range r.ids { // if overall confidence is greater than mime or ext only, then rule out any lesser confident matches if conf > mimeScore && v.confidence != conf { break } // if we have plain text result that is based on ext or mime only, // and not on a text match, and if text matcher is on for this identifier, // then don't report a text match if v.Puid == config.TextPuid() && conf < textScore && r.textActive { continue } // if the match has no corresponding byte or container signature... if ok := r.hasSig(v.Puid); !ok { // break immediately if more than one match if len(nids) > 0 { nids = nids[:0] break } if len(v.Warning) > 0 { v.Warning += "; " + "match on " + lowConfidence(v.confidence) + " only" } else { v.Warning = "match on " + lowConfidence(v.confidence) + " only" } nids = append(nids, v) } } if len(nids) != 1 { poss := make([]string, len(r.ids)) for i, v := range r.ids { poss[i] = v.Puid conf = conf | v.confidence } nids = []Identification{Identification{r.name, "UNKNOWN", "", "", "", nil, fmt.Sprintf("no match; possibilities based on %v are %v", lowConfidence(conf), strings.Join(poss, ", ")), 0, 0}} } r.ids = nids } res <- r.checkActive(r.ids[0]) if len(r.ids) > 1 { for i, v := range r.ids[1:] { if v.confidence == conf || (r.noPriority && v.confidence >= incScore) { res <- r.checkActive(r.ids[i+1]) } else { break } } } } else { res <- Identification{r.name, "UNKNOWN", "", "", "", nil, "no match", 0, 0} } }
func (r *Recorder) Record(m core.MatcherType, res core.Result) bool { switch m { default: return false case core.ExtensionMatcher: if res.Index() >= r.eStart && res.Index() < r.eStart+len(r.ePuids) { idx := res.Index() - r.eStart r.ids = add(r.ids, r.name, r.ePuids[idx], r.infos[r.ePuids[idx]], res.Basis(), extScore) return true } else { return false } case core.MIMEMatcher: if res.Index() >= r.mStart && res.Index() < r.mStart+len(r.mPuids) { idx := res.Index() - r.mStart r.ids = add(r.ids, r.name, r.mPuids[idx], r.infos[r.mPuids[idx]], res.Basis(), mimeScore) return true } else { return false } case core.ContainerMatcher: // add zip default if res.Index() < 0 { if r.zipDefault { r.cscore += incScore r.ids = add(r.ids, r.name, config.ZipPuid(), r.infos[config.ZipPuid()], res.Basis(), r.cscore) } return false } if res.Index() >= r.cStart && res.Index() < r.cStart+len(r.cPuids) { idx := res.Index() - r.cStart r.cscore += incScore basis := res.Basis() p, t := place(idx, r.cPuids) if t > 1 { basis = basis + fmt.Sprintf(" (signature %d/%d)", p, t) } r.ids = add(r.ids, r.name, r.cPuids[idx], r.infos[r.cPuids[idx]], basis, r.cscore) return true } else { return false } case core.ByteMatcher: if res.Index() >= r.bStart && res.Index() < r.bStart+len(r.bPuids) { if r.satisfied { return true } idx := res.Index() - r.bStart r.cscore += incScore basis := res.Basis() p, t := place(idx, r.bPuids) if t > 1 { basis = basis + fmt.Sprintf(" (signature %d/%d)", p, t) } r.ids = add(r.ids, r.name, r.bPuids[idx], r.infos[r.bPuids[idx]], basis, r.cscore) return true } else { return false } case core.TextMatcher: if res.Index() == r.tStart { if r.satisfied { return true } r.ids = add(r.ids, r.name, config.TextPuid(), r.infos[config.TextPuid()], res.Basis(), textScore) return true } else { return false } } }