// // Copyright 2026 The InfiniFlow Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package util import ( "path/filepath" "regexp" "strings" ) const ( FileTypePDF = "pdf" FileTypeDOC = "doc" FileTypeVISUAL = "visual" FileTypeAURAL = "aural" FileTypeFOLDER = "folder" FileTypeOTHER = "other" ) var ( filenameLenLimit = 255 ) func init() { } func normalizeFilename(filename string) (string, bool) { if filename == "" { return "", false } base := filepath.Base(filename) base = strings.TrimSpace(base) if base == "" || len(base) > filenameLenLimit { return "", false } return strings.ToLower(base), true } func FilenameType(filename string) string { normalized, ok := normalizeFilename(filename) if !ok { return FileTypeOTHER } if matched, _ := regexp.MatchString(`.*\.pdf$`, normalized); matched { return FileTypePDF } docExtensions := []string{ "msg", "eml", "doc", "docx", "ppt", "pptx", "yml", "xml", "htm", "json", "jsonl", "ldjson", "csv", "txt", "ini", "xls", "xlsx", "wps", "rtf", "hlp", "pages", "numbers", "key", "md", "mdx", "py", "js", "java", "c", "cpp", "h", "php", "go", "ts", "sh", "cs", "kt", "html", "sql", "epub", } for _, ext := range docExtensions { if strings.HasSuffix(normalized, "."+ext) { return FileTypeDOC } } audioExtensions := []string{ "wav", "flac", "ape", "alac", "wv", "mp3", "aac", "ogg", "vorbis", "opus", } for _, ext := range audioExtensions { if strings.HasSuffix(normalized, "."+ext) { return FileTypeAURAL } } visualExtensions := []string{ "jpg", "jpeg", "png", "tif", "gif", "pcx", "tga", "exif", "fpx", "svg", "psd", "cdr", "pcd", "dxf", "ufo", "eps", "ai", "raw", "WMF", "webp", "avif", "apng", "icon", "ico", "mpg", "mpeg", "avi", "rm", "rmvb", "mov", "wmv", "asf", "dat", "asx", "wvx", "mpe", "mpa", "mp4", "mkv", } for _, ext := range visualExtensions { if strings.HasSuffix(normalized, "."+ext) { return FileTypeVISUAL } } return FileTypeOTHER } func SanitizeFilename(filename string) string { if filename == "" { return "" } filename = strings.TrimSpace(filename) if filename == "" { return "" } filename = strings.ReplaceAll(filename, "\\", "/") filename = strings.Trim(filename, "/") parts := strings.Split(filename, "/") var sanitizedParts []string for _, part := range parts { if part != "" && part != "." && part != ".." { sanitizedParts = append(sanitizedParts, part) } } unsafeRegex := regexp.MustCompile(`[^A-Za-z0-9_\-/]`) for i, part := range sanitizedParts { sanitizedParts[i] = unsafeRegex.ReplaceAllString(part, "") } result := strings.Join(sanitizedParts, "/") return result } func GetFileExtension(filename string) string { ext := filepath.Ext(filename) if len(ext) > 0 && ext[0] == '.' { return strings.ToLower(ext[1:]) } return strings.ToLower(ext) }