76 lines
		
	
	
		
			1.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			76 lines
		
	
	
		
			1.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
|   | // For more tutorials: https://blog.learngoprogramming.com | ||
|  | // | ||
|  | // Copyright © 2018 Inanc Gumus | ||
|  | // Learn Go Programming Course | ||
|  | // License: https://creativecommons.org/licenses/by-nc-sa/4.0/ | ||
|  | // | ||
|  | 
 | ||
|  | package magic | ||
|  | 
 | ||
|  | import ( | ||
|  | 	"bytes" | ||
|  | 	"fmt" | ||
|  | 	"io" | ||
|  | 	"os" | ||
|  | ) | ||
|  | 
 | ||
|  | // Detect returns the files that have a valid header (file signature). | ||
|  | // A valid header is determined by the format. | ||
|  | func Detect(format string, filenames []string) (valids []string, err error) { | ||
|  | 	defer func() { | ||
|  | 		if rerr := recover(); rerr != nil { | ||
|  | 			err = fmt.Errorf("cannot detect: %v", rerr) | ||
|  | 		} | ||
|  | 	}() | ||
|  | 
 | ||
|  | 	return detect(format, filenames), nil | ||
|  | } | ||
|  | 
 | ||
|  | func detect(format string, filenames []string) (valids []string) { | ||
|  | 	header := headerOf(format) | ||
|  | 	buf := make([]byte, len(header)) | ||
|  | 
 | ||
|  | 	for _, filename := range filenames { | ||
|  | 		if read(filename, buf) != nil { | ||
|  | 			continue | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if bytes.Equal([]byte(header), buf) { | ||
|  | 			valids = append(valids, filename) | ||
|  | 		} | ||
|  | 	} | ||
|  | 	return | ||
|  | } | ||
|  | 
 | ||
|  | func headerOf(format string) string { | ||
|  | 	switch format { | ||
|  | 	case "png": | ||
|  | 		return "\x89PNG\r\n\x1a\n" | ||
|  | 	case "jpg": | ||
|  | 		return "\xff\xd8\xff" | ||
|  | 	} | ||
|  | 	// this should never occur | ||
|  | 	panic("unknown format: " + format) | ||
|  | } | ||
|  | 
 | ||
|  | // read reads len(buf) bytes to buf from a file | ||
|  | func read(filename string, buf []byte) error { | ||
|  | 	file, err := os.Open(filename) | ||
|  | 	if err != nil { | ||
|  | 		return err | ||
|  | 	} | ||
|  | 	defer file.Close() | ||
|  | 
 | ||
|  | 	fi, err := file.Stat() | ||
|  | 	if err != nil { | ||
|  | 		return err | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if fi.Size() <= int64(len(buf)) { | ||
|  | 		return fmt.Errorf("file size < len(buf)") | ||
|  | 	} | ||
|  | 
 | ||
|  | 	_, err = io.ReadFull(file, buf) | ||
|  | 	return err | ||
|  | } |