func textMIMES(m map[string]identifier.FormatInfo) []string { ret := make([]string, 1, len(m)) ret[0] = config.TextMIME() // first one is the default for k, v := range m { if v.(formatInfo).text { ret = append(ret, k) } } return ret }
func (mi mimeinfo) Infos() map[string]identifier.FormatInfo { fmap := make(map[string]identifier.FormatInfo, len(mi.m)) for _, v := range mi.m { fi := formatInfo{} if len(v.Comment) > 0 { fi.comment = v.Comment[0] } else if len(v.Comments) > 0 { fi.comment = v.Comments[0] } var magicWeight int for _, mg := range v.Magic { magicWeight += len(mg.Matches) } fi.globWeights, fi.magicWeights = make([]int, len(v.Globs)), make([]int, 0, magicWeight) for i, w := range v.Globs { if len(w.Weight) > 0 { num, err := strconv.Atoi(w.Weight) if err == nil { fi.globWeights[i] = num continue } } fi.globWeights[i] = 50 } for _, w := range v.Magic { weight := 50 if len(w.Priority) > 0 { if num, err := strconv.Atoi(w.Priority); err == nil { weight = num } } for _, s := range w.Matches { ss, _ := toSigs(s) for _, sig := range ss { if sig != nil { fi.magicWeights = append(fi.magicWeights, weight) } } } } if len(v.SuperiorClasses) == 1 && v.SuperiorClasses[0].SubClassOf == config.TextMIME() { fi.text = true } fmap[v.MIME] = fi } return fmap }
func newMIMEInfo(path string) (identifier.Parseable, error) { buf, err := ioutil.ReadFile(path) if err != nil { return nil, err } mi := &mappings.MIMEInfo{} err = xml.Unmarshal(buf, mi) if err != nil { return nil, err } index := make(map[string]int) for i, v := range mi.MIMETypes { index[v.MIME] = i } for i, v := range mi.MIMETypes { if len(v.SuperiorClasses) == 1 && v.SuperiorClasses[0].SubClassOf != config.TextMIME() { // subclasses of text/plain shouldn't inherit text magic sup := index[v.SuperiorClasses[0].SubClassOf] if len(mi.MIMETypes[sup].XMLPattern) > 0 { mi.MIMETypes[i].XMLPattern = append(mi.MIMETypes[i].XMLPattern, mi.MIMETypes[sup].XMLPattern...) } if len(mi.MIMETypes[sup].Magic) > 0 { nm := make([]mappings.Magic, len(mi.MIMETypes[sup].Magic)) copy(nm, mi.MIMETypes[sup].Magic) for i, w := range nm { if len(w.Priority) > 0 { num, err := strconv.Atoi(w.Priority) if err == nil { nm[i].Priority = strconv.Itoa(num - 1) continue } } nm[i].Priority = "49" } mi.MIMETypes[i].Magic = append(mi.MIMETypes[i].Magic, nm...) } } } return mimeinfo{mi.MIMETypes, identifier.Blank{}}, nil }
func applyScore(id Identification, info formatInfo, t core.MatcherType, rel int) Identification { switch t { case core.NameMatcher: score := info.globWeights[rel] if score > id.globScore { id.globScore = score } case core.MIMEMatcher: id.mimeMatch = true case core.XMLMatcher: id.xmlMatch = true case core.ByteMatcher: score := info.magicWeights[rel] if score > id.magicScore { id.magicScore = score } case core.TextMatcher: id.textMatch = true if id.ID == config.TextMIME() { id.textDefault = true } } return id }
func (r *Recorder) Report() []core.Identification { // no results if len(r.ids) == 0 { return []core.Identification{Identification{ Namespace: r.Name(), ID: "UNKNOWN", Warning: "no match", }} } sort.Sort(r.ids) // exhaustive if r.Multi() == config.Exhaustive { ret := make([]core.Identification, len(r.ids)) for i, v := range r.ids { ret[i] = r.updateWarning(v) } return ret } // if we've only got weak matches (match is filename/mime only) report only the first if !r.ids[0].xmlMatch && r.ids[0].magicScore == 0 { var nids []Identification if len(r.ids) == 1 || r.ids.Less(0, 1) { // // Less reports whether the element with index i (0) should sort before the element with index j if r.ids[0].ID != config.TextMIME() || r.ids[0].textMatch || !r.textActive { nids = []Identification{r.ids[0]} } } var conf string if len(nids) != 1 { lowConfidence := confidenceTrick() poss := make([]string, len(r.ids)) for i, v := range r.ids { poss[i] = v.ID conf = lowConfidence(v) } return []core.Identification{Identification{ Namespace: r.Name(), ID: "UNKNOWN", Warning: fmt.Sprintf("no match; possibilities based on %s are %v", conf, strings.Join(poss, ", ")), }} } r.ids = nids } // handle single result only if r.Multi() == config.Single && len(r.ids) > 1 && !r.ids.Less(0, 1) { poss := make([]string, 0, len(r.ids)) for i, v := range r.ids { if i > 0 && r.ids.Less(i-1, i) { break } poss = append(poss, v.ID) } return []core.Identification{Identification{ Namespace: r.Name(), ID: "UNKNOWN", Warning: fmt.Sprintf("multiple matches %v", strings.Join(poss, ", ")), }} } ret := make([]core.Identification, len(r.ids)) for i, v := range r.ids { if i > 0 { switch r.Multi() { case config.Single: return ret[:i] case config.Conclusive: if r.ids.Less(i-1, i) { return ret[:i] } default: if !v.xmlMatch && v.magicScore == 0 { // if weak return ret[:i] } } } ret[i] = r.updateWarning(v) } return ret }
func (r *Recorder) Satisfied(mt core.MatcherType) (bool, int) { if r.NoPriority() { return false, 0 } sort.Sort(r.ids) if len(r.ids) > 0 && (r.ids[0].xmlMatch || (r.ids[0].magicScore > 0 && r.ids[0].ID != config.TextMIME())) { if mt == core.ByteMatcher { return true, r.Start(mt) } return true, 0 } return false, 0 }