Example #1
0
func magics(m []string) ([]frames.Signature, error) {
	hx, ascii, hxx, asciix, err := characterise(m)
	if err != nil {
		return nil, err
	}
	if len(hx) > 0 {
		sigs := make([]frames.Signature, len(hx))
		for i, v := range hx {
			byts, offs, masks, err := dehex(v, hxx[i])
			if err != nil {
				return nil, err
			}
			sigs[i] = make(frames.Signature, len(byts))
			for ii, vv := range byts {
				rel := frames.BOF
				if ii > 0 {
					rel = frames.PREV
				}
				var pat patterns.Pattern
				if masks[ii] {
					pat = patterns.Mask(vv[0])
				} else {
					pat = patterns.Sequence(vv)
				}
				sigs[i][ii] = frames.NewFrame(rel, pat, offs[ii], offs[ii])
			}
		}
		return sigs, nil
	} else if len(ascii) > 0 {
		sigs := make([]frames.Signature, len(ascii))
		for i, v := range ascii {
			pat := patterns.Sequence(v)
			sigs[i] = frames.Signature{frames.NewFrame(frames.BOF, pat, asciix[i], asciix[i])}
		}
		return sigs, nil
	}
	return nil, nil
}
Example #2
0
// groups are chunks of PRONOM/Droid patterns delimited by parentheses or brackets
// these chunks represent any non-sequence pattern (choices, ranges, bitmasks, not-patterns etc.)
func processGroup(l *lexer) (patterns.Pattern, error) {
	var (
		list                    patterns.List   // bucket to stuff patterns into
		choice                  patterns.Choice // bucket to stuff choices into
		val                     []byte          // bucket to stuff text values
		not, mask, anyMask, rng bool            // retains state from previous tokens
	)
	// when commit a pattern (to the list), go back to zero state
	reset := func() {
		val = []byte{}
		not, mask, anyMask, rng = false, false, false, false
	}
	// make a pattern based on the current state
	makePat := func() patterns.Pattern {
		if len(val) == 0 {
			return nil
		}
		var pat patterns.Pattern
		switch {
		case mask:
			pat = patterns.Mask(val[0])
		case anyMask:
			pat = patterns.AnyMask(val[0])
		default:
			pat = patterns.Sequence(val)
		}
		if not {
			pat = patterns.Not{pat}
		}
		reset()
		return pat
	}
	// add patterns to the choice
	addChoice := func() (patterns.Choice, error) {
		switch len(list) {
		case 0:
			return nil, errors.New(l.name + " has choice marker without preceding pattern")
		case 1:
			choice = append(choice, list[0])
		default:
			choice = append(choice, list)
		}
		list = patterns.List{}
		return choice, nil
	}
	for {
		i := <-l.items
		switch i.typ {
		default:
			return nil, errors.New(l.name + " encountered unexpected token " + i.val)
		case itemEnterGroup: // recurse e.g. for a range nested within a choice
			if pat := makePat(); pat != nil {
				list = append(list, pat)
			}
			pat, err := processGroup(l)
			if err != nil {
				return nil, err
			}
			list = append(list, pat)
		case itemExitGroup:
			if pat := makePat(); pat != nil {
				list = append(list, pat)
			}
			if len(choice) > 0 {
				return addChoice()
			} else {
				switch len(list) {
				case 0:
					return nil, errors.New(l.name + " has group with no legal pattern")
				case 1:
					return list[0], nil
				default:
					return list, nil
				}
			}
		case itemRangeMarker:
			rng = true
		case itemChoiceMarker:
			if pat := makePat(); pat != nil {
				list = append(list, pat)
			}
			_, err := addChoice()
			if err != nil {
				return nil, err
			}
		case itemNotMarker:
			not = true
		case itemMaskMarker:
			mask = true
		case itemAnyMaskMarker:
			anyMask = true
		case itemUnprocessedText:
			v := processText(i.val)
			// if it is a range, we need values before and after the range marker, so add it here
			if rng {
				r := Range{val, v}
				if not {
					list = append(list, patterns.Not{r})
				} else {
					list = append(list, r)
				}
				reset()
			} else {
				val = v
			}
		}
	}
}