package parser import ( "fmt" "sort" "sync" ) var ( registry = make(map[string]VendorParser) registryLock sync.RWMutex ) // Register adds a vendor parser to the registry // Called from vendor module init() functions func Register(p VendorParser) { registryLock.Lock() defer registryLock.Unlock() vendor := p.Vendor() if _, exists := registry[vendor]; exists { panic(fmt.Sprintf("parser already registered for vendor: %s", vendor)) } registry[vendor] = p } // GetParser returns parser for specific vendor func GetParser(vendor string) (VendorParser, bool) { registryLock.RLock() defer registryLock.RUnlock() p, ok := registry[vendor] return p, ok } // ListParsers returns list of all registered vendor names func ListParsers() []string { registryLock.RLock() defer registryLock.RUnlock() vendors := make([]string, 0, len(registry)) for v := range registry { vendors = append(vendors, v) } sort.Strings(vendors) return vendors } // ParserInfo contains information about a registered parser type ParserInfo struct { Vendor string `json:"vendor"` Name string `json:"name"` Version string `json:"version"` } // ListParsersInfo returns detailed info about all registered parsers func ListParsersInfo() []ParserInfo { registryLock.RLock() defer registryLock.RUnlock() parsers := make([]ParserInfo, 0, len(registry)) for _, p := range registry { parsers = append(parsers, ParserInfo{ Vendor: p.Vendor(), Name: p.Name(), Version: p.Version(), }) } // Sort by vendor name sort.Slice(parsers, func(i, j int) bool { return parsers[i].Vendor < parsers[j].Vendor }) return parsers } // DetectResult holds detection result for a parser type DetectResult struct { Parser VendorParser Confidence int } // DetectFormat tries to detect archive format and returns best matching parser func DetectFormat(files []ExtractedFile) (VendorParser, error) { registryLock.RLock() defer registryLock.RUnlock() var results []DetectResult for _, p := range registry { confidence := p.Detect(files) if confidence > 0 { results = append(results, DetectResult{ Parser: p, Confidence: confidence, }) } } if len(results) == 0 { return nil, fmt.Errorf("no parser found for this archive format") } // Sort by confidence descending sort.Slice(results, func(i, j int) bool { return results[i].Confidence > results[j].Confidence }) return results[0].Parser, nil } // DetectAllFormats returns all parsers that can handle the files with their confidence func DetectAllFormats(files []ExtractedFile) []DetectResult { registryLock.RLock() defer registryLock.RUnlock() var results []DetectResult for _, p := range registry { confidence := p.Detect(files) if confidence > 0 { results = append(results, DetectResult{ Parser: p, Confidence: confidence, }) } } sort.Slice(results, func(i, j int) bool { return results[i].Confidence > results[j].Confidence }) return results }