using System; using Emby.Naming.Common; namespace Emby.Naming.Video { /// /// Parse 3D format related flags. /// public static class Format3DParser { // Static default result to save on allocation costs. private static readonly Format3DResult _defaultResult = new(false, null); /// /// Parse 3D format related flags. /// /// Path to file. /// The naming options. /// Returns object. public static Format3DResult Parse(ReadOnlySpan path, NamingOptions namingOptions) { int oldLen = namingOptions.VideoFlagDelimiters.Length; Span delimiters = stackalloc char[oldLen + 1]; namingOptions.VideoFlagDelimiters.AsSpan().CopyTo(delimiters); delimiters[oldLen] = ' '; return Parse(path, delimiters, namingOptions); } private static Format3DResult Parse(ReadOnlySpan path, ReadOnlySpan delimiters, NamingOptions namingOptions) { foreach (var rule in namingOptions.Format3DRules) { var result = Parse(path, rule, delimiters); if (result.Is3D) { return result; } } return _defaultResult; } private static Format3DResult Parse(ReadOnlySpan path, Format3DRule rule, ReadOnlySpan delimiters) { bool is3D = false; string? format3D = null; // If there's no preceding token we just consider it found var foundPrefix = string.IsNullOrEmpty(rule.PrecedingToken); while (path.Length > 0) { var index = path.IndexOfAny(delimiters); if (index == -1) { index = path.Length - 1; } var currentSlice = path[..index]; path = path[(index + 1)..]; if (!foundPrefix) { foundPrefix = currentSlice.Equals(rule.PrecedingToken, StringComparison.OrdinalIgnoreCase); continue; } is3D = foundPrefix && currentSlice.Equals(rule.Token, StringComparison.OrdinalIgnoreCase); if (is3D) { format3D = rule.Token; break; } } return is3D ? new Format3DResult(true, format3D) : _defaultResult; } } }